@fazelstudio/floe 1.0.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/LICENSE +21 -0
- package/dist/src/cli/check.d.ts +14 -0
- package/dist/src/cli/check.d.ts.map +1 -0
- package/dist/src/cli/check.js +88 -0
- package/dist/src/cli/check.js.map +1 -0
- package/dist/src/cli/format.d.ts +9 -0
- package/dist/src/cli/format.d.ts.map +1 -0
- package/dist/src/cli/format.js +114 -0
- package/dist/src/cli/format.js.map +1 -0
- package/dist/src/cli/main.d.ts +19 -0
- package/dist/src/cli/main.d.ts.map +1 -0
- package/dist/src/cli/main.js +207 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/render.d.ts +7 -0
- package/dist/src/cli/render.d.ts.map +1 -0
- package/dist/src/cli/render.js +90 -0
- package/dist/src/cli/render.js.map +1 -0
- package/dist/src/diagnostics.d.ts +32 -0
- package/dist/src/diagnostics.d.ts.map +1 -0
- package/dist/src/diagnostics.js +4 -0
- package/dist/src/diagnostics.js.map +1 -0
- package/dist/src/index.d.ts +40 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +64 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/language/completion.d.ts +6 -0
- package/dist/src/language/completion.d.ts.map +1 -0
- package/dist/src/language/completion.js +363 -0
- package/dist/src/language/completion.js.map +1 -0
- package/dist/src/language/definitions.d.ts +9 -0
- package/dist/src/language/definitions.d.ts.map +1 -0
- package/dist/src/language/definitions.js +70 -0
- package/dist/src/language/definitions.js.map +1 -0
- package/dist/src/language/diagnosticsService.d.ts +14 -0
- package/dist/src/language/diagnosticsService.d.ts.map +1 -0
- package/dist/src/language/diagnosticsService.js +37 -0
- package/dist/src/language/diagnosticsService.js.map +1 -0
- package/dist/src/language/folding.d.ts +8 -0
- package/dist/src/language/folding.d.ts.map +1 -0
- package/dist/src/language/folding.js +58 -0
- package/dist/src/language/folding.js.map +1 -0
- package/dist/src/language/formatting.d.ts +5 -0
- package/dist/src/language/formatting.d.ts.map +1 -0
- package/dist/src/language/formatting.js +274 -0
- package/dist/src/language/formatting.js.map +1 -0
- package/dist/src/language/highlighting.d.ts +9 -0
- package/dist/src/language/highlighting.d.ts.map +1 -0
- package/dist/src/language/highlighting.js +74 -0
- package/dist/src/language/highlighting.js.map +1 -0
- package/dist/src/language/hover.d.ts +6 -0
- package/dist/src/language/hover.d.ts.map +1 -0
- package/dist/src/language/hover.js +197 -0
- package/dist/src/language/hover.js.map +1 -0
- package/dist/src/language/indentation.d.ts +15 -0
- package/dist/src/language/indentation.d.ts.map +1 -0
- package/dist/src/language/indentation.js +97 -0
- package/dist/src/language/indentation.js.map +1 -0
- package/dist/src/language/index.d.ts +54 -0
- package/dist/src/language/index.d.ts.map +1 -0
- package/dist/src/language/index.js +85 -0
- package/dist/src/language/index.js.map +1 -0
- package/dist/src/language/references.d.ts +12 -0
- package/dist/src/language/references.d.ts.map +1 -0
- package/dist/src/language/references.js +35 -0
- package/dist/src/language/references.js.map +1 -0
- package/dist/src/language/rename.d.ts +18 -0
- package/dist/src/language/rename.d.ts.map +1 -0
- package/dist/src/language/rename.js +53 -0
- package/dist/src/language/rename.js.map +1 -0
- package/dist/src/language/semanticModel.d.ts +21 -0
- package/dist/src/language/semanticModel.d.ts.map +1 -0
- package/dist/src/language/semanticModel.js +43 -0
- package/dist/src/language/semanticModel.js.map +1 -0
- package/dist/src/language/symbols.d.ts +9 -0
- package/dist/src/language/symbols.d.ts.map +1 -0
- package/dist/src/language/symbols.js +160 -0
- package/dist/src/language/symbols.js.map +1 -0
- package/dist/src/language/types.d.ts +49 -0
- package/dist/src/language/types.d.ts.map +1 -0
- package/dist/src/language/types.js +2 -0
- package/dist/src/language/types.js.map +1 -0
- package/dist/src/language/utils.d.ts +24 -0
- package/dist/src/language/utils.d.ts.map +1 -0
- package/dist/src/language/utils.js +154 -0
- package/dist/src/language/utils.js.map +1 -0
- package/dist/src/layout/dagre.d.ts +13 -0
- package/dist/src/layout/dagre.d.ts.map +1 -0
- package/dist/src/layout/dagre.js +229 -0
- package/dist/src/layout/dagre.js.map +1 -0
- package/dist/src/layout/index.d.ts +15 -0
- package/dist/src/layout/index.d.ts.map +1 -0
- package/dist/src/layout/index.js +22 -0
- package/dist/src/layout/index.js.map +1 -0
- package/dist/src/layout/simple.d.ts +20 -0
- package/dist/src/layout/simple.d.ts.map +1 -0
- package/dist/src/layout/simple.js +674 -0
- package/dist/src/layout/simple.js.map +1 -0
- package/dist/src/layout/types.d.ts +65 -0
- package/dist/src/layout/types.d.ts.map +1 -0
- package/dist/src/layout/types.js +2 -0
- package/dist/src/layout/types.js.map +1 -0
- package/dist/src/lexer.d.ts +25 -0
- package/dist/src/lexer.d.ts.map +1 -0
- package/dist/src/lexer.js +280 -0
- package/dist/src/lexer.js.map +1 -0
- package/dist/src/lsp/documents.d.ts +24 -0
- package/dist/src/lsp/documents.d.ts.map +1 -0
- package/dist/src/lsp/documents.js +97 -0
- package/dist/src/lsp/documents.js.map +1 -0
- package/dist/src/lsp/server.d.ts +70 -0
- package/dist/src/lsp/server.d.ts.map +1 -0
- package/dist/src/lsp/server.js +623 -0
- package/dist/src/lsp/server.js.map +1 -0
- package/dist/src/lsp/utils.d.ts +47 -0
- package/dist/src/lsp/utils.d.ts.map +1 -0
- package/dist/src/lsp/utils.js +142 -0
- package/dist/src/lsp/utils.js.map +1 -0
- package/dist/src/parser.d.ts +106 -0
- package/dist/src/parser.d.ts.map +1 -0
- package/dist/src/parser.js +1018 -0
- package/dist/src/parser.js.map +1 -0
- package/dist/src/pipeline.d.ts +51 -0
- package/dist/src/pipeline.d.ts.map +1 -0
- package/dist/src/pipeline.js +65 -0
- package/dist/src/pipeline.js.map +1 -0
- package/dist/src/range.d.ts +24 -0
- package/dist/src/range.d.ts.map +1 -0
- package/dist/src/range.js +20 -0
- package/dist/src/range.js.map +1 -0
- package/dist/src/render/index.d.ts +3 -0
- package/dist/src/render/index.d.ts.map +1 -0
- package/dist/src/render/index.js +3 -0
- package/dist/src/render/index.js.map +1 -0
- package/dist/src/render/shapes.d.ts +20 -0
- package/dist/src/render/shapes.d.ts.map +1 -0
- package/dist/src/render/shapes.js +110 -0
- package/dist/src/render/shapes.js.map +1 -0
- package/dist/src/render/svg.d.ts +19 -0
- package/dist/src/render/svg.d.ts.map +1 -0
- package/dist/src/render/svg.js +227 -0
- package/dist/src/render/svg.js.map +1 -0
- package/dist/src/security/url.d.ts +7 -0
- package/dist/src/security/url.d.ts.map +1 -0
- package/dist/src/security/url.js +27 -0
- package/dist/src/security/url.js.map +1 -0
- package/dist/src/types.d.ts +111 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +16 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/validator.d.ts +47 -0
- package/dist/src/validator.d.ts.map +1 -0
- package/dist/src/validator.js +235 -0
- package/dist/src/validator.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Parser } from "../parser.js";
|
|
2
|
+
import { validate } from "../validator.js";
|
|
3
|
+
function parseFloe(source) {
|
|
4
|
+
const raw = new Parser(source).parse();
|
|
5
|
+
const validated = validate({
|
|
6
|
+
diagram: raw.diagram,
|
|
7
|
+
diagnostics: raw.diagnostics,
|
|
8
|
+
explicitNodes: raw.explicitNodes,
|
|
9
|
+
edges: raw.edges,
|
|
10
|
+
directionDeclarations: raw.directionDeclarations,
|
|
11
|
+
groups: raw.groups,
|
|
12
|
+
annotations: raw.annotations,
|
|
13
|
+
links: raw.links,
|
|
14
|
+
});
|
|
15
|
+
return { diagram: validated.diagram, diagnostics: validated.diagnostics };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Diagnostics API — useful while document is incomplete.
|
|
19
|
+
* Should produce recoverable diagnostic rather than crashing.
|
|
20
|
+
* Example: "User ->" should produce E009/E006 not throw.
|
|
21
|
+
*/
|
|
22
|
+
export function getDiagnostics(source) {
|
|
23
|
+
const { diagnostics } = parseFloe(source);
|
|
24
|
+
return diagnostics;
|
|
25
|
+
}
|
|
26
|
+
export function getDiagnosticsWithSource(source) {
|
|
27
|
+
const diagnostics = getDiagnostics(source);
|
|
28
|
+
return {
|
|
29
|
+
diagnostics,
|
|
30
|
+
hasErrors: diagnostics.some((d) => d.severity === "error"),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** For LSP/CodeMirror lint integration — returns diagnostics sorted */
|
|
34
|
+
export function lint(source) {
|
|
35
|
+
return getDiagnostics(source).sort((a, b) => a.range.start.offset - b.range.start.offset);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=diagnosticsService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnosticsService.js","sourceRoot":"","sources":["../../../src/language/diagnosticsService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,SAAS,SAAS,CAAC,MAAc;IAC/B,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,QAAQ,CAAC;QACzB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,qBAAqB,EAAE,GAAG,CAAC,qBAAqB;QAChD,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,KAAK,EAAE,GAAG,CAAC,KAAK;KACjB,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC;AAC5E,CAAC;AAED;;;;GAIG;AAEH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAc;IACrD,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3C,OAAO;QACL,WAAW;QACX,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC;KAC3D,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,IAAI,CAAC,MAAc;IACjC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC5F,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FoldingRange } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Folding information — where applicable, groups with braces.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getFoldingRanges(source: string): FoldingRange[];
|
|
6
|
+
/** For CodeMirror folding service — alias */
|
|
7
|
+
export declare function getFoldingInfo(source: string): FoldingRange[];
|
|
8
|
+
//# sourceMappingURL=folding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folding.d.ts","sourceRoot":"","sources":["../../../src/language/folding.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;GAEG;AAEH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAkD/D;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAE7D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { tokenize } from "../lexer.js";
|
|
2
|
+
/**
|
|
3
|
+
* Folding information — where applicable, groups with braces.
|
|
4
|
+
*/
|
|
5
|
+
export function getFoldingRanges(source) {
|
|
6
|
+
const tokens = tokenize(source);
|
|
7
|
+
const stack = [];
|
|
8
|
+
const ranges = [];
|
|
9
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
10
|
+
const tok = tokens[i];
|
|
11
|
+
if (tok.type === "LBRACE") {
|
|
12
|
+
stack.push({ line: tok.range.start.line, column: tok.range.start.column, offset: tok.range.start.offset });
|
|
13
|
+
}
|
|
14
|
+
else if (tok.type === "RBRACE") {
|
|
15
|
+
const open = stack.pop();
|
|
16
|
+
if (open) {
|
|
17
|
+
const startLine = open.line;
|
|
18
|
+
const endLine = tok.range.end.line;
|
|
19
|
+
if (endLine > startLine) {
|
|
20
|
+
ranges.push({
|
|
21
|
+
startLine,
|
|
22
|
+
endLine,
|
|
23
|
+
startColumn: open.column,
|
|
24
|
+
endColumn: tok.range.end.column,
|
|
25
|
+
kind: "group",
|
|
26
|
+
collapsedText: "…",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Also detect unclosed groups (still provide folding from open to end of file)
|
|
33
|
+
// For diagnostics we already handle, but for folding we could include open until EOF
|
|
34
|
+
if (stack.length > 0) {
|
|
35
|
+
const lines = source.split(/\r?\n/);
|
|
36
|
+
const endLine = lines.length;
|
|
37
|
+
for (const open of stack) {
|
|
38
|
+
if (endLine > open.line) {
|
|
39
|
+
ranges.push({
|
|
40
|
+
startLine: open.line,
|
|
41
|
+
endLine,
|
|
42
|
+
startColumn: open.column,
|
|
43
|
+
endColumn: 1,
|
|
44
|
+
kind: "group",
|
|
45
|
+
collapsedText: "…",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Sort by startLine
|
|
51
|
+
ranges.sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine);
|
|
52
|
+
return ranges;
|
|
53
|
+
}
|
|
54
|
+
/** For CodeMirror folding service — alias */
|
|
55
|
+
export function getFoldingInfo(source) {
|
|
56
|
+
return getFoldingRanges(source);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=folding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folding.js","sourceRoot":"","sources":["../../../src/language/folding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC;;GAEG;AAEH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,KAAK,GAAyE,EAAE,CAAC;IACvF,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACvB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7G,CAAC;aAAM,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YACzB,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC5B,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBACnC,IAAI,OAAO,GAAG,SAAS,EAAE,CAAC;oBACxB,MAAM,CAAC,IAAI,CAAC;wBACV,SAAS;wBACT,OAAO;wBACP,WAAW,EAAE,IAAI,CAAC,MAAM;wBACxB,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;wBAC/B,IAAI,EAAE,OAAO;wBACb,aAAa,EAAE,GAAG;qBACnB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,+EAA+E;IAC/E,qFAAqF;IACrF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBACxB,MAAM,CAAC,IAAI,CAAC;oBACV,SAAS,EAAE,IAAI,CAAC,IAAI;oBACpB,OAAO;oBACP,WAAW,EAAE,IAAI,CAAC,MAAM;oBACxB,SAAS,EAAE,CAAC;oBACZ,IAAI,EAAE,OAAO;oBACb,aAAa,EAAE,GAAG;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC1E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FormattingOptions } from "./types.js";
|
|
2
|
+
export declare function format(source: string, opts?: FormattingOptions): string;
|
|
3
|
+
/** Check if formatted output is idempotent — formatting twice yields same result */
|
|
4
|
+
export declare function isFormatted(source: string): boolean;
|
|
5
|
+
//# sourceMappingURL=formatting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../../src/language/formatting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAiBpD,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAiEvE;AAyMD,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatter — create canonical formatting, deterministic.
|
|
3
|
+
* Input:
|
|
4
|
+
* A->B
|
|
5
|
+
* B -> C: hello
|
|
6
|
+
* Output:
|
|
7
|
+
* A -> B
|
|
8
|
+
* B -> C : hello
|
|
9
|
+
*
|
|
10
|
+
* Must be deterministic and preserve semantics.
|
|
11
|
+
* Operates on Floe language model — line-oriented formatting with group indentation.
|
|
12
|
+
*/
|
|
13
|
+
const INDENT = " ";
|
|
14
|
+
export function format(source, opts) {
|
|
15
|
+
const indentStr = opts?.indentString ?? INDENT;
|
|
16
|
+
const lines = source.split(/\r?\n/);
|
|
17
|
+
const outLines = [];
|
|
18
|
+
let indentLevel = 0;
|
|
19
|
+
for (let i = 0; i < lines.length; i++) {
|
|
20
|
+
const raw = lines[i] ?? "";
|
|
21
|
+
const trimmed = raw.trim();
|
|
22
|
+
// Handle blank lines - preserve but normalize to empty, collapse handled later
|
|
23
|
+
if (trimmed === "") {
|
|
24
|
+
outLines.push("");
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
// Extract comment part respecting strings
|
|
28
|
+
const { codePart, commentPart } = splitComment(trimmed);
|
|
29
|
+
// If whole line is comment
|
|
30
|
+
if (codePart === "" && commentPart !== "") {
|
|
31
|
+
outLines.push(indentStr.repeat(indentLevel) + normalizeComment(commentPart));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// Detect closing brace line before indent calculation
|
|
35
|
+
const isClosingBrace = codePart.trim() === "}";
|
|
36
|
+
if (isClosingBrace) {
|
|
37
|
+
indentLevel = Math.max(0, indentLevel - 1);
|
|
38
|
+
const formatted = formatCodePart(codePart, commentPart, indentLevel, indentStr);
|
|
39
|
+
outLines.push(formatted);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Normal line
|
|
43
|
+
const formatted = formatCodePart(codePart, commentPart, indentLevel, indentStr);
|
|
44
|
+
outLines.push(formatted);
|
|
45
|
+
// After formatting, check if line opens a group brace to increase indent for next lines
|
|
46
|
+
// Need to detect if codePart contains "group ... {"
|
|
47
|
+
if (isGroupOpening(codePart)) {
|
|
48
|
+
indentLevel++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Post-process: collapse multiple consecutive blank lines to at most one, trim trailing blanks, ensure final newline
|
|
52
|
+
const collapsed = [];
|
|
53
|
+
let prevBlank = false;
|
|
54
|
+
for (const l of outLines) {
|
|
55
|
+
const isBlank = l === "";
|
|
56
|
+
if (isBlank && prevBlank)
|
|
57
|
+
continue;
|
|
58
|
+
collapsed.push(l);
|
|
59
|
+
prevBlank = isBlank;
|
|
60
|
+
}
|
|
61
|
+
// Remove leading blank lines
|
|
62
|
+
while (collapsed.length > 0 && collapsed[0] === "")
|
|
63
|
+
collapsed.shift();
|
|
64
|
+
// Remove trailing blank lines before ensuring final newline
|
|
65
|
+
while (collapsed.length > 0 && collapsed[collapsed.length - 1] === "")
|
|
66
|
+
collapsed.pop();
|
|
67
|
+
let result = collapsed.join("\n");
|
|
68
|
+
if (result.length === 0)
|
|
69
|
+
return opts?.insertFinalNewline === false ? "" : "";
|
|
70
|
+
if (opts?.insertFinalNewline !== false) {
|
|
71
|
+
if (!result.endsWith("\n"))
|
|
72
|
+
result += "\n";
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function normalizeComment(c) {
|
|
77
|
+
const trim = c.trim();
|
|
78
|
+
if (trim.startsWith("//")) {
|
|
79
|
+
const content = trim.slice(2).trimStart();
|
|
80
|
+
if (content === "")
|
|
81
|
+
return "//";
|
|
82
|
+
return `// ${content}`;
|
|
83
|
+
}
|
|
84
|
+
return trim;
|
|
85
|
+
}
|
|
86
|
+
function splitComment(line) {
|
|
87
|
+
let inString = false;
|
|
88
|
+
let escaped = false;
|
|
89
|
+
for (let i = 0; i < line.length - 1; i++) {
|
|
90
|
+
const ch = line[i];
|
|
91
|
+
const nxt = line[i + 1];
|
|
92
|
+
if (!inString && ch === '"' && !escaped) {
|
|
93
|
+
inString = true;
|
|
94
|
+
escaped = false;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (inString) {
|
|
98
|
+
if (ch === "\\" && !escaped) {
|
|
99
|
+
escaped = true;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (ch === '"' && !escaped) {
|
|
103
|
+
inString = false;
|
|
104
|
+
}
|
|
105
|
+
escaped = false;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!inString && ch === "/" && nxt === "/") {
|
|
109
|
+
const code = line.slice(0, i).trimEnd();
|
|
110
|
+
const comment = line.slice(i).trim();
|
|
111
|
+
return { codePart: code, commentPart: comment };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { codePart: line.trimEnd(), commentPart: "" };
|
|
115
|
+
}
|
|
116
|
+
function isGroupOpening(code) {
|
|
117
|
+
// Check if code ends with { and starts with group keyword
|
|
118
|
+
const t = code.trim();
|
|
119
|
+
return /^\s*group\b.*\{\s*$/.test(t);
|
|
120
|
+
}
|
|
121
|
+
function formatCodePart(codePart, commentPart, indentLevel, indentStr) {
|
|
122
|
+
const indent = indentStr.repeat(indentLevel);
|
|
123
|
+
let formattedCode = formatStatement(codePart.trim());
|
|
124
|
+
if (commentPart) {
|
|
125
|
+
const normComment = normalizeComment(commentPart);
|
|
126
|
+
if (formattedCode === "") {
|
|
127
|
+
formattedCode = normComment;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
formattedCode = `${formattedCode} ${normComment}`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return indent + formattedCode;
|
|
134
|
+
}
|
|
135
|
+
function formatStatement(code) {
|
|
136
|
+
if (code === "")
|
|
137
|
+
return "";
|
|
138
|
+
if (code === "}")
|
|
139
|
+
return "}";
|
|
140
|
+
// Try in order: direction, group, meta, note, link, edge, node
|
|
141
|
+
// Direction: direction LR
|
|
142
|
+
let m = code.match(/^direction\s+(\S+)\s*$/);
|
|
143
|
+
if (m) {
|
|
144
|
+
return `direction ${m[1]}`;
|
|
145
|
+
}
|
|
146
|
+
// If direction without value but with incomplete? e.g., "direction"
|
|
147
|
+
if (/^direction\s*$/.test(code)) {
|
|
148
|
+
return "direction";
|
|
149
|
+
}
|
|
150
|
+
// Group header: group ID [type] "label" {
|
|
151
|
+
// Pattern: group <id> ([<type>])? ("<label>")? {
|
|
152
|
+
m = code.match(/^group\s+([A-Za-z_][A-Za-z0-9_-]*)\s*(?:\[\s*([A-Za-z_][A-Za-z0-9_-]*)\s*\])?\s*(?:"((?:[^"\\]|\\.)*)")?\s*\{\s*$/);
|
|
153
|
+
if (m) {
|
|
154
|
+
const id = m[1];
|
|
155
|
+
const type = m[2];
|
|
156
|
+
const label = m[3];
|
|
157
|
+
let out = `group ${id}`;
|
|
158
|
+
if (type)
|
|
159
|
+
out += ` [${type}]`;
|
|
160
|
+
if (label !== undefined)
|
|
161
|
+
out += ` "${escapeString(unescapeString(label))}"`;
|
|
162
|
+
out += " {";
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
// Group one-liner with closing brace on same line? "group X { }"
|
|
166
|
+
m = code.match(/^group\s+([A-Za-z_][A-Za-z0-9_-]*)\s*(?:\[\s*([A-Za-z_][A-Za-z0-9_-]*)\s*\])?\s*(?:"((?:[^"\\]|\\.)*)")?\s*\{\s*\}\s*$/);
|
|
167
|
+
if (m) {
|
|
168
|
+
const id = m[1];
|
|
169
|
+
const type = m[2];
|
|
170
|
+
const label = m[3];
|
|
171
|
+
let out = `group ${id}`;
|
|
172
|
+
if (type)
|
|
173
|
+
out += ` [${type}]`;
|
|
174
|
+
if (label !== undefined)
|
|
175
|
+
out += ` "${escapeString(unescapeString(label))}"`;
|
|
176
|
+
out += " {";
|
|
177
|
+
// For one-liner we could keep as two lines? But deterministic we output header line plus closing? Simplify to header + " }" handled as two tokens? We'll output as "group X { }"
|
|
178
|
+
// For now normalize to "group X { }" but single line format? Better keep as "group X {"
|
|
179
|
+
// We'll format as "group X {" and expect closing brace separately. But input has both on same line, we normalize to "group X { }"
|
|
180
|
+
return out + " }";
|
|
181
|
+
}
|
|
182
|
+
// Meta: meta key = "value"
|
|
183
|
+
m = code.match(/^meta\s+([A-Za-z_][A-Za-z0-9_-]*)\s*=\s*"((?:[^"\\]|\\.)*)"\s*$/);
|
|
184
|
+
if (m) {
|
|
185
|
+
const key = m[1];
|
|
186
|
+
const val = m[2] ?? "";
|
|
187
|
+
return `meta ${key} = "${escapeString(unescapeString(val))}"`;
|
|
188
|
+
}
|
|
189
|
+
// Note: note [target] "text"
|
|
190
|
+
m = code.match(/^note\s+(?:([A-Za-z_][A-Za-z0-9_-]*)\s+)?"((?:[^"\\]|\\.)*)"\s*$/);
|
|
191
|
+
if (m) {
|
|
192
|
+
const target = m[1];
|
|
193
|
+
const text = m[2] ?? "";
|
|
194
|
+
if (target)
|
|
195
|
+
return `note ${target} "${escapeString(unescapeString(text))}"`;
|
|
196
|
+
return `note "${escapeString(unescapeString(text))}"`;
|
|
197
|
+
}
|
|
198
|
+
// Link: link target "url"
|
|
199
|
+
m = code.match(/^link\s+([A-Za-z_][A-Za-z0-9_-]*)\s+"((?:[^"\\]|\\.)*)"\s*$/);
|
|
200
|
+
if (m) {
|
|
201
|
+
const target = m[1];
|
|
202
|
+
const url = m[2] ?? "";
|
|
203
|
+
return `link ${target} "${escapeString(unescapeString(url))}"`;
|
|
204
|
+
}
|
|
205
|
+
// Edge: IDENT (->|--) IDENT (: label)?
|
|
206
|
+
// Use regex that captures source, op, target, labelPart (including quotes or raw)
|
|
207
|
+
// First try to match edge with label
|
|
208
|
+
m = code.match(/^([A-Za-z_][A-Za-z0-9_-]*)\s*(->|--)\s*([A-Za-z_][A-Za-z0-9_-]*)\s*:\s*(.+?)\s*$/);
|
|
209
|
+
if (m) {
|
|
210
|
+
const src = m[1];
|
|
211
|
+
const op = m[2];
|
|
212
|
+
const tgt = m[3];
|
|
213
|
+
const labelRaw = m[4].trim();
|
|
214
|
+
// If label is quoted string, normalize escaping
|
|
215
|
+
if (labelRaw.startsWith('"') && labelRaw.endsWith('"') && labelRaw.length >= 2) {
|
|
216
|
+
const inner = labelRaw.slice(1, -1);
|
|
217
|
+
// Unescape then re-escape? Keep as is but ensure quoted
|
|
218
|
+
return `${src} ${op} ${tgt} : "${escapeString(unescapeString(inner))}"`;
|
|
219
|
+
}
|
|
220
|
+
return `${src} ${op} ${tgt} : ${labelRaw}`;
|
|
221
|
+
}
|
|
222
|
+
// Edge without label
|
|
223
|
+
m = code.match(/^([A-Za-z_][A-Za-z0-9_-]*)\s*(->|--)\s*([A-Za-z_][A-Za-z0-9_-]*)\s*$/);
|
|
224
|
+
if (m) {
|
|
225
|
+
const src = m[1];
|
|
226
|
+
const op = m[2];
|
|
227
|
+
const tgt = m[3];
|
|
228
|
+
return `${src} ${op} ${tgt}`;
|
|
229
|
+
}
|
|
230
|
+
// Edge with colon but empty label? Keep as is but normalized spacing: "A -> B :"
|
|
231
|
+
m = code.match(/^([A-Za-z_][A-Za-z0-9_-]*)\s*(->|--)\s*([A-Za-z_][A-Za-z0-9_-]*)\s*:\s*$/);
|
|
232
|
+
if (m) {
|
|
233
|
+
const src = m[1];
|
|
234
|
+
const op = m[2];
|
|
235
|
+
const tgt = m[3];
|
|
236
|
+
return `${src} ${op} ${tgt} :`;
|
|
237
|
+
}
|
|
238
|
+
// Node: IDENT [type] "label"
|
|
239
|
+
m = code.match(/^([A-Za-z_][A-Za-z0-9_-]*)\s*(?:\[\s*([A-Za-z_][A-Za-z0-9_-]*)\s*\])?\s*(?:"((?:[^"\\]|\\.)*)")?\s*$/);
|
|
240
|
+
if (m) {
|
|
241
|
+
const id = m[1];
|
|
242
|
+
const type = m[2];
|
|
243
|
+
const label = m[3];
|
|
244
|
+
let out = id;
|
|
245
|
+
if (type)
|
|
246
|
+
out += ` [${type}]`;
|
|
247
|
+
if (label !== undefined)
|
|
248
|
+
out += ` "${escapeString(unescapeString(label))}"`;
|
|
249
|
+
return out;
|
|
250
|
+
}
|
|
251
|
+
// Fallback: normalize whitespace for unknown statement but keep trimmed
|
|
252
|
+
// For invalid lines like "User ->" or "A--B" etc, still try to canonicalize spaces around ->/--
|
|
253
|
+
// Use simple replacement: ensure spaces around -> and -- and colon and brackets
|
|
254
|
+
let fallback = code.trim();
|
|
255
|
+
// Normalize arrow spacing: replace any surrounding spaces around -> or -- to single spaces
|
|
256
|
+
fallback = fallback.replace(/\s*(->|--)\s*/g, " $1 ");
|
|
257
|
+
fallback = fallback.replace(/\s*:\s*/g, " : ");
|
|
258
|
+
fallback = fallback.replace(/\s*\[\s*/g, " [");
|
|
259
|
+
fallback = fallback.replace(/\s*\]\s*/g, "]");
|
|
260
|
+
fallback = fallback.replace(/\s*=\s*/g, " = ");
|
|
261
|
+
fallback = fallback.replace(/\s+/g, " ").trim();
|
|
262
|
+
return fallback;
|
|
263
|
+
}
|
|
264
|
+
function escapeString(s) {
|
|
265
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
266
|
+
}
|
|
267
|
+
function unescapeString(s) {
|
|
268
|
+
return s.replace(/\\"/g, '"').replace(/\\\\/g, "\\").replace(/\\n/g, "\n").replace(/\\t/g, "\t");
|
|
269
|
+
}
|
|
270
|
+
/** Check if formatted output is idempotent — formatting twice yields same result */
|
|
271
|
+
export function isFormatted(source) {
|
|
272
|
+
return format(source) === source;
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=formatting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.js","sourceRoot":"","sources":["../../../src/language/formatting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HighlightToken } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Syntax highlighting information — independent from any editor.
|
|
4
|
+
* Operates on Floe language model (lexer tokens + ranges).
|
|
5
|
+
*/
|
|
6
|
+
export declare function getHighlightTokens(source: string): HighlightToken[];
|
|
7
|
+
/** For CodeMirror or other editors that expect classifications per line */
|
|
8
|
+
export declare function getHighlightingInfo(source: string): HighlightToken[];
|
|
9
|
+
//# sourceMappingURL=highlighting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlighting.d.ts","sourceRoot":"","sources":["../../../src/language/highlighting.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;GAGG;AAEH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CA8DnE;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CAEpE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { tokenize } from "../lexer.js";
|
|
2
|
+
/**
|
|
3
|
+
* Syntax highlighting information — independent from any editor.
|
|
4
|
+
* Operates on Floe language model (lexer tokens + ranges).
|
|
5
|
+
*/
|
|
6
|
+
export function getHighlightTokens(source) {
|
|
7
|
+
const tokens = tokenize(source);
|
|
8
|
+
const out = [];
|
|
9
|
+
for (const tok of tokens) {
|
|
10
|
+
if (tok.type === "NEWLINE" || tok.type === "EOF")
|
|
11
|
+
continue;
|
|
12
|
+
let scope;
|
|
13
|
+
switch (tok.type) {
|
|
14
|
+
case "DIRECTION_KW":
|
|
15
|
+
case "GROUP_KW":
|
|
16
|
+
case "META_KW":
|
|
17
|
+
case "NOTE_KW":
|
|
18
|
+
case "LINK_KW":
|
|
19
|
+
scope = "keyword";
|
|
20
|
+
break;
|
|
21
|
+
case "IDENT":
|
|
22
|
+
scope = "variableName";
|
|
23
|
+
break;
|
|
24
|
+
case "STRING":
|
|
25
|
+
scope = "string";
|
|
26
|
+
break;
|
|
27
|
+
case "COMMENT":
|
|
28
|
+
scope = "comment";
|
|
29
|
+
break;
|
|
30
|
+
case "ARROW":
|
|
31
|
+
case "DASHDASH":
|
|
32
|
+
scope = "operator";
|
|
33
|
+
break;
|
|
34
|
+
case "LBRACKET":
|
|
35
|
+
case "RBRACKET":
|
|
36
|
+
case "LBRACE":
|
|
37
|
+
case "RBRACE":
|
|
38
|
+
case "COLON":
|
|
39
|
+
case "EQUALS":
|
|
40
|
+
scope = "punctuation";
|
|
41
|
+
break;
|
|
42
|
+
case "UNKNOWN":
|
|
43
|
+
scope = "invalid";
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
scope = "plain";
|
|
47
|
+
}
|
|
48
|
+
out.push({
|
|
49
|
+
type: tok.type,
|
|
50
|
+
lexeme: tok.lexeme,
|
|
51
|
+
range: tok.range,
|
|
52
|
+
scope,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// Enhance: inside brackets [type] — type identifier should be typeName not variableName
|
|
56
|
+
// Find pattern LBRACKET IDENT RBRACKET and override scope
|
|
57
|
+
const enhanced = [...out];
|
|
58
|
+
for (let i = 0; i < enhanced.length; i++) {
|
|
59
|
+
const t = enhanced[i];
|
|
60
|
+
if (t.type === "LBRACKET") {
|
|
61
|
+
const next = enhanced[i + 1];
|
|
62
|
+
const next2 = enhanced[i + 2];
|
|
63
|
+
if (next && next.type === "IDENT" && next2 && next2.type === "RBRACKET") {
|
|
64
|
+
next.scope = "typeName";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return enhanced;
|
|
69
|
+
}
|
|
70
|
+
/** For CodeMirror or other editors that expect classifications per line */
|
|
71
|
+
export function getHighlightingInfo(source) {
|
|
72
|
+
return getHighlightTokens(source);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=highlighting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlighting.js","sourceRoot":"","sources":["../../../src/language/highlighting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC;;;GAGG;AAEH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK;YAAE,SAAS;QAC3D,IAAI,KAAa,CAAC;QAClB,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,cAAc,CAAC;YACpB,KAAK,UAAU,CAAC;YAChB,KAAK,SAAS,CAAC;YACf,KAAK,SAAS,CAAC;YACf,KAAK,SAAS;gBACZ,KAAK,GAAG,SAAS,CAAC;gBAClB,MAAM;YACR,KAAK,OAAO;gBACV,KAAK,GAAG,cAAc,CAAC;gBACvB,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,GAAG,QAAQ,CAAC;gBACjB,MAAM;YACR,KAAK,SAAS;gBACZ,KAAK,GAAG,SAAS,CAAC;gBAClB,MAAM;YACR,KAAK,OAAO,CAAC;YACb,KAAK,UAAU;gBACb,KAAK,GAAG,UAAU,CAAC;gBACnB,MAAM;YACR,KAAK,UAAU,CAAC;YAChB,KAAK,UAAU,CAAC;YAChB,KAAK,QAAQ,CAAC;YACd,KAAK,QAAQ,CAAC;YACd,KAAK,OAAO,CAAC;YACb,KAAK,QAAQ;gBACX,KAAK,GAAG,aAAa,CAAC;gBACtB,MAAM;YACR,KAAK,SAAS;gBACZ,KAAK,GAAG,SAAS,CAAC;gBAClB,MAAM;YACR;gBACE,KAAK,GAAG,OAAO,CAAC;QACpB,CAAC;QACD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IACD,wFAAwF;IACxF,0DAA0D;IAC1D,MAAM,QAAQ,GAAqB,CAAC,GAAG,GAAG,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QACvB,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9B,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACxE,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hover.d.ts","sourceRoot":"","sources":["../../../src/language/hover.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAmB5C;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAkJzE"}
|