@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.
Files changed (154) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/cli/check.d.ts +14 -0
  3. package/dist/src/cli/check.d.ts.map +1 -0
  4. package/dist/src/cli/check.js +88 -0
  5. package/dist/src/cli/check.js.map +1 -0
  6. package/dist/src/cli/format.d.ts +9 -0
  7. package/dist/src/cli/format.d.ts.map +1 -0
  8. package/dist/src/cli/format.js +114 -0
  9. package/dist/src/cli/format.js.map +1 -0
  10. package/dist/src/cli/main.d.ts +19 -0
  11. package/dist/src/cli/main.d.ts.map +1 -0
  12. package/dist/src/cli/main.js +207 -0
  13. package/dist/src/cli/main.js.map +1 -0
  14. package/dist/src/cli/render.d.ts +7 -0
  15. package/dist/src/cli/render.d.ts.map +1 -0
  16. package/dist/src/cli/render.js +90 -0
  17. package/dist/src/cli/render.js.map +1 -0
  18. package/dist/src/diagnostics.d.ts +32 -0
  19. package/dist/src/diagnostics.d.ts.map +1 -0
  20. package/dist/src/diagnostics.js +4 -0
  21. package/dist/src/diagnostics.js.map +1 -0
  22. package/dist/src/index.d.ts +40 -0
  23. package/dist/src/index.d.ts.map +1 -0
  24. package/dist/src/index.js +64 -0
  25. package/dist/src/index.js.map +1 -0
  26. package/dist/src/language/completion.d.ts +6 -0
  27. package/dist/src/language/completion.d.ts.map +1 -0
  28. package/dist/src/language/completion.js +363 -0
  29. package/dist/src/language/completion.js.map +1 -0
  30. package/dist/src/language/definitions.d.ts +9 -0
  31. package/dist/src/language/definitions.d.ts.map +1 -0
  32. package/dist/src/language/definitions.js +70 -0
  33. package/dist/src/language/definitions.js.map +1 -0
  34. package/dist/src/language/diagnosticsService.d.ts +14 -0
  35. package/dist/src/language/diagnosticsService.d.ts.map +1 -0
  36. package/dist/src/language/diagnosticsService.js +37 -0
  37. package/dist/src/language/diagnosticsService.js.map +1 -0
  38. package/dist/src/language/folding.d.ts +8 -0
  39. package/dist/src/language/folding.d.ts.map +1 -0
  40. package/dist/src/language/folding.js +58 -0
  41. package/dist/src/language/folding.js.map +1 -0
  42. package/dist/src/language/formatting.d.ts +5 -0
  43. package/dist/src/language/formatting.d.ts.map +1 -0
  44. package/dist/src/language/formatting.js +274 -0
  45. package/dist/src/language/formatting.js.map +1 -0
  46. package/dist/src/language/highlighting.d.ts +9 -0
  47. package/dist/src/language/highlighting.d.ts.map +1 -0
  48. package/dist/src/language/highlighting.js +74 -0
  49. package/dist/src/language/highlighting.js.map +1 -0
  50. package/dist/src/language/hover.d.ts +6 -0
  51. package/dist/src/language/hover.d.ts.map +1 -0
  52. package/dist/src/language/hover.js +197 -0
  53. package/dist/src/language/hover.js.map +1 -0
  54. package/dist/src/language/indentation.d.ts +15 -0
  55. package/dist/src/language/indentation.d.ts.map +1 -0
  56. package/dist/src/language/indentation.js +97 -0
  57. package/dist/src/language/indentation.js.map +1 -0
  58. package/dist/src/language/index.d.ts +54 -0
  59. package/dist/src/language/index.d.ts.map +1 -0
  60. package/dist/src/language/index.js +85 -0
  61. package/dist/src/language/index.js.map +1 -0
  62. package/dist/src/language/references.d.ts +12 -0
  63. package/dist/src/language/references.d.ts.map +1 -0
  64. package/dist/src/language/references.js +35 -0
  65. package/dist/src/language/references.js.map +1 -0
  66. package/dist/src/language/rename.d.ts +18 -0
  67. package/dist/src/language/rename.d.ts.map +1 -0
  68. package/dist/src/language/rename.js +53 -0
  69. package/dist/src/language/rename.js.map +1 -0
  70. package/dist/src/language/semanticModel.d.ts +21 -0
  71. package/dist/src/language/semanticModel.d.ts.map +1 -0
  72. package/dist/src/language/semanticModel.js +43 -0
  73. package/dist/src/language/semanticModel.js.map +1 -0
  74. package/dist/src/language/symbols.d.ts +9 -0
  75. package/dist/src/language/symbols.d.ts.map +1 -0
  76. package/dist/src/language/symbols.js +160 -0
  77. package/dist/src/language/symbols.js.map +1 -0
  78. package/dist/src/language/types.d.ts +49 -0
  79. package/dist/src/language/types.d.ts.map +1 -0
  80. package/dist/src/language/types.js +2 -0
  81. package/dist/src/language/types.js.map +1 -0
  82. package/dist/src/language/utils.d.ts +24 -0
  83. package/dist/src/language/utils.d.ts.map +1 -0
  84. package/dist/src/language/utils.js +154 -0
  85. package/dist/src/language/utils.js.map +1 -0
  86. package/dist/src/layout/dagre.d.ts +13 -0
  87. package/dist/src/layout/dagre.d.ts.map +1 -0
  88. package/dist/src/layout/dagre.js +229 -0
  89. package/dist/src/layout/dagre.js.map +1 -0
  90. package/dist/src/layout/index.d.ts +15 -0
  91. package/dist/src/layout/index.d.ts.map +1 -0
  92. package/dist/src/layout/index.js +22 -0
  93. package/dist/src/layout/index.js.map +1 -0
  94. package/dist/src/layout/simple.d.ts +20 -0
  95. package/dist/src/layout/simple.d.ts.map +1 -0
  96. package/dist/src/layout/simple.js +674 -0
  97. package/dist/src/layout/simple.js.map +1 -0
  98. package/dist/src/layout/types.d.ts +65 -0
  99. package/dist/src/layout/types.d.ts.map +1 -0
  100. package/dist/src/layout/types.js +2 -0
  101. package/dist/src/layout/types.js.map +1 -0
  102. package/dist/src/lexer.d.ts +25 -0
  103. package/dist/src/lexer.d.ts.map +1 -0
  104. package/dist/src/lexer.js +280 -0
  105. package/dist/src/lexer.js.map +1 -0
  106. package/dist/src/lsp/documents.d.ts +24 -0
  107. package/dist/src/lsp/documents.d.ts.map +1 -0
  108. package/dist/src/lsp/documents.js +97 -0
  109. package/dist/src/lsp/documents.js.map +1 -0
  110. package/dist/src/lsp/server.d.ts +70 -0
  111. package/dist/src/lsp/server.d.ts.map +1 -0
  112. package/dist/src/lsp/server.js +623 -0
  113. package/dist/src/lsp/server.js.map +1 -0
  114. package/dist/src/lsp/utils.d.ts +47 -0
  115. package/dist/src/lsp/utils.d.ts.map +1 -0
  116. package/dist/src/lsp/utils.js +142 -0
  117. package/dist/src/lsp/utils.js.map +1 -0
  118. package/dist/src/parser.d.ts +106 -0
  119. package/dist/src/parser.d.ts.map +1 -0
  120. package/dist/src/parser.js +1018 -0
  121. package/dist/src/parser.js.map +1 -0
  122. package/dist/src/pipeline.d.ts +51 -0
  123. package/dist/src/pipeline.d.ts.map +1 -0
  124. package/dist/src/pipeline.js +65 -0
  125. package/dist/src/pipeline.js.map +1 -0
  126. package/dist/src/range.d.ts +24 -0
  127. package/dist/src/range.d.ts.map +1 -0
  128. package/dist/src/range.js +20 -0
  129. package/dist/src/range.js.map +1 -0
  130. package/dist/src/render/index.d.ts +3 -0
  131. package/dist/src/render/index.d.ts.map +1 -0
  132. package/dist/src/render/index.js +3 -0
  133. package/dist/src/render/index.js.map +1 -0
  134. package/dist/src/render/shapes.d.ts +20 -0
  135. package/dist/src/render/shapes.d.ts.map +1 -0
  136. package/dist/src/render/shapes.js +110 -0
  137. package/dist/src/render/shapes.js.map +1 -0
  138. package/dist/src/render/svg.d.ts +19 -0
  139. package/dist/src/render/svg.d.ts.map +1 -0
  140. package/dist/src/render/svg.js +227 -0
  141. package/dist/src/render/svg.js.map +1 -0
  142. package/dist/src/security/url.d.ts +7 -0
  143. package/dist/src/security/url.d.ts.map +1 -0
  144. package/dist/src/security/url.js +27 -0
  145. package/dist/src/security/url.js.map +1 -0
  146. package/dist/src/types.d.ts +111 -0
  147. package/dist/src/types.d.ts.map +1 -0
  148. package/dist/src/types.js +16 -0
  149. package/dist/src/types.js.map +1 -0
  150. package/dist/src/validator.d.ts +47 -0
  151. package/dist/src/validator.d.ts.map +1 -0
  152. package/dist/src/validator.js +235 -0
  153. package/dist/src/validator.js.map +1 -0
  154. 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,6 @@
1
+ import type { HoverInfo } from "./types.js";
2
+ /**
3
+ * Hover — may expose node ID, type, label, incoming/outgoing edges, metadata
4
+ */
5
+ export declare function getHover(source: string, offset: number): HoverInfo | null;
6
+ //# sourceMappingURL=hover.d.ts.map
@@ -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"}