@polagram/core 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +172 -85
- package/dist/polagram-core.js +2721 -2061
- package/dist/polagram-core.umd.cjs +20 -14
- package/package.json +11 -9
- package/dist/src/api.d.ts +0 -75
- package/dist/src/api.js +0 -160
- package/dist/src/ast/ast.test.d.ts +0 -1
- package/dist/src/ast/ast.test.js +0 -146
- package/dist/src/ast/index.d.ts +0 -119
- package/dist/src/ast/index.js +0 -2
- package/dist/src/config/index.d.ts +0 -1
- package/dist/src/config/index.js +0 -1
- package/dist/src/config/schema.d.ts +0 -182
- package/dist/src/config/schema.js +0 -78
- package/dist/src/config/schema.test.d.ts +0 -1
- package/dist/src/config/schema.test.js +0 -94
- package/dist/src/generator/base/walker.d.ts +0 -19
- package/dist/src/generator/base/walker.js +0 -56
- package/dist/src/generator/base/walker.test.d.ts +0 -1
- package/dist/src/generator/base/walker.test.js +0 -49
- package/dist/src/generator/generators/mermaid.d.ts +0 -24
- package/dist/src/generator/generators/mermaid.js +0 -140
- package/dist/src/generator/generators/mermaid.test.d.ts +0 -1
- package/dist/src/generator/generators/mermaid.test.js +0 -70
- package/dist/src/generator/interface.d.ts +0 -17
- package/dist/src/generator/interface.js +0 -1
- package/dist/src/index.d.ts +0 -9
- package/dist/src/index.js +0 -17
- package/dist/src/parser/base/lexer.d.ts +0 -18
- package/dist/src/parser/base/lexer.js +0 -95
- package/dist/src/parser/base/lexer.test.d.ts +0 -1
- package/dist/src/parser/base/lexer.test.js +0 -53
- package/dist/src/parser/base/parser.d.ts +0 -14
- package/dist/src/parser/base/parser.js +0 -43
- package/dist/src/parser/base/parser.test.d.ts +0 -1
- package/dist/src/parser/base/parser.test.js +0 -90
- package/dist/src/parser/index.d.ts +0 -10
- package/dist/src/parser/index.js +0 -29
- package/dist/src/parser/index.test.d.ts +0 -1
- package/dist/src/parser/index.test.js +0 -23
- package/dist/src/parser/interface.d.ts +0 -8
- package/dist/src/parser/interface.js +0 -1
- package/dist/src/parser/languages/mermaid/constants.d.ts +0 -7
- package/dist/src/parser/languages/mermaid/constants.js +0 -20
- package/dist/src/parser/languages/mermaid/index.d.ts +0 -4
- package/dist/src/parser/languages/mermaid/index.js +0 -11
- package/dist/src/parser/languages/mermaid/lexer.d.ts +0 -14
- package/dist/src/parser/languages/mermaid/lexer.js +0 -152
- package/dist/src/parser/languages/mermaid/lexer.test.d.ts +0 -1
- package/dist/src/parser/languages/mermaid/lexer.test.js +0 -58
- package/dist/src/parser/languages/mermaid/parser.d.ts +0 -21
- package/dist/src/parser/languages/mermaid/parser.js +0 -340
- package/dist/src/parser/languages/mermaid/parser.test.d.ts +0 -1
- package/dist/src/parser/languages/mermaid/parser.test.js +0 -252
- package/dist/src/parser/languages/mermaid/tokens.d.ts +0 -9
- package/dist/src/parser/languages/mermaid/tokens.js +0 -1
- package/dist/src/transformer/cleaners/prune-empty.d.ts +0 -9
- package/dist/src/transformer/cleaners/prune-empty.js +0 -27
- package/dist/src/transformer/cleaners/prune-empty.test.d.ts +0 -1
- package/dist/src/transformer/cleaners/prune-empty.test.js +0 -69
- package/dist/src/transformer/cleaners/prune-unused.d.ts +0 -5
- package/dist/src/transformer/cleaners/prune-unused.js +0 -48
- package/dist/src/transformer/cleaners/prune-unused.test.d.ts +0 -1
- package/dist/src/transformer/cleaners/prune-unused.test.js +0 -71
- package/dist/src/transformer/filters/focus.d.ts +0 -13
- package/dist/src/transformer/filters/focus.js +0 -71
- package/dist/src/transformer/filters/focus.test.d.ts +0 -1
- package/dist/src/transformer/filters/focus.test.js +0 -50
- package/dist/src/transformer/filters/remove.d.ts +0 -12
- package/dist/src/transformer/filters/remove.js +0 -82
- package/dist/src/transformer/filters/remove.test.d.ts +0 -1
- package/dist/src/transformer/filters/remove.test.js +0 -38
- package/dist/src/transformer/filters/resolve.d.ts +0 -9
- package/dist/src/transformer/filters/resolve.js +0 -32
- package/dist/src/transformer/filters/resolve.test.d.ts +0 -1
- package/dist/src/transformer/filters/resolve.test.js +0 -48
- package/dist/src/transformer/index.d.ts +0 -10
- package/dist/src/transformer/index.js +0 -10
- package/dist/src/transformer/lens.d.ts +0 -12
- package/dist/src/transformer/lens.js +0 -58
- package/dist/src/transformer/lens.test.d.ts +0 -1
- package/dist/src/transformer/lens.test.js +0 -60
- package/dist/src/transformer/orchestration/engine.d.ts +0 -5
- package/dist/src/transformer/orchestration/engine.js +0 -24
- package/dist/src/transformer/orchestration/engine.test.d.ts +0 -1
- package/dist/src/transformer/orchestration/engine.test.js +0 -41
- package/dist/src/transformer/orchestration/registry.d.ts +0 -10
- package/dist/src/transformer/orchestration/registry.js +0 -27
- package/dist/src/transformer/selector/matcher.d.ts +0 -9
- package/dist/src/transformer/selector/matcher.js +0 -62
- package/dist/src/transformer/selector/matcher.test.d.ts +0 -1
- package/dist/src/transformer/selector/matcher.test.js +0 -53
- package/dist/src/transformer/traverse/walker.d.ts +0 -14
- package/dist/src/transformer/traverse/walker.js +0 -67
- package/dist/src/transformer/traverse/walker.test.d.ts +0 -1
- package/dist/src/transformer/traverse/walker.test.js +0 -48
- package/dist/src/transformer/types.d.ts +0 -47
- package/dist/src/transformer/types.js +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { BaseLexer } from '../../base/lexer';
|
|
2
|
-
export class Lexer extends BaseLexer {
|
|
3
|
-
constructor(input) {
|
|
4
|
-
super(input);
|
|
5
|
-
}
|
|
6
|
-
nextToken() {
|
|
7
|
-
this.skipWhitespace();
|
|
8
|
-
const start = this.position;
|
|
9
|
-
const startColumn = this.column;
|
|
10
|
-
let tok;
|
|
11
|
-
switch (this.ch) {
|
|
12
|
-
case ':':
|
|
13
|
-
tok = this.newToken('COLON', this.ch, start, startColumn);
|
|
14
|
-
break;
|
|
15
|
-
case ',':
|
|
16
|
-
tok = this.newToken('COMMA', this.ch, start, startColumn);
|
|
17
|
-
break;
|
|
18
|
-
case '+':
|
|
19
|
-
tok = this.newToken('PLUS', this.ch, start, startColumn);
|
|
20
|
-
break;
|
|
21
|
-
case '-':
|
|
22
|
-
if (this.isArrowStart()) {
|
|
23
|
-
const literal = this.readArrow();
|
|
24
|
-
tok = this.newToken('ARROW', literal, start, startColumn);
|
|
25
|
-
return tok;
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
tok = this.newToken('MINUS', this.ch, start, startColumn);
|
|
29
|
-
}
|
|
30
|
-
break;
|
|
31
|
-
case '"':
|
|
32
|
-
// eslint-disable-next-line no-case-declarations
|
|
33
|
-
const str = this.readString();
|
|
34
|
-
tok = this.newToken('STRING', str, start, startColumn);
|
|
35
|
-
return tok;
|
|
36
|
-
case '\n':
|
|
37
|
-
tok = this.newToken('NEWLINE', this.ch, start, startColumn);
|
|
38
|
-
break;
|
|
39
|
-
case '':
|
|
40
|
-
tok = this.newToken('EOF', '', start, startColumn);
|
|
41
|
-
break;
|
|
42
|
-
default:
|
|
43
|
-
if (this.isLetter(this.ch)) {
|
|
44
|
-
const literal = this.readIdentifier();
|
|
45
|
-
const type = this.lookupIdent(literal);
|
|
46
|
-
return this.newToken(type, literal, start, startColumn);
|
|
47
|
-
}
|
|
48
|
-
else if (this.isDigit(this.ch)) {
|
|
49
|
-
const literal = this.readNumber();
|
|
50
|
-
return this.newToken('IDENTIFIER', literal, start, startColumn);
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
tok = this.newToken('UNKNOWN', this.ch, start, startColumn);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
this.readChar();
|
|
57
|
-
return tok;
|
|
58
|
-
}
|
|
59
|
-
newToken(type, literal, start, startColumn) {
|
|
60
|
-
return {
|
|
61
|
-
type: type,
|
|
62
|
-
literal,
|
|
63
|
-
line: this.line,
|
|
64
|
-
column: startColumn,
|
|
65
|
-
start,
|
|
66
|
-
// If the lexer position has advanced beyond the start (consumed tokens like String/Arrow), use that position.
|
|
67
|
-
// Otherwise (simple chars), assume length-based calculation.
|
|
68
|
-
end: (this.position > start) ? this.position : start + literal.length
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
readIdentifier() {
|
|
72
|
-
const position = this.position;
|
|
73
|
-
while (this.isLetter(this.ch) || this.isDigit(this.ch)) {
|
|
74
|
-
this.readChar();
|
|
75
|
-
}
|
|
76
|
-
return this.input.slice(position, this.position);
|
|
77
|
-
}
|
|
78
|
-
readNumber() {
|
|
79
|
-
const position = this.position;
|
|
80
|
-
while (this.isDigit(this.ch)) {
|
|
81
|
-
this.readChar();
|
|
82
|
-
}
|
|
83
|
-
return this.input.slice(position, this.position);
|
|
84
|
-
}
|
|
85
|
-
readString() {
|
|
86
|
-
const position = this.position + 1;
|
|
87
|
-
this.readChar();
|
|
88
|
-
while (this.ch !== '"' && this.ch !== '' && this.ch !== '\n') {
|
|
89
|
-
this.readChar();
|
|
90
|
-
}
|
|
91
|
-
const str = this.input.slice(position, this.position);
|
|
92
|
-
if (this.ch === '"') {
|
|
93
|
-
// Logic handled in nextToken via readChar or here?
|
|
94
|
-
// In BaseLexer readChar advances.
|
|
95
|
-
// Original logic was slightly tricky.
|
|
96
|
-
// Let's keep consistent with valid implementation.
|
|
97
|
-
}
|
|
98
|
-
this.readChar();
|
|
99
|
-
return str;
|
|
100
|
-
}
|
|
101
|
-
isArrowStart() {
|
|
102
|
-
if (this.ch !== '-')
|
|
103
|
-
return false;
|
|
104
|
-
const next = this.peekChar();
|
|
105
|
-
return next === '>' || next === '-' || next === ')' || next === 'x';
|
|
106
|
-
}
|
|
107
|
-
readArrow() {
|
|
108
|
-
const potential4 = this.input.slice(this.position, this.position + 4);
|
|
109
|
-
if (potential4 === '-->>') {
|
|
110
|
-
this.readMulti(4);
|
|
111
|
-
return '-->>';
|
|
112
|
-
}
|
|
113
|
-
const potential3 = this.input.slice(this.position, this.position + 3);
|
|
114
|
-
if (potential3 === '-->' || potential3 === '--)' || potential3 === '->>' || potential3 === '--x') {
|
|
115
|
-
this.readMulti(3);
|
|
116
|
-
return potential3;
|
|
117
|
-
}
|
|
118
|
-
const potential2 = this.input.slice(this.position, this.position + 2);
|
|
119
|
-
if (potential2 === '->' || potential2 === '-)' || potential2 === '-x') {
|
|
120
|
-
this.readMulti(2);
|
|
121
|
-
return potential2;
|
|
122
|
-
}
|
|
123
|
-
return '-';
|
|
124
|
-
}
|
|
125
|
-
readMulti(count) {
|
|
126
|
-
for (let i = 0; i < count; i++)
|
|
127
|
-
this.readChar();
|
|
128
|
-
}
|
|
129
|
-
lookupIdent(ident) {
|
|
130
|
-
const keywords = {
|
|
131
|
-
'sequenceDiagram': 'SEQUENCE_DIAGRAM',
|
|
132
|
-
'participant': 'PARTICIPANT',
|
|
133
|
-
'actor': 'ACTOR',
|
|
134
|
-
'loop': 'LOOP',
|
|
135
|
-
'alt': 'ALT',
|
|
136
|
-
'opt': 'OPT',
|
|
137
|
-
'end': 'END',
|
|
138
|
-
'else': 'ELSE',
|
|
139
|
-
'note': 'NOTE',
|
|
140
|
-
'left': 'LEFT',
|
|
141
|
-
'right': 'RIGHT',
|
|
142
|
-
'over': 'OVER',
|
|
143
|
-
'of': 'OF',
|
|
144
|
-
'as': 'AS',
|
|
145
|
-
'title': 'TITLE',
|
|
146
|
-
'activate': 'ACTIVATE',
|
|
147
|
-
'deactivate': 'DEACTIVATE',
|
|
148
|
-
'box': 'BOX'
|
|
149
|
-
};
|
|
150
|
-
return keywords[ident] || 'IDENTIFIER';
|
|
151
|
-
}
|
|
152
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { Lexer } from './lexer';
|
|
3
|
-
describe('Mermaid Lexer', () => {
|
|
4
|
-
const checkValues = (input, expected) => {
|
|
5
|
-
const lexer = new Lexer(input);
|
|
6
|
-
for (const [type, literal] of expected) {
|
|
7
|
-
const token = lexer.nextToken();
|
|
8
|
-
expect(token.type).toBe(type);
|
|
9
|
-
expect(token.literal).toBe(literal);
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
it('should parse simple tokens', () => {
|
|
13
|
-
const input = 'sequenceDiagram participant :';
|
|
14
|
-
checkValues(input, [
|
|
15
|
-
['SEQUENCE_DIAGRAM', 'sequenceDiagram'],
|
|
16
|
-
['PARTICIPANT', 'participant'],
|
|
17
|
-
['COLON', ':']
|
|
18
|
-
]);
|
|
19
|
-
});
|
|
20
|
-
it('should parse keywords correctly', () => {
|
|
21
|
-
// Re-verify 'participant'
|
|
22
|
-
const lexer = new Lexer('participant actor loop');
|
|
23
|
-
const t1 = lexer.nextToken();
|
|
24
|
-
expect(t1.type).toBe('PARTICIPANT');
|
|
25
|
-
const t2 = lexer.nextToken();
|
|
26
|
-
expect(t2.type).toBe('ACTOR');
|
|
27
|
-
const t3 = lexer.nextToken();
|
|
28
|
-
expect(t3.type).toBe('LOOP');
|
|
29
|
-
});
|
|
30
|
-
it('should parse arrows', () => {
|
|
31
|
-
checkValues('-> --> ->> -->> -) --) -x --x', [
|
|
32
|
-
['ARROW', '->'],
|
|
33
|
-
['ARROW', '-->'],
|
|
34
|
-
['ARROW', '->>'],
|
|
35
|
-
['ARROW', '-->>'],
|
|
36
|
-
['ARROW', '-)'],
|
|
37
|
-
['ARROW', '--)'],
|
|
38
|
-
// Let's debug my lexer readArrow implementation logic mentally.
|
|
39
|
-
// potential3: '--)' is checked.
|
|
40
|
-
// So expected is ARROW '--)'
|
|
41
|
-
]);
|
|
42
|
-
const l2 = new Lexer('--)');
|
|
43
|
-
const t = l2.nextToken();
|
|
44
|
-
expect(t.type).toBe('ARROW');
|
|
45
|
-
expect(t.literal).toBe('--)');
|
|
46
|
-
});
|
|
47
|
-
it('should parse strings', () => {
|
|
48
|
-
checkValues('"hello world"', [
|
|
49
|
-
['STRING', 'hello world']
|
|
50
|
-
]);
|
|
51
|
-
});
|
|
52
|
-
it('should parse plus and minus', () => {
|
|
53
|
-
checkValues('+ -', [
|
|
54
|
-
['PLUS', '+'],
|
|
55
|
-
['MINUS', '-']
|
|
56
|
-
]);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { PolagramRoot } from '../../../ast';
|
|
2
|
-
import { BaseParser } from '../../base/parser';
|
|
3
|
-
import { Lexer } from './lexer';
|
|
4
|
-
export declare class Parser extends BaseParser {
|
|
5
|
-
private currentGroup;
|
|
6
|
-
private idCounters;
|
|
7
|
-
constructor(lexer: Lexer);
|
|
8
|
-
parse(): PolagramRoot;
|
|
9
|
-
private parseBlock;
|
|
10
|
-
private isParticipantToken;
|
|
11
|
-
private parseGroup;
|
|
12
|
-
private parseFragment;
|
|
13
|
-
private parseParticipant;
|
|
14
|
-
private parseNote;
|
|
15
|
-
private parseActivation;
|
|
16
|
-
private parseMessage;
|
|
17
|
-
private resolveArrow;
|
|
18
|
-
private generateId;
|
|
19
|
-
private readRestOfLine;
|
|
20
|
-
private ensureParticipant;
|
|
21
|
-
}
|
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
import { BaseParser } from '../../base/parser';
|
|
2
|
-
import { ARROW_MAPPING } from './constants';
|
|
3
|
-
export class Parser extends BaseParser {
|
|
4
|
-
constructor(lexer) {
|
|
5
|
-
super(lexer);
|
|
6
|
-
Object.defineProperty(this, "currentGroup", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
configurable: true,
|
|
9
|
-
writable: true,
|
|
10
|
-
value: null
|
|
11
|
-
});
|
|
12
|
-
Object.defineProperty(this, "idCounters", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
configurable: true,
|
|
15
|
-
writable: true,
|
|
16
|
-
value: {
|
|
17
|
-
evt: 0,
|
|
18
|
-
frag: 0,
|
|
19
|
-
br: 0,
|
|
20
|
-
note: 0,
|
|
21
|
-
group: 0,
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
parse() {
|
|
26
|
-
const root = {
|
|
27
|
-
kind: 'root',
|
|
28
|
-
meta: { version: '1.0.0', source: 'unknown' },
|
|
29
|
-
participants: [],
|
|
30
|
-
groups: [],
|
|
31
|
-
events: []
|
|
32
|
-
};
|
|
33
|
-
root.events = this.parseBlock(root);
|
|
34
|
-
return root;
|
|
35
|
-
}
|
|
36
|
-
parseBlock(root, stopTokens = []) {
|
|
37
|
-
const events = [];
|
|
38
|
-
while (this.currToken.type !== 'EOF') {
|
|
39
|
-
const type = this.currToken.type;
|
|
40
|
-
if (stopTokens.includes(type)) {
|
|
41
|
-
return events;
|
|
42
|
-
}
|
|
43
|
-
if (type === 'NEWLINE') {
|
|
44
|
-
this.advance();
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (type === 'SEQUENCE_DIAGRAM') {
|
|
48
|
-
root.meta.source = 'mermaid';
|
|
49
|
-
this.advance();
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (type === 'TITLE') {
|
|
53
|
-
this.advance(); // eat TITLE
|
|
54
|
-
root.meta.title = this.readRestOfLine();
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (type === 'BOX') {
|
|
58
|
-
const groupEvents = this.parseGroup(root);
|
|
59
|
-
events.push(...groupEvents);
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
if (type === 'PARTICIPANT' || type === 'ACTOR') {
|
|
63
|
-
this.parseParticipant(root);
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (type === 'LOOP' || type === 'ALT' || type === 'OPT') {
|
|
67
|
-
events.push(this.parseFragment(root));
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
if (type === 'NOTE') {
|
|
71
|
-
events.push(this.parseNote(root));
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
if (type === 'ACTIVATE' || type === 'DEACTIVATE') {
|
|
75
|
-
events.push(this.parseActivation(root));
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (this.isParticipantToken(this.currToken)) {
|
|
79
|
-
const msg = this.parseMessage(root);
|
|
80
|
-
if (msg) {
|
|
81
|
-
events.push(msg);
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// Skip unknown or unhandled
|
|
86
|
-
this.advance();
|
|
87
|
-
}
|
|
88
|
-
return events;
|
|
89
|
-
}
|
|
90
|
-
isParticipantToken(tok) {
|
|
91
|
-
return tok.type === 'IDENTIFIER' || tok.type === 'STRING';
|
|
92
|
-
}
|
|
93
|
-
parseGroup(root) {
|
|
94
|
-
this.advance(); // eat 'box'
|
|
95
|
-
const rawAttrs = this.readRestOfLine().trim();
|
|
96
|
-
let name = rawAttrs;
|
|
97
|
-
let color;
|
|
98
|
-
const parts = rawAttrs.split(/\s+/);
|
|
99
|
-
if (parts.length > 0) {
|
|
100
|
-
const first = parts[0];
|
|
101
|
-
if (first.startsWith('#') || ['rgb', 'rgba', 'transparent', 'aqua', 'grey', 'gray', 'purple', 'red', 'blue', 'green'].includes(first.toLowerCase())) {
|
|
102
|
-
color = first;
|
|
103
|
-
name = parts.slice(1).join(' ');
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (!name)
|
|
107
|
-
name = `Group ${this.idCounters.group + 1}`;
|
|
108
|
-
const group = {
|
|
109
|
-
kind: 'group',
|
|
110
|
-
id: this.generateId('group'),
|
|
111
|
-
name: name,
|
|
112
|
-
type: 'box',
|
|
113
|
-
participantIds: [],
|
|
114
|
-
style: color ? { backgroundColor: color } : undefined
|
|
115
|
-
};
|
|
116
|
-
root.groups.push(group);
|
|
117
|
-
// Set current group context
|
|
118
|
-
const previousGroup = this.currentGroup;
|
|
119
|
-
this.currentGroup = group;
|
|
120
|
-
// Parse content until 'end'
|
|
121
|
-
const events = this.parseBlock(root, ['END']);
|
|
122
|
-
// Restore context
|
|
123
|
-
this.currentGroup = previousGroup;
|
|
124
|
-
if (this.currToken.type === 'END') {
|
|
125
|
-
this.advance(); // eat 'end'
|
|
126
|
-
}
|
|
127
|
-
return events;
|
|
128
|
-
}
|
|
129
|
-
parseFragment(root) {
|
|
130
|
-
const type = this.currToken.type;
|
|
131
|
-
let operator = 'loop';
|
|
132
|
-
if (type === 'ALT')
|
|
133
|
-
operator = 'alt';
|
|
134
|
-
if (type === 'OPT')
|
|
135
|
-
operator = 'opt';
|
|
136
|
-
this.advance(); // eat operator
|
|
137
|
-
const condition = this.readRestOfLine();
|
|
138
|
-
const branches = [];
|
|
139
|
-
const events = this.parseBlock(root, ['END', 'ELSE']);
|
|
140
|
-
branches.push({
|
|
141
|
-
id: this.generateId('br'),
|
|
142
|
-
condition,
|
|
143
|
-
events
|
|
144
|
-
});
|
|
145
|
-
while (this.currToken.type === 'ELSE') {
|
|
146
|
-
this.advance();
|
|
147
|
-
const elseCond = this.readRestOfLine();
|
|
148
|
-
const elseEvents = this.parseBlock(root, ['END', 'ELSE']);
|
|
149
|
-
branches.push({
|
|
150
|
-
id: this.generateId('br'),
|
|
151
|
-
condition: elseCond,
|
|
152
|
-
events: elseEvents
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
if (this.currToken.type === 'END') {
|
|
156
|
-
this.advance();
|
|
157
|
-
}
|
|
158
|
-
return {
|
|
159
|
-
kind: 'fragment',
|
|
160
|
-
id: this.generateId('frag'),
|
|
161
|
-
operator,
|
|
162
|
-
branches
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
parseParticipant(root) {
|
|
166
|
-
const isActor = this.currToken.type === 'ACTOR';
|
|
167
|
-
this.advance(); // eat 'participant' or 'actor'
|
|
168
|
-
let id = '';
|
|
169
|
-
let name = '';
|
|
170
|
-
if (this.isParticipantToken(this.currToken)) {
|
|
171
|
-
id = this.currToken.literal;
|
|
172
|
-
name = id;
|
|
173
|
-
this.advance();
|
|
174
|
-
}
|
|
175
|
-
// Check for 'as'
|
|
176
|
-
if (this.currToken.type === 'AS') {
|
|
177
|
-
this.advance(); // eat 'as'
|
|
178
|
-
// Use readRestOfLine to capture multi-word aliases (e.g., "API Server")
|
|
179
|
-
const alias = this.readRestOfLine().trim();
|
|
180
|
-
if (alias) {
|
|
181
|
-
name = alias;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
const existing = root.participants.find(p => p.id === id);
|
|
185
|
-
if (!existing) {
|
|
186
|
-
root.participants.push({
|
|
187
|
-
id,
|
|
188
|
-
name,
|
|
189
|
-
type: isActor ? 'actor' : 'participant'
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
if (name !== id)
|
|
194
|
-
existing.name = name;
|
|
195
|
-
if (isActor)
|
|
196
|
-
existing.type = 'actor';
|
|
197
|
-
}
|
|
198
|
-
// Assign to current group if exists
|
|
199
|
-
if (this.currentGroup) {
|
|
200
|
-
if (!this.currentGroup.participantIds.includes(id)) {
|
|
201
|
-
this.currentGroup.participantIds.push(id);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
parseNote(root) {
|
|
206
|
-
this.advance(); // eat 'note'
|
|
207
|
-
let position = 'over'; // default
|
|
208
|
-
if (this.currToken.type === 'LEFT') {
|
|
209
|
-
position = 'left';
|
|
210
|
-
this.advance();
|
|
211
|
-
}
|
|
212
|
-
else if (this.currToken.type === 'RIGHT') {
|
|
213
|
-
position = 'right';
|
|
214
|
-
this.advance();
|
|
215
|
-
}
|
|
216
|
-
else if (this.currToken.type === 'OVER') {
|
|
217
|
-
position = 'over';
|
|
218
|
-
this.advance();
|
|
219
|
-
}
|
|
220
|
-
// consume 'of' if present (optional in some cases but usually note right of A)
|
|
221
|
-
if (this.currToken.type === 'OF') {
|
|
222
|
-
this.advance();
|
|
223
|
-
}
|
|
224
|
-
const participantIds = [];
|
|
225
|
-
while (this.isParticipantToken(this.currToken)) {
|
|
226
|
-
participantIds.push(this.currToken.literal);
|
|
227
|
-
this.ensureParticipant(root, this.currToken.literal);
|
|
228
|
-
this.advance();
|
|
229
|
-
if (this.currToken.type === 'COMMA') {
|
|
230
|
-
this.advance();
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
let text = '';
|
|
237
|
-
if (this.currToken.type === 'COLON') {
|
|
238
|
-
this.advance();
|
|
239
|
-
text = this.readRestOfLine();
|
|
240
|
-
}
|
|
241
|
-
return {
|
|
242
|
-
kind: 'note',
|
|
243
|
-
id: this.generateId('note'),
|
|
244
|
-
position,
|
|
245
|
-
participantIds,
|
|
246
|
-
text
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
parseActivation(root) {
|
|
250
|
-
const action = this.currToken.type === 'ACTIVATE' ? 'activate' : 'deactivate';
|
|
251
|
-
this.advance(); // eat command
|
|
252
|
-
let participantId = '';
|
|
253
|
-
if (this.isParticipantToken(this.currToken)) {
|
|
254
|
-
participantId = this.currToken.literal;
|
|
255
|
-
this.ensureParticipant(root, participantId);
|
|
256
|
-
this.advance();
|
|
257
|
-
}
|
|
258
|
-
return {
|
|
259
|
-
kind: 'activation',
|
|
260
|
-
participantId,
|
|
261
|
-
action
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
parseMessage(root) {
|
|
265
|
-
if (this.peekToken.type !== 'ARROW') {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
const fromId = this.currToken.literal;
|
|
269
|
-
this.ensureParticipant(root, fromId);
|
|
270
|
-
this.advance(); // eat from
|
|
271
|
-
if (this.currToken.type !== 'ARROW') {
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
const arrowLiteral = this.currToken.literal;
|
|
275
|
-
this.advance(); // eat arrow
|
|
276
|
-
let activateTarget = false;
|
|
277
|
-
let deactivateSource = false;
|
|
278
|
-
if (this.currToken.type === 'PLUS') {
|
|
279
|
-
activateTarget = true;
|
|
280
|
-
this.advance();
|
|
281
|
-
}
|
|
282
|
-
if (this.currToken.type === 'MINUS') {
|
|
283
|
-
deactivateSource = true;
|
|
284
|
-
this.advance();
|
|
285
|
-
}
|
|
286
|
-
if (!this.isParticipantToken(this.currToken))
|
|
287
|
-
return null;
|
|
288
|
-
const toId = this.currToken.literal;
|
|
289
|
-
this.ensureParticipant(root, toId);
|
|
290
|
-
this.advance(); // eat to
|
|
291
|
-
let text = '';
|
|
292
|
-
if (this.currToken.type === 'COLON') {
|
|
293
|
-
this.advance();
|
|
294
|
-
text = this.readRestOfLine();
|
|
295
|
-
}
|
|
296
|
-
const { type, style } = this.resolveArrow(arrowLiteral);
|
|
297
|
-
return {
|
|
298
|
-
kind: 'message',
|
|
299
|
-
id: this.generateId('evt'),
|
|
300
|
-
from: fromId,
|
|
301
|
-
to: toId,
|
|
302
|
-
text: text,
|
|
303
|
-
type: type,
|
|
304
|
-
style: style,
|
|
305
|
-
lifecycle: (activateTarget || deactivateSource) ? { activateTarget, deactivateSource } : undefined
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
resolveArrow(arrow) {
|
|
309
|
-
const mapping = ARROW_MAPPING[arrow];
|
|
310
|
-
if (mapping) {
|
|
311
|
-
return mapping;
|
|
312
|
-
}
|
|
313
|
-
return { type: 'sync', style: { line: 'solid', head: 'arrow' } };
|
|
314
|
-
}
|
|
315
|
-
generateId(prefix) {
|
|
316
|
-
this.idCounters[prefix]++;
|
|
317
|
-
return `${prefix}_${this.idCounters[prefix]}`;
|
|
318
|
-
}
|
|
319
|
-
readRestOfLine() {
|
|
320
|
-
if (this.currToken.type === 'NEWLINE' || this.currToken.type === 'EOF') {
|
|
321
|
-
return '';
|
|
322
|
-
}
|
|
323
|
-
const start = this.currToken.start;
|
|
324
|
-
let end = this.currToken.end;
|
|
325
|
-
while (this.currToken.type !== 'NEWLINE' && this.currToken.type !== 'EOF') {
|
|
326
|
-
end = this.currToken.end;
|
|
327
|
-
this.advance();
|
|
328
|
-
}
|
|
329
|
-
return this.lexer.getInput().slice(start, end);
|
|
330
|
-
}
|
|
331
|
-
ensureParticipant(root, id) {
|
|
332
|
-
if (!root.participants.find(p => p.id === id)) {
|
|
333
|
-
root.participants.push({
|
|
334
|
-
id,
|
|
335
|
-
name: id,
|
|
336
|
-
type: 'participant'
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|