Merge pull request #7136 from mermaid-js/feat/sequence-alias-support-new-participant-syntax

feat : add alias support for new participant syntax
This commit is contained in:
Shubham P
2025-11-20 07:46:34 +00:00
committed by GitHub
11 changed files with 447 additions and 11 deletions

View File

@@ -30,6 +30,7 @@
[0-9]+(?=[ \n]+) return 'NUM';
<ID>\@\{ { this.begin('CONFIG'); return 'CONFIG_START'; }
<CONFIG>[^\}]+ { return 'CONFIG_CONTENT'; }
<CONFIG>\}(?=\s+as\s) { this.popState(); this.begin('ALIAS'); return 'CONFIG_END'; }
<CONFIG>\} { this.popState(); this.popState(); return 'CONFIG_END'; }
<ID>[^\<->\->:\n,;@\s]+(?=\@\{) { yytext = yytext.trim(); return 'ACTOR'; }
<ID>[^<>:\n,;@\s]+(?=\s+as\s) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
@@ -264,7 +265,10 @@ participant_statement
| 'participant_actor' actor 'AS' restOfLine 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant';$2.description=yy.parseMessage($4); $$=$2;}
| 'participant_actor' actor 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant'; $$=$2;}
| 'destroy' actor 'NEWLINE' {$2.type='destroyParticipant'; $$=$2;}
| 'participant' actor_with_config 'AS' restOfLine 'NEWLINE' {$2.draw='participant'; $2.type='addParticipant'; $2.description=yy.parseMessage($4); $$=$2;}
| 'participant' actor_with_config 'NEWLINE' {$2.draw='participant'; $2.type='addParticipant'; $$=$2;}
| 'participant_actor' actor_with_config 'AS' restOfLine 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant'; $2.description=yy.parseMessage($4); $$=$2;}
| 'participant_actor' actor_with_config 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant'; $$=$2;}
;

View File

@@ -172,6 +172,12 @@ export class SequenceDB implements DiagramDB {
doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA }) as ParticipantMetaData;
}
type = doc?.type ?? type;
// If alias is provided in metadata and description is not already set, use the alias
if (doc?.alias && (!description || description.text === name)) {
description = { text: doc.alias, wrap: description?.wrap, type };
}
const old = this.state.records.actors.get(id);
if (old) {
// If already set and trying to set to a new one throw error

View File

@@ -2621,5 +2621,114 @@ Bob->>Alice:Got it!
}
expect(error).toBe(true);
});
it('should parse participant with stereotype and alias', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
participant Alice@{ "type" : "boundary" } as Public API
participant Bob@{ "type" : "control" } as Controller
Alice->>Bob: Request
Bob-->>Alice: Response
`);
const actors = diagram.db.getActors();
expect(actors.get('Alice').type).toBe('boundary');
expect(actors.get('Alice').description).toBe('Public API');
expect(actors.get('Bob').type).toBe('control');
expect(actors.get('Bob').description).toBe('Controller');
});
it('should parse actor with stereotype and alias', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
actor A@{ "type" : "database" } AS Database Server
actor B@{ "type" : "queue" } as Message Queue
A->>B: Send message
`);
const actors = diagram.db.getActors();
expect(actors.get('A').type).toBe('database');
expect(actors.get('A').description).toBe('Database Server');
expect(actors.get('B').type).toBe('queue');
expect(actors.get('B').description).toBe('Message Queue');
});
it('should parse participant with stereotype and simple alias', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
participant API@{ "type" : "boundary" } AS Public API
API->>API: test
`);
const actors = diagram.db.getActors();
expect(actors.get('API').type).toBe('boundary');
expect(actors.get('API').description).toBe('Public API');
});
it('should parse participant with inline alias in config object', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
participant API@{ "type" : "boundary", "alias": "Public API" }
participant Auth@{ "type" : "control", "alias": "Auth Controller" }
API->>Auth: Request
Auth-->>API: Response
`);
const actors = diagram.db.getActors();
expect(actors.get('API').type).toBe('boundary');
expect(actors.get('API').description).toBe('Public API');
expect(actors.get('Auth').type).toBe('control');
expect(actors.get('Auth').description).toBe('Auth Controller');
});
it('should parse actor with inline alias in config object', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
actor U@{ "type" : "actor", "alias": "End User" }
actor DB@{ "type" : "database", "alias": "User Database" }
U->>DB: Query
DB-->>U: Result
`);
const actors = diagram.db.getActors();
expect(actors.get('U').type).toBe('actor');
expect(actors.get('U').description).toBe('End User');
expect(actors.get('DB').type).toBe('database');
expect(actors.get('DB').description).toBe('User Database');
});
it('should prioritize external alias over inline alias', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
participant API@{ "type" : "boundary", "alias": "Internal Name" } as External Name
API->>API: test
`);
const actors = diagram.db.getActors();
expect(actors.get('API').type).toBe('boundary');
expect(actors.get('API').description).toBe('External Name');
});
it('should handle participant with only inline alias (no type)', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
participant API@{ "alias": "Public API" }
API->>API: test
`);
const actors = diagram.db.getActors();
expect(actors.get('API').description).toBe('Public API');
});
it('should handle mixed inline and external alias syntax', async () => {
const diagram = await Diagram.fromText(`
sequenceDiagram
participant A@{ "type" : "boundary", "alias": "Service A" }
participant B@{ "type" : "control" } as Service B
participant C@{ "type" : "database" }
A->>B: Request
B->>C: Query
`);
const actors = diagram.db.getActors();
expect(actors.get('A').type).toBe('boundary');
expect(actors.get('A').description).toBe('Service A');
expect(actors.get('B').type).toBe('control');
expect(actors.get('B').description).toBe('Service B');
expect(actors.get('C').type).toBe('database');
expect(actors.get('C').description).toBe('C');
});
});
});

View File

@@ -120,7 +120,11 @@ sequenceDiagram
### Aliases
The actor can have a convenient identifier and a descriptive label.
The actor can have a convenient identifier and a descriptive label. Aliases can be defined in two ways: using external syntax with the `as` keyword, or inline within the configuration object.
#### External Alias Syntax
You can define an alias using the `as` keyword after the participant declaration:
```mermaid-example
sequenceDiagram
@@ -130,6 +134,48 @@ sequenceDiagram
J->>A: Great!
```
The external alias syntax also works with participant stereotype configurations, allowing you to combine type specification with aliases:
```mermaid-example
sequenceDiagram
participant API@{ "type": "boundary" } as Public API
actor DB@{ "type": "database" } as User Database
participant Svc@{ "type": "control" } as Auth Service
API->>Svc: Authenticate
Svc->>DB: Query user
DB-->>Svc: User data
Svc-->>API: Token
```
#### Inline Alias Syntax
Alternatively, you can define an alias directly inside the configuration object using the `"alias"` field. This works with both `participant` and `actor` keywords:
```mermaid-example
sequenceDiagram
participant API@{ "type": "boundary", "alias": "Public API" }
participant Auth@{ "type": "control", "alias": "Auth Service" }
participant DB@{ "type": "database", "alias": "User Database" }
API->>Auth: Login request
Auth->>DB: Query user
DB-->>Auth: User data
Auth-->>API: Access token
```
#### Alias Precedence
When both inline alias (in the configuration object) and external alias (using `as` keyword) are provided, the **external alias takes precedence**:
```mermaid-example
sequenceDiagram
participant API@{ "type": "boundary", "alias": "Internal Name" } as External Name
participant DB@{ "type": "database", "alias": "Internal DB" } as External DB
API->>DB: Query
DB-->>API: Result
```
In the example above, "External Name" and "External DB" will be displayed, not "Internal Name" and "Internal DB".
### Actor Creation and Destruction (v10.3.0+)
It is possible to create and destroy actors by messages. To do so, add a create or destroy directive before the message.

View File

@@ -23,6 +23,7 @@ export interface ParticipantMetaData {
| 'database'
| 'collections'
| 'queue';
alias?: string;
}
export interface EdgeMetaData {