@polagram/core 0.0.3 → 0.0.4
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 +104 -6
- package/dist/polagram-core.js +2689 -2157
- package/dist/polagram-core.umd.cjs +20 -14
- package/dist/src/api.d.ts +12 -3
- package/dist/src/api.js +26 -3
- package/dist/src/config/schema.d.ts +16 -0
- package/dist/src/config/schema.js +5 -1
- package/dist/src/generator/generators/plantuml.d.ts +17 -0
- package/dist/src/generator/generators/plantuml.js +131 -0
- package/dist/src/generator/generators/plantuml.test.d.ts +1 -0
- package/dist/src/generator/generators/plantuml.test.js +143 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +4 -0
- package/dist/src/parser/base/lexer.d.ts +3 -3
- package/dist/src/parser/base/parser.d.ts +9 -9
- package/dist/src/parser/base/token.d.ts +18 -0
- package/dist/src/parser/base/token.js +1 -0
- package/dist/src/parser/base/tokens.d.ts +8 -0
- package/dist/src/parser/base/tokens.js +1 -0
- package/dist/src/parser/format-detector.d.ts +55 -0
- package/dist/src/parser/format-detector.js +98 -0
- package/dist/src/parser/index.d.ts +1 -0
- package/dist/src/parser/index.js +4 -0
- package/dist/src/parser/languages/mermaid/lexer.d.ts +1 -1
- package/dist/src/parser/languages/mermaid/parser.d.ts +2 -1
- package/dist/src/parser/languages/plantuml/index.d.ts +4 -0
- package/dist/src/parser/languages/plantuml/index.js +11 -0
- package/dist/src/parser/languages/plantuml/lexer.d.ts +15 -0
- package/dist/src/parser/languages/plantuml/lexer.js +143 -0
- package/dist/src/parser/languages/plantuml/parser.d.ts +23 -0
- package/dist/src/parser/languages/plantuml/parser.js +481 -0
- package/dist/src/parser/languages/plantuml/parser.test.d.ts +1 -0
- package/dist/src/parser/languages/plantuml/parser.test.js +236 -0
- package/dist/src/parser/languages/plantuml/tokens.d.ts +9 -0
- package/dist/src/parser/languages/plantuml/tokens.js +1 -0
- package/dist/src/transformer/orchestration/engine.test.js +12 -1
- package/dist/src/transformer/selector/matcher.test.js +17 -0
- package/dist/src/transformer/traverse/walker.test.js +67 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -9
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
});
|
package/dist/src/parser/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var _a;
|
|
2
2
|
import { mermaidParser } from './languages/mermaid';
|
|
3
|
+
import { plantumlParser } from './languages/plantuml';
|
|
3
4
|
/**
|
|
4
5
|
* Parser Factory
|
|
5
6
|
* Centralizes retrieval of parser strategies.
|
|
@@ -26,4 +27,7 @@ Object.defineProperty(ParserFactory, "parsers", {
|
|
|
26
27
|
(() => {
|
|
27
28
|
// Register built-in parsers
|
|
28
29
|
_a.register('mermaid', mermaidParser);
|
|
30
|
+
_a.register('plantuml', plantumlParser);
|
|
29
31
|
})();
|
|
32
|
+
// Re-export format detector
|
|
33
|
+
export { FormatDetector } from './format-detector';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { PolagramRoot } from '../../../ast';
|
|
2
2
|
import { BaseParser } from '../../base/parser';
|
|
3
3
|
import { Lexer } from './lexer';
|
|
4
|
-
|
|
4
|
+
import { Token } from './tokens';
|
|
5
|
+
export declare class Parser extends BaseParser<Token> {
|
|
5
6
|
private currentGroup;
|
|
6
7
|
private idCounters;
|
|
7
8
|
constructor(lexer: Lexer);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Lexer } from './lexer';
|
|
2
|
+
import { Parser } from './parser';
|
|
3
|
+
export const plantumlParser = {
|
|
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';
|
|
@@ -0,0 +1,15 @@
|
|
|
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 readString;
|
|
9
|
+
private lookupIdent;
|
|
10
|
+
private readArrow;
|
|
11
|
+
private peekExact;
|
|
12
|
+
private peekString;
|
|
13
|
+
readRestOfLine(): string;
|
|
14
|
+
private readMulti;
|
|
15
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
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 '\n':
|
|
13
|
+
tok = this.newToken('NEWLINE', this.ch, start, startColumn);
|
|
14
|
+
break;
|
|
15
|
+
case '@':
|
|
16
|
+
if (this.peekString('startuml')) {
|
|
17
|
+
this.readMulti(9);
|
|
18
|
+
tok = this.newToken('START_UML', '@startuml', start, startColumn);
|
|
19
|
+
}
|
|
20
|
+
else if (this.peekString('enduml')) {
|
|
21
|
+
this.readMulti(7);
|
|
22
|
+
tok = this.newToken('END_UML', '@enduml', start, startColumn);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
tok = this.newToken('UNKNOWN', this.ch, start, startColumn);
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
case ',':
|
|
29
|
+
tok = this.newToken('COMMA', ',', start, startColumn);
|
|
30
|
+
break;
|
|
31
|
+
case '"':
|
|
32
|
+
const str = this.readString();
|
|
33
|
+
return this.newToken('STRING', str, start, startColumn);
|
|
34
|
+
case ':':
|
|
35
|
+
tok = this.newToken('COLON', ':', start, startColumn);
|
|
36
|
+
break;
|
|
37
|
+
case '-':
|
|
38
|
+
const arrow = this.readArrow();
|
|
39
|
+
if (arrow) {
|
|
40
|
+
tok = this.newToken('ARROW', arrow, start, startColumn);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
tok = this.newToken('UNKNOWN', this.ch, start, startColumn);
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
case '':
|
|
47
|
+
tok = this.newToken('EOF', '', start, startColumn);
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
if (this.isLetter(this.ch)) {
|
|
51
|
+
const literal = this.readIdentifier();
|
|
52
|
+
const type = this.lookupIdent(literal);
|
|
53
|
+
return this.newToken(type, literal, start, startColumn);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
tok = this.newToken('UNKNOWN', this.ch, start, startColumn);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
this.readChar();
|
|
60
|
+
return tok;
|
|
61
|
+
}
|
|
62
|
+
newToken(type, literal, start, startColumn) {
|
|
63
|
+
const end = (this.position === start) ? start + literal.length : this.position;
|
|
64
|
+
return { type, literal, line: this.line, column: startColumn, start, end };
|
|
65
|
+
}
|
|
66
|
+
readIdentifier() {
|
|
67
|
+
const position = this.position;
|
|
68
|
+
while (this.isLetter(this.ch) || this.isDigit(this.ch)) {
|
|
69
|
+
this.readChar();
|
|
70
|
+
}
|
|
71
|
+
return this.input.slice(position, this.position);
|
|
72
|
+
}
|
|
73
|
+
readString() {
|
|
74
|
+
const position = this.position + 1;
|
|
75
|
+
this.readChar();
|
|
76
|
+
while (this.ch !== '"' && this.ch !== '' && this.ch !== '\n') {
|
|
77
|
+
this.readChar();
|
|
78
|
+
}
|
|
79
|
+
const str = this.input.slice(position, this.position);
|
|
80
|
+
this.readChar();
|
|
81
|
+
return str;
|
|
82
|
+
}
|
|
83
|
+
lookupIdent(ident) {
|
|
84
|
+
const keywords = {
|
|
85
|
+
'title': 'TITLE',
|
|
86
|
+
'participant': 'PARTICIPANT',
|
|
87
|
+
'actor': 'ACTOR',
|
|
88
|
+
'database': 'DATABASE',
|
|
89
|
+
'as': 'AS',
|
|
90
|
+
'activate': 'ACTIVATE',
|
|
91
|
+
'deactivate': 'DEACTIVATE',
|
|
92
|
+
'note': 'NOTE',
|
|
93
|
+
'left': 'LEFT',
|
|
94
|
+
'right': 'RIGHT',
|
|
95
|
+
'over': 'OVER',
|
|
96
|
+
'of': 'OF',
|
|
97
|
+
'alt': 'ALT',
|
|
98
|
+
'opt': 'OPT',
|
|
99
|
+
'loop': 'LOOP',
|
|
100
|
+
'else': 'ELSE',
|
|
101
|
+
'end': 'END',
|
|
102
|
+
'box': 'BOX',
|
|
103
|
+
'@startuml': 'START_UML',
|
|
104
|
+
'@enduml': 'END_UML'
|
|
105
|
+
};
|
|
106
|
+
return keywords[ident] || 'IDENTIFIER';
|
|
107
|
+
}
|
|
108
|
+
readArrow() {
|
|
109
|
+
// We are at '-'
|
|
110
|
+
// Check for -->
|
|
111
|
+
if (this.peekString('->')) {
|
|
112
|
+
this.readMulti(2);
|
|
113
|
+
return '-->';
|
|
114
|
+
}
|
|
115
|
+
// Check for ->
|
|
116
|
+
if (this.peekExact('>')) {
|
|
117
|
+
this.readMulti(1);
|
|
118
|
+
return '->';
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
peekExact(char) {
|
|
123
|
+
return this.input[this.position + 1] === char;
|
|
124
|
+
}
|
|
125
|
+
peekString(str) {
|
|
126
|
+
for (let i = 0; i < str.length; i++) {
|
|
127
|
+
if (this.input[this.position + 1 + i] !== str[i])
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
readRestOfLine() {
|
|
133
|
+
const start = this.position;
|
|
134
|
+
while (this.input[this.position] !== '\n' && this.input[this.position] !== '' && this.position < this.input.length) {
|
|
135
|
+
this.readChar();
|
|
136
|
+
}
|
|
137
|
+
return this.input.slice(start, this.position).trim();
|
|
138
|
+
}
|
|
139
|
+
readMulti(count) {
|
|
140
|
+
for (let i = 0; i < count; i++)
|
|
141
|
+
this.readChar();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
constructor(lexer: Lexer);
|
|
7
|
+
/**
|
|
8
|
+
* Type-safe token type checker.
|
|
9
|
+
* Helps TypeScript understand token type after advance() calls.
|
|
10
|
+
*/
|
|
11
|
+
private isTokenType;
|
|
12
|
+
parse(): PolagramRoot;
|
|
13
|
+
private parseGroup;
|
|
14
|
+
private parseFragment;
|
|
15
|
+
private parseStatement;
|
|
16
|
+
private parseNote;
|
|
17
|
+
private parseActivation;
|
|
18
|
+
private isParticipantToken;
|
|
19
|
+
private parseMessage;
|
|
20
|
+
private ensureParticipant;
|
|
21
|
+
private parseParticipant;
|
|
22
|
+
private readRestOfLine;
|
|
23
|
+
}
|