@polagram/core 0.0.4 → 0.1.1
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 +1524 -1392
- package/dist/polagram-core.umd.cjs +23 -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,90 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { BaseLexer } from './lexer';
|
|
3
|
-
import { BaseParser } from './parser';
|
|
4
|
-
// Mocks
|
|
5
|
-
class MockLexer extends BaseLexer {
|
|
6
|
-
constructor(tokens) {
|
|
7
|
-
super("");
|
|
8
|
-
Object.defineProperty(this, "tokens", {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
configurable: true,
|
|
11
|
-
writable: true,
|
|
12
|
-
value: void 0
|
|
13
|
-
});
|
|
14
|
-
Object.defineProperty(this, "index", {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
configurable: true,
|
|
17
|
-
writable: true,
|
|
18
|
-
value: 0
|
|
19
|
-
});
|
|
20
|
-
this.tokens = tokens;
|
|
21
|
-
}
|
|
22
|
-
nextToken() {
|
|
23
|
-
if (this.index >= this.tokens.length) {
|
|
24
|
-
return { type: 'EOF', literal: '', line: 0, column: 0, start: 0, end: 0 };
|
|
25
|
-
}
|
|
26
|
-
return this.tokens[this.index++];
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
class TestParser extends BaseParser {
|
|
30
|
-
parse() {
|
|
31
|
-
return { kind: 'root', meta: { version: '1.0.0', source: 'unknown' }, participants: [], groups: [], events: [] };
|
|
32
|
-
}
|
|
33
|
-
// Expose protected methods
|
|
34
|
-
getCurr() { return this.currToken; }
|
|
35
|
-
getPeek() { return this.peekToken; }
|
|
36
|
-
testAdvance() { this.advance(); }
|
|
37
|
-
testCurTokenIs(t) { return this.curTokenIs(t); }
|
|
38
|
-
testPeakTokenIs(t) { return this.peekTokenIs(t); }
|
|
39
|
-
testExpectPeek(t) { return this.expectPeek(t); }
|
|
40
|
-
}
|
|
41
|
-
describe('BaseParser', () => {
|
|
42
|
-
const tokens = [
|
|
43
|
-
{ type: 'IDENTIFIER', literal: 'A', line: 1, column: 0, start: 0, end: 1 },
|
|
44
|
-
{ type: 'ARROW', literal: '->', line: 1, column: 1, start: 1, end: 3 },
|
|
45
|
-
{ type: 'IDENTIFIER', literal: 'B', line: 1, column: 3, start: 3, end: 4 },
|
|
46
|
-
];
|
|
47
|
-
it('should initialize curr and peek tokens', () => {
|
|
48
|
-
const lexer = new MockLexer(tokens);
|
|
49
|
-
const parser = new TestParser(lexer);
|
|
50
|
-
// Constructor called advance twice.
|
|
51
|
-
// 1st advance: curr=undefined, peek=Tokens[0]
|
|
52
|
-
// 2nd advance: curr=Tokens[0], peek=Tokens[1]
|
|
53
|
-
expect(parser.getCurr().type).toBe('IDENTIFIER');
|
|
54
|
-
expect(parser.getCurr().literal).toBe('A');
|
|
55
|
-
expect(parser.getPeek().type).toBe('ARROW');
|
|
56
|
-
});
|
|
57
|
-
it('should advance tokens', () => {
|
|
58
|
-
const lexer = new MockLexer(tokens);
|
|
59
|
-
const parser = new TestParser(lexer);
|
|
60
|
-
parser.testAdvance();
|
|
61
|
-
// curr=Tokens[1] (ARROW), peek=Tokens[2] (IDENTIFIER B)
|
|
62
|
-
expect(parser.getCurr().type).toBe('ARROW');
|
|
63
|
-
expect(parser.getPeek().type).toBe('IDENTIFIER');
|
|
64
|
-
});
|
|
65
|
-
it('should check current and peek token types', () => {
|
|
66
|
-
const lexer = new MockLexer(tokens);
|
|
67
|
-
const parser = new TestParser(lexer);
|
|
68
|
-
expect(parser.testCurTokenIs('IDENTIFIER')).toBe(true);
|
|
69
|
-
expect(parser.testPeakTokenIs('ARROW')).toBe(true);
|
|
70
|
-
expect(parser.testPeakTokenIs('EOF')).toBe(false);
|
|
71
|
-
});
|
|
72
|
-
it('should expect peek token and advance if match', () => {
|
|
73
|
-
const lexer = new MockLexer(tokens);
|
|
74
|
-
const parser = new TestParser(lexer);
|
|
75
|
-
// Peek is ARROW. Expect ARROW should likely succeed?
|
|
76
|
-
// Method signature: expectPeek(t). If peek matches, advance and return true.
|
|
77
|
-
const result = parser.testExpectPeek('ARROW');
|
|
78
|
-
expect(result).toBe(true);
|
|
79
|
-
// After advance, curr is ARROW.
|
|
80
|
-
expect(parser.getCurr().type).toBe('ARROW');
|
|
81
|
-
});
|
|
82
|
-
it('should expect peek token and return false if mismatch', () => {
|
|
83
|
-
const lexer = new MockLexer(tokens);
|
|
84
|
-
const parser = new TestParser(lexer);
|
|
85
|
-
const result = parser.testExpectPeek('EOF'); // Peek is ARROW
|
|
86
|
-
expect(result).toBe(false);
|
|
87
|
-
// Should not have advanced
|
|
88
|
-
expect(parser.getCurr().type).toBe('IDENTIFIER');
|
|
89
|
-
});
|
|
90
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base token interface that all token types should extend.
|
|
3
|
-
* Represents a lexical token with position information.
|
|
4
|
-
*/
|
|
5
|
-
export interface BaseToken {
|
|
6
|
-
/** Token type identifier */
|
|
7
|
-
type: string;
|
|
8
|
-
/** Literal string value of the token */
|
|
9
|
-
literal: string;
|
|
10
|
-
/** Line number (1-indexed) */
|
|
11
|
-
line: number;
|
|
12
|
-
/** Column number (0-indexed) */
|
|
13
|
-
column: number;
|
|
14
|
-
/** Start position in source (0-indexed) */
|
|
15
|
-
start: number;
|
|
16
|
-
/** End position in source (0-indexed) */
|
|
17
|
-
end: number;
|
|
18
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Supported diagram formats
|
|
3
|
-
*/
|
|
4
|
-
export type DiagramFormat = 'mermaid' | 'plantuml';
|
|
5
|
-
/**
|
|
6
|
-
* Format detection utilities for diagram source code.
|
|
7
|
-
* Detects diagram format based on file extension and content analysis.
|
|
8
|
-
*/
|
|
9
|
-
export declare class FormatDetector {
|
|
10
|
-
/**
|
|
11
|
-
* File extensions mapped to their diagram formats
|
|
12
|
-
*/
|
|
13
|
-
private static readonly EXTENSION_MAP;
|
|
14
|
-
/**
|
|
15
|
-
* Content patterns for format detection
|
|
16
|
-
*/
|
|
17
|
-
private static readonly CONTENT_PATTERNS;
|
|
18
|
-
/**
|
|
19
|
-
* Detect diagram format from file path and content.
|
|
20
|
-
*
|
|
21
|
-
* @param filePath - Path to the diagram file
|
|
22
|
-
* @param content - Content of the diagram file
|
|
23
|
-
* @returns Detected format, or null if format cannot be determined
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* const format = FormatDetector.detect('diagram.puml', content);
|
|
28
|
-
* if (format === 'plantuml') {
|
|
29
|
-
* // Process as PlantUML
|
|
30
|
-
* }
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
static detect(filePath: string, content: string): DiagramFormat | null;
|
|
34
|
-
/**
|
|
35
|
-
* Detect format based on file extension.
|
|
36
|
-
*
|
|
37
|
-
* @param filePath - Path to the diagram file
|
|
38
|
-
* @returns Detected format, or null if extension is not recognized
|
|
39
|
-
*/
|
|
40
|
-
static detectByExtension(filePath: string): DiagramFormat | null;
|
|
41
|
-
/**
|
|
42
|
-
* Detect format based on content patterns.
|
|
43
|
-
*
|
|
44
|
-
* @param content - Content of the diagram file
|
|
45
|
-
* @returns Detected format, or null if no pattern matches
|
|
46
|
-
*/
|
|
47
|
-
static detectByContent(content: string): DiagramFormat | null;
|
|
48
|
-
/**
|
|
49
|
-
* Get file extension for a given format.
|
|
50
|
-
*
|
|
51
|
-
* @param format - Diagram format
|
|
52
|
-
* @returns Default file extension for the format
|
|
53
|
-
*/
|
|
54
|
-
static getDefaultExtension(format: DiagramFormat): string;
|
|
55
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format detection utilities for diagram source code.
|
|
3
|
-
* Detects diagram format based on file extension and content analysis.
|
|
4
|
-
*/
|
|
5
|
-
export class FormatDetector {
|
|
6
|
-
/**
|
|
7
|
-
* Detect diagram format from file path and content.
|
|
8
|
-
*
|
|
9
|
-
* @param filePath - Path to the diagram file
|
|
10
|
-
* @param content - Content of the diagram file
|
|
11
|
-
* @returns Detected format, or null if format cannot be determined
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* const format = FormatDetector.detect('diagram.puml', content);
|
|
16
|
-
* if (format === 'plantuml') {
|
|
17
|
-
* // Process as PlantUML
|
|
18
|
-
* }
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
static detect(filePath, content) {
|
|
22
|
-
// Try extension-based detection first
|
|
23
|
-
const extensionFormat = this.detectByExtension(filePath);
|
|
24
|
-
if (extensionFormat) {
|
|
25
|
-
return extensionFormat;
|
|
26
|
-
}
|
|
27
|
-
// Fall back to content-based detection
|
|
28
|
-
return this.detectByContent(content);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Detect format based on file extension.
|
|
32
|
-
*
|
|
33
|
-
* @param filePath - Path to the diagram file
|
|
34
|
-
* @returns Detected format, or null if extension is not recognized
|
|
35
|
-
*/
|
|
36
|
-
static detectByExtension(filePath) {
|
|
37
|
-
const ext = filePath.toLowerCase().match(/\.[^.]+$/)?.[0];
|
|
38
|
-
if (!ext) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
return this.EXTENSION_MAP[ext] || null;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Detect format based on content patterns.
|
|
45
|
-
*
|
|
46
|
-
* @param content - Content of the diagram file
|
|
47
|
-
* @returns Detected format, or null if no pattern matches
|
|
48
|
-
*/
|
|
49
|
-
static detectByContent(content) {
|
|
50
|
-
for (const { pattern, format } of this.CONTENT_PATTERNS) {
|
|
51
|
-
if (pattern.test(content)) {
|
|
52
|
-
return format;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Get file extension for a given format.
|
|
59
|
-
*
|
|
60
|
-
* @param format - Diagram format
|
|
61
|
-
* @returns Default file extension for the format
|
|
62
|
-
*/
|
|
63
|
-
static getDefaultExtension(format) {
|
|
64
|
-
switch (format) {
|
|
65
|
-
case 'plantuml':
|
|
66
|
-
return '.puml';
|
|
67
|
-
case 'mermaid':
|
|
68
|
-
return '.mmd';
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* File extensions mapped to their diagram formats
|
|
74
|
-
*/
|
|
75
|
-
Object.defineProperty(FormatDetector, "EXTENSION_MAP", {
|
|
76
|
-
enumerable: true,
|
|
77
|
-
configurable: true,
|
|
78
|
-
writable: true,
|
|
79
|
-
value: {
|
|
80
|
-
'.puml': 'plantuml',
|
|
81
|
-
'.plantuml': 'plantuml',
|
|
82
|
-
'.pu': 'plantuml',
|
|
83
|
-
'.mmd': 'mermaid',
|
|
84
|
-
'.mermaid': 'mermaid',
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
/**
|
|
88
|
-
* Content patterns for format detection
|
|
89
|
-
*/
|
|
90
|
-
Object.defineProperty(FormatDetector, "CONTENT_PATTERNS", {
|
|
91
|
-
enumerable: true,
|
|
92
|
-
configurable: true,
|
|
93
|
-
writable: true,
|
|
94
|
-
value: [
|
|
95
|
-
{ pattern: /^\s*@startuml/m, format: 'plantuml' },
|
|
96
|
-
{ pattern: /^\s*sequenceDiagram/m, format: 'mermaid' },
|
|
97
|
-
]
|
|
98
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { DiagramParser } from './interface';
|
|
2
|
-
/**
|
|
3
|
-
* Parser Factory
|
|
4
|
-
* Centralizes retrieval of parser strategies.
|
|
5
|
-
*/
|
|
6
|
-
export declare class ParserFactory {
|
|
7
|
-
private static parsers;
|
|
8
|
-
static register(language: string, parser: DiagramParser): void;
|
|
9
|
-
static getParser(language: string): DiagramParser;
|
|
10
|
-
}
|
|
11
|
-
export { FormatDetector, type DiagramFormat } from './format-detector';
|
package/dist/src/parser/index.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
var _a;
|
|
2
|
-
import { mermaidParser } from './languages/mermaid';
|
|
3
|
-
import { plantumlParser } from './languages/plantuml';
|
|
4
|
-
/**
|
|
5
|
-
* Parser Factory
|
|
6
|
-
* Centralizes retrieval of parser strategies.
|
|
7
|
-
*/
|
|
8
|
-
export class ParserFactory {
|
|
9
|
-
static register(language, parser) {
|
|
10
|
-
this.parsers.set(language, parser);
|
|
11
|
-
}
|
|
12
|
-
static getParser(language) {
|
|
13
|
-
const parser = this.parsers.get(language);
|
|
14
|
-
if (!parser) {
|
|
15
|
-
throw new Error(`Parser for language '${language}' not found.`);
|
|
16
|
-
}
|
|
17
|
-
return parser;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
_a = ParserFactory;
|
|
21
|
-
Object.defineProperty(ParserFactory, "parsers", {
|
|
22
|
-
enumerable: true,
|
|
23
|
-
configurable: true,
|
|
24
|
-
writable: true,
|
|
25
|
-
value: new Map()
|
|
26
|
-
});
|
|
27
|
-
(() => {
|
|
28
|
-
// Register built-in parsers
|
|
29
|
-
_a.register('mermaid', mermaidParser);
|
|
30
|
-
_a.register('plantuml', plantumlParser);
|
|
31
|
-
})();
|
|
32
|
-
// Re-export format detector
|
|
33
|
-
export { FormatDetector } from './format-detector';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { ParserFactory } from './index';
|
|
3
|
-
describe('ParserFactory', () => {
|
|
4
|
-
it('should retrieve registered parser', () => {
|
|
5
|
-
const parser = ParserFactory.getParser('mermaid');
|
|
6
|
-
expect(parser).toBeDefined();
|
|
7
|
-
// Since we import implemented parser, we expect checking it conforms to interface
|
|
8
|
-
expect(typeof parser.parse).toBe('function');
|
|
9
|
-
});
|
|
10
|
-
it('should throw error for unknown language', () => {
|
|
11
|
-
expect(() => {
|
|
12
|
-
ParserFactory.getParser('unknown-lang');
|
|
13
|
-
}).toThrow("Parser for language 'unknown-lang' not found.");
|
|
14
|
-
});
|
|
15
|
-
it('should allow registering new parser', () => {
|
|
16
|
-
const mockParser = {
|
|
17
|
-
parse: (_code) => ({ kind: 'root', meta: { version: '1.0.0', source: 'unknown' }, participants: [], groups: [], events: [] })
|
|
18
|
-
};
|
|
19
|
-
ParserFactory.register('test-lang', mockParser);
|
|
20
|
-
const retrieved = ParserFactory.getParser('test-lang');
|
|
21
|
-
expect(retrieved).toBe(mockParser);
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { MessageNode } from '../../../ast';
|
|
2
|
-
export declare const ARROW_MAPPING: Record<string, {
|
|
3
|
-
type: MessageNode['type'];
|
|
4
|
-
style: MessageNode['style'];
|
|
5
|
-
}>;
|
|
6
|
-
export declare const REVERSE_ARROW_MAPPING: Record<string, string>;
|
|
7
|
-
export declare function getArrowString(type: MessageNode['type'], style: MessageNode['style']): string;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export const ARROW_MAPPING = {
|
|
2
|
-
'->': { type: 'sync', style: { line: 'solid', head: 'open' } },
|
|
3
|
-
'->>': { type: 'sync', style: { line: 'solid', head: 'arrow' } },
|
|
4
|
-
'-->': { type: 'reply', style: { line: 'dotted', head: 'open' } },
|
|
5
|
-
'-->>': { type: 'reply', style: { line: 'dotted', head: 'arrow' } },
|
|
6
|
-
'-)': { type: 'async', style: { line: 'solid', head: 'async' } },
|
|
7
|
-
'--)': { type: 'async', style: { line: 'dotted', head: 'async' } },
|
|
8
|
-
'-x': { type: 'destroy', style: { line: 'solid', head: 'cross' } },
|
|
9
|
-
'--x': { type: 'destroy', style: { line: 'dotted', head: 'cross' } },
|
|
10
|
-
};
|
|
11
|
-
export const REVERSE_ARROW_MAPPING = Object.entries(ARROW_MAPPING).reduce((acc, [key, value]) => {
|
|
12
|
-
// Create a unique key for the style + type combination to map back to the string
|
|
13
|
-
const lookupKey = JSON.stringify({ type: value.type, style: value.style });
|
|
14
|
-
acc[lookupKey] = key;
|
|
15
|
-
return acc;
|
|
16
|
-
}, {});
|
|
17
|
-
export function getArrowString(type, style) {
|
|
18
|
-
const key = JSON.stringify({ type, style });
|
|
19
|
-
return REVERSE_ARROW_MAPPING[key] || '->>'; // Default fallthrough
|
|
20
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Lexer } from './lexer';
|
|
2
|
-
import { Parser } from './parser';
|
|
3
|
-
export const mermaidParser = {
|
|
4
|
-
parse: (code) => {
|
|
5
|
-
const lexer = new Lexer(code);
|
|
6
|
-
const parser = new Parser(lexer);
|
|
7
|
-
return parser.parse();
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
export { Lexer } from './lexer';
|
|
11
|
-
export { Parser } from './parser';
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { BaseLexer } from '../../base/lexer';
|
|
2
|
-
import { Token } from './tokens';
|
|
3
|
-
export declare class Lexer extends BaseLexer<Token> {
|
|
4
|
-
constructor(input: string);
|
|
5
|
-
nextToken(): Token;
|
|
6
|
-
private newToken;
|
|
7
|
-
private readIdentifier;
|
|
8
|
-
private readNumber;
|
|
9
|
-
private readString;
|
|
10
|
-
private isArrowStart;
|
|
11
|
-
private readArrow;
|
|
12
|
-
private readMulti;
|
|
13
|
-
private lookupIdent;
|
|
14
|
-
}
|
|
@@ -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,22 +0,0 @@
|
|
|
1
|
-
import { PolagramRoot } from '../../../ast';
|
|
2
|
-
import { BaseParser } from '../../base/parser';
|
|
3
|
-
import { Lexer } from './lexer';
|
|
4
|
-
import { Token } from './tokens';
|
|
5
|
-
export declare class Parser extends BaseParser<Token> {
|
|
6
|
-
private currentGroup;
|
|
7
|
-
private idCounters;
|
|
8
|
-
constructor(lexer: Lexer);
|
|
9
|
-
parse(): PolagramRoot;
|
|
10
|
-
private parseBlock;
|
|
11
|
-
private isParticipantToken;
|
|
12
|
-
private parseGroup;
|
|
13
|
-
private parseFragment;
|
|
14
|
-
private parseParticipant;
|
|
15
|
-
private parseNote;
|
|
16
|
-
private parseActivation;
|
|
17
|
-
private parseMessage;
|
|
18
|
-
private resolveArrow;
|
|
19
|
-
private generateId;
|
|
20
|
-
private readRestOfLine;
|
|
21
|
-
private ensureParticipant;
|
|
22
|
-
}
|