@polagram/core 0.0.4 → 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 +102 -113
- package/dist/polagram-core.js +1532 -1404
- package/dist/polagram-core.umd.cjs +22 -22
- package/package.json +3 -2
- package/dist/src/api.d.ts +0 -84
- package/dist/src/api.js +0 -183
- 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 -198
- package/dist/src/config/schema.js +0 -82
- 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/generators/plantuml.d.ts +0 -17
- package/dist/src/generator/generators/plantuml.js +0 -131
- package/dist/src/generator/generators/plantuml.test.d.ts +0 -1
- package/dist/src/generator/generators/plantuml.test.js +0 -143
- package/dist/src/generator/interface.d.ts +0 -17
- package/dist/src/generator/interface.js +0 -1
- package/dist/src/index.d.ts +0 -13
- package/dist/src/index.js +0 -21
- 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/base/token.d.ts +0 -18
- package/dist/src/parser/base/token.js +0 -1
- package/dist/src/parser/base/tokens.d.ts +0 -8
- package/dist/src/parser/base/tokens.js +0 -1
- package/dist/src/parser/format-detector.d.ts +0 -55
- package/dist/src/parser/format-detector.js +0 -98
- package/dist/src/parser/index.d.ts +0 -11
- package/dist/src/parser/index.js +0 -33
- 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 -22
- 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/parser/languages/plantuml/index.d.ts +0 -4
- package/dist/src/parser/languages/plantuml/index.js +0 -11
- package/dist/src/parser/languages/plantuml/lexer.d.ts +0 -15
- package/dist/src/parser/languages/plantuml/lexer.js +0 -143
- package/dist/src/parser/languages/plantuml/parser.d.ts +0 -23
- package/dist/src/parser/languages/plantuml/parser.js +0 -481
- package/dist/src/parser/languages/plantuml/parser.test.d.ts +0 -1
- package/dist/src/parser/languages/plantuml/parser.test.js +0 -236
- package/dist/src/parser/languages/plantuml/tokens.d.ts +0 -9
- package/dist/src/parser/languages/plantuml/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 -52
- 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 -70
- 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 -111
- package/dist/src/transformer/types.d.ts +0 -47
- package/dist/src/transformer/types.js +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { MermaidGeneratorVisitor } from './mermaid';
|
|
3
|
-
describe('MermaidGeneratorVisitor', () => {
|
|
4
|
-
it('should generate sequence diagram header', () => {
|
|
5
|
-
const root = { kind: 'root', meta: { version: '1.0.0', source: 'mermaid' }, participants: [], groups: [], events: [] };
|
|
6
|
-
const visitor = new MermaidGeneratorVisitor();
|
|
7
|
-
const output = visitor.generate(root);
|
|
8
|
-
expect(output).toContain('sequenceDiagram');
|
|
9
|
-
});
|
|
10
|
-
it('should generate title if present', () => {
|
|
11
|
-
const root = { kind: 'root', meta: { version: '1.0.0', source: 'mermaid', title: 'My Diagram' }, participants: [], groups: [], events: [] };
|
|
12
|
-
const visitor = new MermaidGeneratorVisitor();
|
|
13
|
-
const output = visitor.generate(root);
|
|
14
|
-
expect(output).toContain('title My Diagram');
|
|
15
|
-
});
|
|
16
|
-
it('should generate participants', () => {
|
|
17
|
-
const root = {
|
|
18
|
-
kind: 'root',
|
|
19
|
-
meta: { version: '1.0.0', source: 'mermaid' },
|
|
20
|
-
participants: [
|
|
21
|
-
{ id: 'A', name: 'Alice', type: 'participant' },
|
|
22
|
-
{ id: 'B', name: 'Bob', type: 'actor' }
|
|
23
|
-
],
|
|
24
|
-
groups: [],
|
|
25
|
-
events: []
|
|
26
|
-
};
|
|
27
|
-
const visitor = new MermaidGeneratorVisitor();
|
|
28
|
-
const output = visitor.generate(root);
|
|
29
|
-
expect(output).toContain('participant A as Alice');
|
|
30
|
-
expect(output).toContain('actor B as Bob');
|
|
31
|
-
});
|
|
32
|
-
it('should generate participant with multi-word name without extra quotes', () => {
|
|
33
|
-
const root = {
|
|
34
|
-
kind: 'root',
|
|
35
|
-
meta: { version: '1.0.0', source: 'mermaid' },
|
|
36
|
-
participants: [
|
|
37
|
-
{ id: 'API', name: 'API Server', type: 'participant' }
|
|
38
|
-
],
|
|
39
|
-
groups: [],
|
|
40
|
-
events: []
|
|
41
|
-
};
|
|
42
|
-
const visitor = new MermaidGeneratorVisitor();
|
|
43
|
-
const output = visitor.generate(root);
|
|
44
|
-
// We expect it NOT to be quoted if the user wants clean text
|
|
45
|
-
// But currently it IS quoted. checking what it does now vs what we want.
|
|
46
|
-
// If we want to fix it, we should expect "API Server" plain.
|
|
47
|
-
expect(output).toContain('participant API as API Server');
|
|
48
|
-
});
|
|
49
|
-
it('should generate messages', () => {
|
|
50
|
-
const msg = {
|
|
51
|
-
kind: 'message',
|
|
52
|
-
id: '1',
|
|
53
|
-
from: 'A',
|
|
54
|
-
to: 'B',
|
|
55
|
-
text: 'hello',
|
|
56
|
-
type: 'sync',
|
|
57
|
-
style: { line: 'solid', head: 'arrow' }
|
|
58
|
-
};
|
|
59
|
-
const root = {
|
|
60
|
-
kind: 'root',
|
|
61
|
-
meta: { version: '1.0.0', source: 'mermaid' },
|
|
62
|
-
participants: [],
|
|
63
|
-
groups: [],
|
|
64
|
-
events: [msg]
|
|
65
|
-
};
|
|
66
|
-
const visitor = new MermaidGeneratorVisitor();
|
|
67
|
-
const output = visitor.generate(root);
|
|
68
|
-
expect(output).toContain('A->>B: hello');
|
|
69
|
-
});
|
|
70
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ActivationNode, DividerNode, FragmentNode, MessageNode, NoteNode, Participant, ParticipantGroup, PolagramRoot, ReferenceNode, SpacerNode } from '../../ast';
|
|
2
|
-
import { PolagramVisitor } from '../interface';
|
|
3
|
-
export declare class PlantUMLGeneratorVisitor implements PolagramVisitor {
|
|
4
|
-
generate(root: PolagramRoot): string;
|
|
5
|
-
visitRoot(node: PolagramRoot): string;
|
|
6
|
-
visitParticipant(node: Participant): string;
|
|
7
|
-
visitGroup(node: ParticipantGroup, context?: Map<string, Participant>): string;
|
|
8
|
-
visitMessage(node: MessageNode): string;
|
|
9
|
-
visitFragment(node: FragmentNode): string;
|
|
10
|
-
private visitEvent;
|
|
11
|
-
visitNote(node: NoteNode): string;
|
|
12
|
-
visitActivation(node: ActivationNode): string;
|
|
13
|
-
visitParticipantGroup(_node: ParticipantGroup): string;
|
|
14
|
-
visitDivider(_node: DividerNode): string;
|
|
15
|
-
visitSpacer(_node: SpacerNode): string;
|
|
16
|
-
visitReference(_node: ReferenceNode): string;
|
|
17
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
export class PlantUMLGeneratorVisitor {
|
|
2
|
-
generate(root) {
|
|
3
|
-
return this.visitRoot(root);
|
|
4
|
-
}
|
|
5
|
-
visitRoot(node) {
|
|
6
|
-
const lines = ['@startuml'];
|
|
7
|
-
if (node.meta.title) {
|
|
8
|
-
lines.push(`title ${node.meta.title}`);
|
|
9
|
-
}
|
|
10
|
-
const participantsMap = new Map(node.participants.map(p => [p.id, p]));
|
|
11
|
-
const groupedParticipantIds = new Set();
|
|
12
|
-
// Groups
|
|
13
|
-
for (const group of node.groups) {
|
|
14
|
-
lines.push(this.visitGroup(group, participantsMap));
|
|
15
|
-
group.participantIds.forEach(id => groupedParticipantIds.add(id));
|
|
16
|
-
}
|
|
17
|
-
// Ungrouped Participants
|
|
18
|
-
for (const participant of node.participants) {
|
|
19
|
-
if (!groupedParticipantIds.has(participant.id)) {
|
|
20
|
-
lines.push(this.visitParticipant(participant));
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
// Events
|
|
24
|
-
for (const event of node.events) {
|
|
25
|
-
lines.push(this.visitEvent(event));
|
|
26
|
-
}
|
|
27
|
-
lines.push('@enduml');
|
|
28
|
-
return lines.join('\n');
|
|
29
|
-
}
|
|
30
|
-
visitParticipant(node) {
|
|
31
|
-
// If Name == ID, use concise format: "type ID"
|
|
32
|
-
// Otherwise use explicit format: "type "Name" as ID"
|
|
33
|
-
if (node.name === node.id) {
|
|
34
|
-
return `${node.type} ${node.id}`;
|
|
35
|
-
}
|
|
36
|
-
return `${node.type} "${node.name}" as ${node.id}`;
|
|
37
|
-
}
|
|
38
|
-
// Adjusted signature to pass context
|
|
39
|
-
visitGroup(node, context) {
|
|
40
|
-
const parts = [];
|
|
41
|
-
const color = node.style?.backgroundColor ? ` ${node.style.backgroundColor}` : '';
|
|
42
|
-
const title = node.name ? ` "${node.name}"` : '';
|
|
43
|
-
parts.push(`box${title}${color}`);
|
|
44
|
-
if (context) {
|
|
45
|
-
for (const pid of node.participantIds) {
|
|
46
|
-
const p = context.get(pid);
|
|
47
|
-
if (p) {
|
|
48
|
-
parts.push(this.visitParticipant(p));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
parts.push('end box');
|
|
53
|
-
return parts.join('\n');
|
|
54
|
-
}
|
|
55
|
-
visitMessage(node) {
|
|
56
|
-
const from = node.from || '[*]'; // Handle lost/found if needed
|
|
57
|
-
const to = node.to || '[*]';
|
|
58
|
-
let arrow = '->';
|
|
59
|
-
if (node.type === 'reply')
|
|
60
|
-
arrow = '-->';
|
|
61
|
-
else if (node.type === 'async')
|
|
62
|
-
arrow = '->>'; // PlantUML doesn't strictly distinguish async arrow head generally, but ->> is fine
|
|
63
|
-
// style override
|
|
64
|
-
if (node.style.line === 'dotted') {
|
|
65
|
-
// If reply, already --> (dotted). If sync but dotted: A -[dotted]-> B ?
|
|
66
|
-
// PlantUML: A ..> B
|
|
67
|
-
// But --> is usually standard reply.
|
|
68
|
-
}
|
|
69
|
-
return `${from} ${arrow} ${to}: ${node.text}`;
|
|
70
|
-
}
|
|
71
|
-
visitFragment(node) {
|
|
72
|
-
const lines = [];
|
|
73
|
-
const op = node.operator;
|
|
74
|
-
node.branches.forEach((branch, index) => {
|
|
75
|
-
if (index === 0) {
|
|
76
|
-
lines.push(`${op} ${branch.condition || ''}`.trim());
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
lines.push(`else ${branch.condition || ''}`.trim());
|
|
80
|
-
}
|
|
81
|
-
for (const event of branch.events) {
|
|
82
|
-
// We need to recursively visit events (messages, nested fragments, etc.)
|
|
83
|
-
// But we can't easily call visitX because we don't know the type statically here or need a centralized dispatcher that returns string.
|
|
84
|
-
// But wait, visitRoot has a dispatcher. We should extract it to `visitEvent`.
|
|
85
|
-
// For now, let's duplicate the relevant dispatch logic or creating a helper.
|
|
86
|
-
lines.push(this.visitEvent(event));
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
lines.push('end');
|
|
90
|
-
return lines.join('\n');
|
|
91
|
-
}
|
|
92
|
-
visitEvent(event) {
|
|
93
|
-
switch (event.kind) {
|
|
94
|
-
case 'message': return this.visitMessage(event);
|
|
95
|
-
case 'fragment': return this.visitFragment(event);
|
|
96
|
-
case 'note': return this.visitNote(event);
|
|
97
|
-
case 'activation': return this.visitActivation(event);
|
|
98
|
-
case 'divider': return this.visitDivider(event);
|
|
99
|
-
case 'spacer': return this.visitSpacer(event);
|
|
100
|
-
case 'ref': return this.visitReference(event);
|
|
101
|
-
default: return '';
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
visitNote(node) {
|
|
105
|
-
const position = node.position || 'over';
|
|
106
|
-
const participants = node.participantIds.join(', ');
|
|
107
|
-
// note left of A: Text
|
|
108
|
-
// note over A, B: Text
|
|
109
|
-
// For 'over', we don't say 'of' in standard examples? "note over Alice", "note over Alice, Bob"
|
|
110
|
-
// But 'left of', 'right of' use 'of'.
|
|
111
|
-
const positionStr = (position === 'left' || position === 'right') ? `${position} of` : position;
|
|
112
|
-
return `note ${positionStr} ${participants}: ${node.text}`;
|
|
113
|
-
}
|
|
114
|
-
visitActivation(node) {
|
|
115
|
-
// activate A
|
|
116
|
-
// deactivate A
|
|
117
|
-
return `${node.action} ${node.participantId}`;
|
|
118
|
-
}
|
|
119
|
-
visitParticipantGroup(_node) {
|
|
120
|
-
return '';
|
|
121
|
-
}
|
|
122
|
-
visitDivider(_node) {
|
|
123
|
-
return '';
|
|
124
|
-
}
|
|
125
|
-
visitSpacer(_node) {
|
|
126
|
-
return '';
|
|
127
|
-
}
|
|
128
|
-
visitReference(_node) {
|
|
129
|
-
return '';
|
|
130
|
-
}
|
|
131
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { PlantUMLGeneratorVisitor } from './plantuml';
|
|
3
|
-
describe('PlantUML Generator', () => {
|
|
4
|
-
const generator = new PlantUMLGeneratorVisitor();
|
|
5
|
-
it('should generate basic document structure', () => {
|
|
6
|
-
const ast = {
|
|
7
|
-
kind: 'root',
|
|
8
|
-
meta: { version: '1.0.0', source: 'plantuml', title: 'My Diagram' },
|
|
9
|
-
participants: [],
|
|
10
|
-
groups: [],
|
|
11
|
-
events: []
|
|
12
|
-
};
|
|
13
|
-
const code = generator.generate(ast);
|
|
14
|
-
expect(code).toContain('@startuml');
|
|
15
|
-
expect(code).toContain('title My Diagram');
|
|
16
|
-
expect(code).toContain('@enduml');
|
|
17
|
-
});
|
|
18
|
-
it('should generate participants', () => {
|
|
19
|
-
const ast = {
|
|
20
|
-
kind: 'root',
|
|
21
|
-
meta: { version: '1.0.0', source: 'plantuml' },
|
|
22
|
-
participants: [
|
|
23
|
-
{ id: 'User', name: 'User', type: 'actor' },
|
|
24
|
-
{ id: 'DB', name: 'DB', type: 'database' },
|
|
25
|
-
{ id: 'Svc', name: 'Service', type: 'participant' }
|
|
26
|
-
],
|
|
27
|
-
groups: [],
|
|
28
|
-
events: []
|
|
29
|
-
};
|
|
30
|
-
const code = generator.generate(ast);
|
|
31
|
-
expect(code).toContain('actor User');
|
|
32
|
-
expect(code).toContain('database DB');
|
|
33
|
-
expect(code).toContain('participant "Service" as Svc');
|
|
34
|
-
});
|
|
35
|
-
it('should generate messages', () => {
|
|
36
|
-
const ast = {
|
|
37
|
-
kind: 'root',
|
|
38
|
-
meta: { version: '1.0.0', source: 'plantuml' },
|
|
39
|
-
participants: [
|
|
40
|
-
{ id: 'A', name: 'A', type: 'participant' },
|
|
41
|
-
{ id: 'B', name: 'B', type: 'participant' }
|
|
42
|
-
],
|
|
43
|
-
groups: [],
|
|
44
|
-
events: [
|
|
45
|
-
{ kind: 'message', id: 'm1', from: 'A', to: 'B', text: 'Sync', type: 'sync', style: { line: 'solid', head: 'arrow' } },
|
|
46
|
-
{ kind: 'message', id: 'm2', from: 'B', to: 'A', text: 'Reply', type: 'reply', style: { line: 'dotted', head: 'arrow' } },
|
|
47
|
-
{ kind: 'message', id: 'm3', from: 'A', to: 'A', text: 'Self', type: 'sync', style: { line: 'solid', head: 'arrow' } }
|
|
48
|
-
]
|
|
49
|
-
};
|
|
50
|
-
const code = generator.generate(ast);
|
|
51
|
-
expect(code).toContain('A -> B: Sync');
|
|
52
|
-
expect(code).toContain('B --> A: Reply');
|
|
53
|
-
expect(code).toContain('A -> A: Self');
|
|
54
|
-
});
|
|
55
|
-
it('should generate fragments', () => {
|
|
56
|
-
const ast = {
|
|
57
|
-
kind: 'root',
|
|
58
|
-
meta: { version: '1.0.0', source: 'plantuml' },
|
|
59
|
-
participants: [],
|
|
60
|
-
groups: [],
|
|
61
|
-
events: [
|
|
62
|
-
{
|
|
63
|
-
kind: 'fragment',
|
|
64
|
-
id: 'f1',
|
|
65
|
-
operator: 'alt',
|
|
66
|
-
branches: [
|
|
67
|
-
{ id: 'b1', condition: 'success', events: [
|
|
68
|
-
{ kind: 'message', id: 'm1', from: 'A', to: 'B', text: 'OK', type: 'sync', style: { line: 'solid', head: 'arrow' } }
|
|
69
|
-
] },
|
|
70
|
-
{ id: 'b2', condition: 'failure', events: [
|
|
71
|
-
{ kind: 'message', id: 'm2', from: 'A', to: 'B', text: 'Fail', type: 'sync', style: { line: 'solid', head: 'arrow' } }
|
|
72
|
-
] }
|
|
73
|
-
]
|
|
74
|
-
}
|
|
75
|
-
]
|
|
76
|
-
};
|
|
77
|
-
const code = generator.generate(ast);
|
|
78
|
-
expect(code).toContain('alt success');
|
|
79
|
-
expect(code).toContain('A -> B: OK');
|
|
80
|
-
expect(code).toContain('else failure');
|
|
81
|
-
expect(code).toContain('A -> B: Fail');
|
|
82
|
-
expect(code).toContain('end');
|
|
83
|
-
});
|
|
84
|
-
it('should generate notes', () => {
|
|
85
|
-
const ast = {
|
|
86
|
-
kind: 'root',
|
|
87
|
-
meta: { version: '1.0.0', source: 'plantuml' },
|
|
88
|
-
participants: [
|
|
89
|
-
{ id: 'A', name: 'A', type: 'participant' }
|
|
90
|
-
],
|
|
91
|
-
groups: [],
|
|
92
|
-
events: [
|
|
93
|
-
{ kind: 'note', id: 'n1', text: 'My Note', position: 'right', participantIds: ['A'] },
|
|
94
|
-
{ kind: 'note', id: 'n2', text: 'Over Note', position: 'over', participantIds: ['A'] }
|
|
95
|
-
]
|
|
96
|
-
};
|
|
97
|
-
const code = generator.generate(ast);
|
|
98
|
-
expect(code).toContain('note right of A: My Note');
|
|
99
|
-
expect(code).toContain('note over A: Over Note');
|
|
100
|
-
});
|
|
101
|
-
it('should generate lifecycle events', () => {
|
|
102
|
-
const ast = {
|
|
103
|
-
kind: 'root',
|
|
104
|
-
meta: { version: '1.0.0', source: 'plantuml' },
|
|
105
|
-
participants: [
|
|
106
|
-
{ id: 'A', name: 'A', type: 'participant' }
|
|
107
|
-
],
|
|
108
|
-
groups: [],
|
|
109
|
-
events: [
|
|
110
|
-
{ kind: 'activation', participantId: 'A', action: 'activate' },
|
|
111
|
-
// Some message presumably
|
|
112
|
-
{ kind: 'activation', participantId: 'A', action: 'deactivate' }
|
|
113
|
-
]
|
|
114
|
-
};
|
|
115
|
-
const code = generator.generate(ast);
|
|
116
|
-
expect(code).toContain('activate A');
|
|
117
|
-
expect(code).toContain('deactivate A');
|
|
118
|
-
});
|
|
119
|
-
it('should generate groups', () => {
|
|
120
|
-
const ast = {
|
|
121
|
-
kind: 'root',
|
|
122
|
-
meta: { version: '1.0.0', source: 'plantuml' },
|
|
123
|
-
participants: [
|
|
124
|
-
{ id: 'A', name: 'A', type: 'participant' },
|
|
125
|
-
{ id: 'B', name: 'B', type: 'participant' },
|
|
126
|
-
{ id: 'C', name: 'C', type: 'participant' }
|
|
127
|
-
],
|
|
128
|
-
groups: [
|
|
129
|
-
{ kind: 'group', id: 'g1', name: 'Box1', type: 'box', participantIds: ['A', 'B'], style: { backgroundColor: '#LightBlue' } }
|
|
130
|
-
],
|
|
131
|
-
events: []
|
|
132
|
-
};
|
|
133
|
-
const code = generator.generate(ast);
|
|
134
|
-
// Expect Box1 to contain A and B
|
|
135
|
-
// C should be outside
|
|
136
|
-
// Exact order depends on implementation, but box should be there
|
|
137
|
-
expect(code).toContain('box "Box1" #LightBlue');
|
|
138
|
-
expect(code).toContain('participant A');
|
|
139
|
-
expect(code).toContain('participant B');
|
|
140
|
-
expect(code).toContain('end box');
|
|
141
|
-
expect(code).toContain('participant C');
|
|
142
|
-
});
|
|
143
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ActivationNode, DividerNode, FragmentNode, MessageNode, NoteNode, Participant, ParticipantGroup, PolagramRoot, ReferenceNode, SpacerNode } from '../ast';
|
|
2
|
-
/**
|
|
3
|
-
* Visitor interface for traversing the Polagram AST.
|
|
4
|
-
* Implement this interface to create code generators, validators, etc.
|
|
5
|
-
*/
|
|
6
|
-
export interface PolagramVisitor {
|
|
7
|
-
visitRoot(node: PolagramRoot): void;
|
|
8
|
-
visitParticipant(node: Participant): void;
|
|
9
|
-
visitParticipantGroup(node: ParticipantGroup): void;
|
|
10
|
-
visitMessage(node: MessageNode): void;
|
|
11
|
-
visitFragment(node: FragmentNode): void;
|
|
12
|
-
visitNote(node: NoteNode): void;
|
|
13
|
-
visitActivation(node: ActivationNode): void;
|
|
14
|
-
visitDivider(node: DividerNode): void;
|
|
15
|
-
visitSpacer(node: SpacerNode): void;
|
|
16
|
-
visitReference(node: ReferenceNode): void;
|
|
17
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/src/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export * from './ast';
|
|
2
|
-
export { ParserFactory } from './parser';
|
|
3
|
-
export { FormatDetector } from './parser/format-detector';
|
|
4
|
-
export type { DiagramFormat } from './parser/format-detector';
|
|
5
|
-
export type { DiagramParser } from './parser/interface';
|
|
6
|
-
export { Traverser } from './generator/base/walker';
|
|
7
|
-
export type { PolagramVisitor } from './generator/interface';
|
|
8
|
-
export * from './config/schema';
|
|
9
|
-
export { MermaidGeneratorVisitor } from './generator/generators/mermaid';
|
|
10
|
-
export { PlantUMLGeneratorVisitor } from './generator/generators/plantuml';
|
|
11
|
-
export * from './transformer';
|
|
12
|
-
export { Polagram, PolagramBuilder } from './api';
|
|
13
|
-
export * from './config';
|
package/dist/src/index.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Public API Exports
|
|
2
|
-
// AST
|
|
3
|
-
export * from './ast';
|
|
4
|
-
// Parsers (Factory & Strategy)
|
|
5
|
-
export { ParserFactory } from './parser';
|
|
6
|
-
export { FormatDetector } from './parser/format-detector';
|
|
7
|
-
// Generators
|
|
8
|
-
export { Traverser } from './generator/base/walker';
|
|
9
|
-
// Default Implementations (Optional, or force users to use Factory)
|
|
10
|
-
// We export Mermaid Generator specifically as it might be used directly or via a future Factory
|
|
11
|
-
// Config & Validation
|
|
12
|
-
export * from './config/schema';
|
|
13
|
-
export { MermaidGeneratorVisitor } from './generator/generators/mermaid';
|
|
14
|
-
export { PlantUMLGeneratorVisitor } from './generator/generators/plantuml';
|
|
15
|
-
// Transformation Engine
|
|
16
|
-
export * from './transformer';
|
|
17
|
-
// Fluent API (Recommended for most users)
|
|
18
|
-
export { Polagram, PolagramBuilder } from './api';
|
|
19
|
-
// Legacy compatibility or convenience helpers could go here if needed.
|
|
20
|
-
// Configuration & Schema
|
|
21
|
-
export * from './config';
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { BaseToken } from './token';
|
|
2
|
-
export declare abstract class BaseLexer<T extends BaseToken = BaseToken> {
|
|
3
|
-
protected input: string;
|
|
4
|
-
protected position: number;
|
|
5
|
-
protected readPosition: number;
|
|
6
|
-
protected ch: string;
|
|
7
|
-
protected line: number;
|
|
8
|
-
protected column: number;
|
|
9
|
-
constructor(input: string);
|
|
10
|
-
getInput(): string;
|
|
11
|
-
abstract nextToken(): T;
|
|
12
|
-
protected readChar(): void;
|
|
13
|
-
protected peekChar(): string;
|
|
14
|
-
protected skipWhitespace(): void;
|
|
15
|
-
protected readWhile(predicate: (ch: string) => boolean): string;
|
|
16
|
-
protected isLetter(ch: string): boolean;
|
|
17
|
-
protected isDigit(ch: string): boolean;
|
|
18
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
export class BaseLexer {
|
|
2
|
-
constructor(input) {
|
|
3
|
-
Object.defineProperty(this, "input", {
|
|
4
|
-
enumerable: true,
|
|
5
|
-
configurable: true,
|
|
6
|
-
writable: true,
|
|
7
|
-
value: input
|
|
8
|
-
});
|
|
9
|
-
Object.defineProperty(this, "position", {
|
|
10
|
-
enumerable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
writable: true,
|
|
13
|
-
value: 0
|
|
14
|
-
});
|
|
15
|
-
Object.defineProperty(this, "readPosition", {
|
|
16
|
-
enumerable: true,
|
|
17
|
-
configurable: true,
|
|
18
|
-
writable: true,
|
|
19
|
-
value: 0
|
|
20
|
-
});
|
|
21
|
-
Object.defineProperty(this, "ch", {
|
|
22
|
-
enumerable: true,
|
|
23
|
-
configurable: true,
|
|
24
|
-
writable: true,
|
|
25
|
-
value: ''
|
|
26
|
-
});
|
|
27
|
-
Object.defineProperty(this, "line", {
|
|
28
|
-
enumerable: true,
|
|
29
|
-
configurable: true,
|
|
30
|
-
writable: true,
|
|
31
|
-
value: 1
|
|
32
|
-
});
|
|
33
|
-
Object.defineProperty(this, "column", {
|
|
34
|
-
enumerable: true,
|
|
35
|
-
configurable: true,
|
|
36
|
-
writable: true,
|
|
37
|
-
value: 0
|
|
38
|
-
});
|
|
39
|
-
this.readChar();
|
|
40
|
-
}
|
|
41
|
-
getInput() {
|
|
42
|
-
return this.input;
|
|
43
|
-
}
|
|
44
|
-
readChar() {
|
|
45
|
-
if (this.readPosition >= this.input.length) {
|
|
46
|
-
this.ch = '';
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
this.ch = this.input[this.readPosition];
|
|
50
|
-
}
|
|
51
|
-
this.position = this.readPosition;
|
|
52
|
-
this.readPosition += 1;
|
|
53
|
-
this.column += 1;
|
|
54
|
-
if (this.ch === '\n') {
|
|
55
|
-
this.line += 1;
|
|
56
|
-
this.column = 0;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
peekChar() {
|
|
60
|
-
if (this.readPosition >= this.input.length) {
|
|
61
|
-
return '';
|
|
62
|
-
}
|
|
63
|
-
return this.input[this.readPosition];
|
|
64
|
-
}
|
|
65
|
-
skipWhitespace() {
|
|
66
|
-
while (this.ch === ' ' || this.ch === '\t' || this.ch === '\r') {
|
|
67
|
-
this.readChar();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
readWhile(predicate) {
|
|
71
|
-
const position = this.position;
|
|
72
|
-
while (predicate(this.ch)) {
|
|
73
|
-
this.readChar();
|
|
74
|
-
}
|
|
75
|
-
return this.input.slice(position, this.position);
|
|
76
|
-
}
|
|
77
|
-
isLetter(ch) {
|
|
78
|
-
// Support ASCII letters and underscore
|
|
79
|
-
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch === '_') {
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
// Support Unicode letters (including Japanese, Chinese, Korean, etc.)
|
|
83
|
-
// This uses a simple check: if the character code is > 127 (non-ASCII)
|
|
84
|
-
// and it's not a digit or whitespace, treat it as a letter
|
|
85
|
-
const code = ch.charCodeAt(0);
|
|
86
|
-
if (code > 127) {
|
|
87
|
-
// Exclude Unicode digits and whitespace
|
|
88
|
-
return !/[\s\d]/.test(ch);
|
|
89
|
-
}
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
isDigit(ch) {
|
|
93
|
-
return '0' <= ch && ch <= '9';
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { BaseLexer } from './lexer';
|
|
3
|
-
// Concrete implementation for testing abstract class
|
|
4
|
-
class TestLexer extends BaseLexer {
|
|
5
|
-
nextToken() {
|
|
6
|
-
this.skipWhitespace();
|
|
7
|
-
if (this.readPosition > this.input.length) { // fixed EOF logic for test, check base-lexer readChar behavior
|
|
8
|
-
// BaseLexer: readPosition moves past End.
|
|
9
|
-
return { type: 'EOF', literal: '', line: this.line, column: this.column, start: this.position, end: this.position };
|
|
10
|
-
}
|
|
11
|
-
const char = this.ch;
|
|
12
|
-
const start = this.position;
|
|
13
|
-
this.readChar();
|
|
14
|
-
return {
|
|
15
|
-
type: 'UNKNOWN', // Dummy type
|
|
16
|
-
literal: char,
|
|
17
|
-
line: this.line,
|
|
18
|
-
column: this.column,
|
|
19
|
-
start,
|
|
20
|
-
end: this.position
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
// Expose protected methods for testing
|
|
24
|
-
testReadIdentifier() { return this.readWhile(c => this.isLetter(c)); }
|
|
25
|
-
testIsDigit(c) { return this.isDigit(c); }
|
|
26
|
-
testIsLetter(c) { return this.isLetter(c); }
|
|
27
|
-
getChar() { return this.ch; }
|
|
28
|
-
}
|
|
29
|
-
describe('BaseLexer', () => {
|
|
30
|
-
it('should initialize correctly', () => {
|
|
31
|
-
const input = "abc";
|
|
32
|
-
const lexer = new TestLexer(input);
|
|
33
|
-
expect(lexer.getInput()).toBe(input);
|
|
34
|
-
expect(lexer.getChar()).toBe('a');
|
|
35
|
-
});
|
|
36
|
-
it('should identify digits', () => {
|
|
37
|
-
const lexer = new TestLexer("");
|
|
38
|
-
expect(lexer.testIsDigit('1')).toBe(true);
|
|
39
|
-
expect(lexer.testIsDigit('a')).toBe(false);
|
|
40
|
-
});
|
|
41
|
-
it('should identify letters', () => {
|
|
42
|
-
const lexer = new TestLexer("");
|
|
43
|
-
expect(lexer.testIsLetter('a')).toBe(true);
|
|
44
|
-
expect(lexer.testIsLetter('_')).toBe(true);
|
|
45
|
-
expect(lexer.testIsLetter('1')).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
it('should read characters while predicate matches', () => {
|
|
48
|
-
const lexer = new TestLexer("abc 123");
|
|
49
|
-
const ident = lexer.testReadIdentifier();
|
|
50
|
-
expect(ident).toBe("abc");
|
|
51
|
-
expect(lexer.getChar()).toBe(" "); // Stops at space
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { PolagramRoot } from '../../ast';
|
|
2
|
-
import { BaseLexer } from './lexer';
|
|
3
|
-
import { BaseToken } from './token';
|
|
4
|
-
export declare abstract class BaseParser<T extends BaseToken = BaseToken> {
|
|
5
|
-
protected lexer: BaseLexer<T>;
|
|
6
|
-
protected currToken: T;
|
|
7
|
-
protected peekToken: T;
|
|
8
|
-
constructor(lexer: BaseLexer<T>);
|
|
9
|
-
protected advance(): void;
|
|
10
|
-
abstract parse(): PolagramRoot;
|
|
11
|
-
protected curTokenIs(t: string): boolean;
|
|
12
|
-
protected peekTokenIs(t: string): boolean;
|
|
13
|
-
protected expectPeek(t: string): boolean;
|
|
14
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export class BaseParser {
|
|
2
|
-
constructor(lexer) {
|
|
3
|
-
Object.defineProperty(this, "lexer", {
|
|
4
|
-
enumerable: true,
|
|
5
|
-
configurable: true,
|
|
6
|
-
writable: true,
|
|
7
|
-
value: lexer
|
|
8
|
-
});
|
|
9
|
-
Object.defineProperty(this, "currToken", {
|
|
10
|
-
enumerable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
writable: true,
|
|
13
|
-
value: void 0
|
|
14
|
-
});
|
|
15
|
-
Object.defineProperty(this, "peekToken", {
|
|
16
|
-
enumerable: true,
|
|
17
|
-
configurable: true,
|
|
18
|
-
writable: true,
|
|
19
|
-
value: void 0
|
|
20
|
-
});
|
|
21
|
-
this.advance();
|
|
22
|
-
this.advance();
|
|
23
|
-
}
|
|
24
|
-
advance() {
|
|
25
|
-
this.currToken = this.peekToken;
|
|
26
|
-
this.peekToken = this.lexer.nextToken();
|
|
27
|
-
}
|
|
28
|
-
curTokenIs(t) {
|
|
29
|
-
return this.currToken.type === t;
|
|
30
|
-
}
|
|
31
|
-
peekTokenIs(t) {
|
|
32
|
-
return this.peekToken.type === t;
|
|
33
|
-
}
|
|
34
|
-
expectPeek(t) {
|
|
35
|
-
if (this.peekTokenIs(t)) {
|
|
36
|
-
this.advance();
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|