@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zulfazli (Fazelllyyy) <zulfazlilsm@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,14 @@
1
+ import type { Diagnostic } from "../diagnostics.js";
2
+ export interface CheckOptions {
3
+ json?: boolean;
4
+ quiet?: boolean;
5
+ }
6
+ export interface CheckResult {
7
+ file: string;
8
+ diagnostics: Diagnostic[];
9
+ hasErrors: boolean;
10
+ }
11
+ export declare function formatDiagnostic(file: string, d: Diagnostic): string;
12
+ export declare function checkFile(filePath: string, opts?: CheckOptions): CheckResult;
13
+ export declare function runCheck(files: string[], opts?: CheckOptions): number;
14
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,GAAG,MAAM,CAGpE;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,WAAW,CAWhF;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,YAAiB,GAAG,MAAM,CA6DzE"}
@@ -0,0 +1,88 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { parseFloe } from "../index.js";
4
+ export function formatDiagnostic(file, d) {
5
+ const { line, column } = d.range.start;
6
+ return `${file}:${line}:${column} ${d.code} ${d.severity} ${d.message}`;
7
+ }
8
+ export function checkFile(filePath, opts = {}) {
9
+ let source;
10
+ try {
11
+ source = fs.readFileSync(filePath, "utf-8");
12
+ }
13
+ catch (e) {
14
+ const msg = e instanceof Error ? e.message : String(e);
15
+ throw new Error(`Cannot read file '${filePath}': ${msg}`);
16
+ }
17
+ const { diagnostics } = parseFloe(source);
18
+ const hasErrors = diagnostics.some((d) => d.severity === "error");
19
+ return { file: filePath, diagnostics, hasErrors };
20
+ }
21
+ export function runCheck(files, opts = {}) {
22
+ if (files.length === 0) {
23
+ console.error("floe check: no input files");
24
+ console.error("Usage: floe check <file.floe> [--json]");
25
+ return 2;
26
+ }
27
+ let overallHasErrors = false;
28
+ let overallOutput = [];
29
+ for (const f of files) {
30
+ const resolved = path.resolve(f);
31
+ if (!fs.existsSync(resolved)) {
32
+ console.error(`floe check: file not found: ${f}`);
33
+ return 2;
34
+ }
35
+ try {
36
+ const result = checkFile(resolved, opts);
37
+ overallOutput.push(result);
38
+ if (result.hasErrors)
39
+ overallHasErrors = true;
40
+ }
41
+ catch (e) {
42
+ const msg = e instanceof Error ? e.message : String(e);
43
+ console.error(msg);
44
+ return 2;
45
+ }
46
+ }
47
+ if (opts.json) {
48
+ const jsonOut = overallOutput.map((r) => ({
49
+ file: path.relative(process.cwd(), r.file),
50
+ diagnostics: r.diagnostics.map((d) => ({
51
+ code: d.code,
52
+ severity: d.severity,
53
+ message: d.message,
54
+ range: d.range,
55
+ })),
56
+ hasErrors: r.hasErrors,
57
+ }));
58
+ console.log(JSON.stringify(jsonOut, null, 2));
59
+ }
60
+ else {
61
+ for (const r of overallOutput) {
62
+ const rel = path.relative(process.cwd(), r.file);
63
+ if (r.diagnostics.length === 0) {
64
+ if (!opts.quiet)
65
+ console.log(`✔ ${rel}: OK`);
66
+ }
67
+ else {
68
+ const errCount = r.diagnostics.filter((d) => d.severity === "error").length;
69
+ const warnCount = r.diagnostics.filter((d) => d.severity === "warning").length;
70
+ if (!opts.quiet) {
71
+ if (errCount > 0)
72
+ console.error(`✖ ${rel}: ${errCount} error(s)${warnCount ? `, ${warnCount} warning(s)` : ""}`);
73
+ else
74
+ console.log(`✔ ${rel}: ${warnCount} warning(s)`);
75
+ }
76
+ for (const d of r.diagnostics) {
77
+ const line = formatDiagnostic(rel, d);
78
+ if (d.severity === "error")
79
+ console.error(line);
80
+ else
81
+ console.log(line);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return overallHasErrors ? 1 : 0;
87
+ }
88
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/cli/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface FormatOptions {
2
+ write?: boolean;
3
+ check?: boolean;
4
+ stdout?: boolean;
5
+ json?: boolean;
6
+ }
7
+ export declare function runFormat(files: string[], opts?: FormatOptions): number;
8
+ export declare function checkIsFormatted(source: string): boolean;
9
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/cli/format.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAyG3E;AAGD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD"}
@@ -0,0 +1,114 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { format, isFormatted } from "../language/formatting.js";
4
+ import { parseFloe } from "../index.js";
5
+ export function runFormat(files, opts = {}) {
6
+ if (files.length === 0) {
7
+ console.error("floe format: no input files");
8
+ console.error("Usage: floe format <file.floe> [--write] [--check]");
9
+ return 2;
10
+ }
11
+ // Mutually exclusive: --write and --check should not both be set? Allow but prioritize check?
12
+ if (opts.write && opts.check) {
13
+ console.error("floe format: --write and --check are mutually exclusive");
14
+ return 2;
15
+ }
16
+ let hasUnformatted = false;
17
+ let hasErrors = false;
18
+ for (const f of files) {
19
+ const resolved = path.resolve(f);
20
+ if (!fs.existsSync(resolved)) {
21
+ console.error(`floe format: file not found: ${f}`);
22
+ return 2;
23
+ }
24
+ let source;
25
+ try {
26
+ source = fs.readFileSync(resolved, "utf-8");
27
+ }
28
+ catch (e) {
29
+ const msg = e instanceof Error ? e.message : String(e);
30
+ console.error(`Cannot read file '${f}': ${msg}`);
31
+ return 2;
32
+ }
33
+ // Validate that format never throws on malformed input (security: no crash)
34
+ let formatted;
35
+ try {
36
+ formatted = format(source);
37
+ }
38
+ catch (e) {
39
+ const msg = e instanceof Error ? e.message : String(e);
40
+ console.error(`floe format: internal error formatting '${f}': ${msg}`);
41
+ return 1;
42
+ }
43
+ const needsFormat = source !== formatted;
44
+ if (opts.check) {
45
+ if (needsFormat) {
46
+ hasUnformatted = true;
47
+ const rel = path.relative(process.cwd(), resolved);
48
+ if (opts.json) {
49
+ // json output for check mode
50
+ }
51
+ else {
52
+ console.error(`✖ ${rel}: not formatted`);
53
+ }
54
+ }
55
+ else {
56
+ if (!opts.json) {
57
+ const rel = path.relative(process.cwd(), resolved);
58
+ // quiet on success? Only print if not json?
59
+ // For CI, we want quiet success. So no output unless not formatted.
60
+ }
61
+ }
62
+ continue;
63
+ }
64
+ if (opts.write) {
65
+ if (needsFormat) {
66
+ try {
67
+ fs.writeFileSync(resolved, formatted, "utf-8");
68
+ const rel = path.relative(process.cwd(), resolved);
69
+ if (!opts.json)
70
+ console.log(`formatted ${rel}`);
71
+ }
72
+ catch (e) {
73
+ const msg = e instanceof Error ? e.message : String(e);
74
+ console.error(`Cannot write file '${f}': ${msg}`);
75
+ return 2;
76
+ }
77
+ }
78
+ else {
79
+ // Already formatted, no write
80
+ if (!opts.json) {
81
+ // no output? Could be verbose
82
+ }
83
+ }
84
+ continue;
85
+ }
86
+ // Default: stdout (scriptable). If multiple files, separate with header?
87
+ if (files.length === 1) {
88
+ // Single file -> raw formatted to stdout
89
+ process.stdout.write(formatted);
90
+ }
91
+ else {
92
+ const rel = path.relative(process.cwd(), resolved);
93
+ // For multiple files to stdout, add filename header for scriptability? But spec says scriptable, so we should output each?
94
+ // We'll output with header comment per file for clarity, but that would break piping.
95
+ // Instead, if multiple files and stdout mode, we print each file's formatted content separated by newline and header to stderr
96
+ console.error(`== ${rel} ==`);
97
+ process.stdout.write(formatted);
98
+ if (!formatted.endsWith("\n"))
99
+ process.stdout.write("\n");
100
+ }
101
+ }
102
+ if (opts.check) {
103
+ return hasUnformatted ? 1 : 0;
104
+ }
105
+ // For write/stdout, exit 0 unless there were read errors (already returned)
106
+ // Should we exit 1 if original file had parse errors? Formatting should still succeed but maybe warn.
107
+ // We keep exit 0 for formatting success, to allow CI to use --check for validation.
108
+ return 0;
109
+ }
110
+ // For testing: check if file is formatted
111
+ export function checkIsFormatted(source) {
112
+ return isFormatted(source);
113
+ }
114
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/cli/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Floe CLI
4
+ * Commands:
5
+ * floe check <file.floe> [--json] [--quiet]
6
+ * floe format <file.floe> [--write] [--check]
7
+ * floe render <file.floe> [-o output.svg]
8
+ * floe lsp [--stdio] (starts LSP server)
9
+ *
10
+ * Keep CLI behavior scriptable for CI with appropriate exit codes:
11
+ * 0 success
12
+ * 1 validation / check failure
13
+ * 2 usage / file not found error
14
+ *
15
+ * Treat .floe files as untrusted: never eval, ensure SVG cannot execute code.
16
+ * This CLI never uses eval and delegates to safe core.
17
+ */
18
+ export {};
19
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Floe CLI
4
+ * Commands:
5
+ * floe check <file.floe> [--json] [--quiet]
6
+ * floe format <file.floe> [--write] [--check]
7
+ * floe render <file.floe> [-o output.svg]
8
+ * floe lsp [--stdio] (starts LSP server)
9
+ *
10
+ * Keep CLI behavior scriptable for CI with appropriate exit codes:
11
+ * 0 success
12
+ * 1 validation / check failure
13
+ * 2 usage / file not found error
14
+ *
15
+ * Treat .floe files as untrusted: never eval, ensure SVG cannot execute code.
16
+ * This CLI never uses eval and delegates to safe core.
17
+ */
18
+ import * as fs from "node:fs";
19
+ import * as path from "node:path";
20
+ import { runCheck } from "./check.js";
21
+ import { runFormat } from "./format.js";
22
+ import { runRender } from "./render.js";
23
+ const VERSION = "1.0.0";
24
+ function printHelp() {
25
+ console.log(`Floe ${VERSION} — diagram DSL
26
+
27
+ Usage:
28
+ floe <command> [options] <file...>
29
+
30
+ Commands:
31
+ check Validate a .floe file and print diagnostics
32
+ format Format file using canonical formatter
33
+ render Produce SVG output
34
+ lsp Start Language Server (stdio)
35
+ help Show this help
36
+
37
+ Options:
38
+ -h, --help Show help
39
+ -v, --version Show version
40
+
41
+ Check:
42
+ floe check diagram.floe [--json] [--quiet]
43
+ --json Output diagnostics as JSON
44
+ --quiet Suppress OK messages
45
+
46
+ Format:
47
+ floe format diagram.floe [--write] [--check]
48
+ --write Overwrite file in place
49
+ --check Exit 1 if file not formatted (for CI)
50
+ (default: print formatted content to stdout)
51
+
52
+ Render:
53
+ floe render diagram.floe [-o output.svg]
54
+ -o, --output <file> Write SVG to file (default: stdout)
55
+
56
+ LSP:
57
+ floe lsp [--stdio]
58
+ Starts LSP server over stdio (for editor integration)
59
+
60
+ Exit codes:
61
+ 0 success
62
+ 1 validation error / not formatted / render had errors
63
+ 2 usage or file error
64
+
65
+ Examples:
66
+ floe check diagram.floe
67
+ floe format diagram.floe --write
68
+ floe render diagram.floe -o diagram.svg
69
+ floe lsp
70
+
71
+ Docs: SPEC.md
72
+ `);
73
+ }
74
+ function printVersion() {
75
+ console.log(VERSION);
76
+ }
77
+ function parseArgs(argv) {
78
+ const args = argv.slice(2);
79
+ if (args.length === 0)
80
+ return { files: [], opts: {} };
81
+ // Handle global flags
82
+ if (args[0] === "--help" || args[0] === "-h" || args[0] === "help") {
83
+ return { command: "help", files: [], opts: {} };
84
+ }
85
+ if (args[0] === "--version" || args[0] === "-v" || args[0] === "version") {
86
+ return { command: "version", files: [], opts: {} };
87
+ }
88
+ const command = args[0];
89
+ const rest = args.slice(1);
90
+ const files = [];
91
+ const opts = {};
92
+ let i = 0;
93
+ while (i < rest.length) {
94
+ const a = rest[i];
95
+ if (a === "--json") {
96
+ opts.json = true;
97
+ i++;
98
+ }
99
+ else if (a === "--quiet" || a === "-q") {
100
+ opts.quiet = true;
101
+ i++;
102
+ }
103
+ else if (a === "--write" || a === "-w") {
104
+ opts.write = true;
105
+ i++;
106
+ }
107
+ else if (a === "--check" || a === "-c") {
108
+ opts.check = true;
109
+ i++;
110
+ }
111
+ else if (a === "--stdio") {
112
+ opts.stdio = true;
113
+ i++;
114
+ }
115
+ else if (a === "-o" || a === "--output") {
116
+ const next = rest[i + 1];
117
+ if (!next) {
118
+ console.error(`floe ${command}: missing value for ${a}`);
119
+ process.exit(2);
120
+ }
121
+ opts.output = next;
122
+ i += 2;
123
+ }
124
+ else if (a === "--help" || a === "-h") {
125
+ opts.help = true;
126
+ i++;
127
+ }
128
+ else if (a === "--version" || a === "-v") {
129
+ opts.version = true;
130
+ i++;
131
+ }
132
+ else if (a.startsWith("-")) {
133
+ console.error(`floe ${command}: unknown option ${a}`);
134
+ console.error(`Run 'floe ${command} --help' for usage.`);
135
+ process.exit(2);
136
+ }
137
+ else {
138
+ files.push(a);
139
+ i++;
140
+ }
141
+ }
142
+ return { command, files, opts };
143
+ }
144
+ async function main() {
145
+ const { command, files, opts } = parseArgs(process.argv);
146
+ if (!command) {
147
+ printHelp();
148
+ process.exit(2);
149
+ }
150
+ if (command === "help") {
151
+ printHelp();
152
+ process.exit(0);
153
+ }
154
+ if (command === "version") {
155
+ printVersion();
156
+ process.exit(0);
157
+ }
158
+ // Allow help per command
159
+ if (opts.help) {
160
+ printHelp();
161
+ process.exit(0);
162
+ }
163
+ if (opts.version) {
164
+ printVersion();
165
+ process.exit(0);
166
+ }
167
+ let exitCode = 0;
168
+ switch (command) {
169
+ case "check": {
170
+ exitCode = runCheck(files, { json: !!opts.json, quiet: !!opts.quiet });
171
+ break;
172
+ }
173
+ case "format": {
174
+ exitCode = runFormat(files, { write: !!opts.write, check: !!opts.check, json: !!opts.json });
175
+ break;
176
+ }
177
+ case "render": {
178
+ exitCode = runRender(files, { output: opts.output, json: !!opts.json });
179
+ break;
180
+ }
181
+ case "lsp":
182
+ case "lsp-server": {
183
+ // Start LSP server
184
+ // Dynamic import to avoid loading LSP code unless needed (keeps core Node/browser separation)
185
+ const { startLspServer } = await import("../lsp/server.js");
186
+ await startLspServer({ stdio: true });
187
+ // startLspServer runs indefinitely until shutdown
188
+ return;
189
+ }
190
+ default: {
191
+ console.error(`floe: unknown command '${command}'`);
192
+ console.error("Run 'floe --help' for usage.");
193
+ process.exit(2);
194
+ }
195
+ }
196
+ process.exit(exitCode);
197
+ }
198
+ // Ensure unhandled errors are reported with exit 1 (no crash with empty exit)
199
+ main().catch((e) => {
200
+ const msg = e instanceof Error ? e.message : String(e);
201
+ console.error(`floe: internal error: ${msg}`);
202
+ // Do not print stack for user-facing errors unless debug? Keep simple
203
+ if (process.env.FLOE_DEBUG)
204
+ console.error(e instanceof Error ? e.stack : "");
205
+ process.exit(1);
206
+ });
207
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface RenderOptions {
2
+ output?: string;
3
+ stdout?: boolean;
4
+ json?: boolean;
5
+ }
6
+ export declare function runRender(files: string[], opts?: RenderOptions): number;
7
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/cli/render.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAmF3E"}
@@ -0,0 +1,90 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { parseFloe } from "../index.js";
4
+ import { renderFloe } from "../pipeline.js";
5
+ export function runRender(files, opts = {}) {
6
+ if (files.length === 0) {
7
+ console.error("floe render: no input files");
8
+ console.error("Usage: floe render <file.floe> [-o <output.svg>]");
9
+ return 2;
10
+ }
11
+ if (files.length > 1 && opts.output) {
12
+ console.error("floe render: -o/--output can only be used with a single input file");
13
+ return 2;
14
+ }
15
+ let hadErrors = false;
16
+ for (const f of files) {
17
+ const resolved = path.resolve(f);
18
+ if (!fs.existsSync(resolved)) {
19
+ console.error(`floe render: file not found: ${f}`);
20
+ return 2;
21
+ }
22
+ let source;
23
+ try {
24
+ source = fs.readFileSync(resolved, "utf-8");
25
+ }
26
+ catch (e) {
27
+ const msg = e instanceof Error ? e.message : String(e);
28
+ console.error(`Cannot read file '${f}': ${msg}`);
29
+ return 2;
30
+ }
31
+ // Parse to check diagnostics but still render best-effort (per spec: never crash)
32
+ let svg;
33
+ let hasParseErrors = false;
34
+ try {
35
+ const parseResult = parseFloe(source);
36
+ hasParseErrors = parseResult.diagnostics.some((d) => d.severity === "error");
37
+ if (hasParseErrors)
38
+ hadErrors = true;
39
+ // Render via pipeline (deterministic, never throws on malformed input)
40
+ const result = renderFloe(source);
41
+ svg = result.svg;
42
+ }
43
+ catch (e) {
44
+ const msg = e instanceof Error ? e.message : String(e);
45
+ console.error(`floe render: failed to render '${f}': ${msg}`);
46
+ return 1;
47
+ }
48
+ // Security: ensure svg is properly escaped (render already does) and not containing executable vectors
49
+ // We do not inject any untrusted content as raw; svg is derived via escaped paths.
50
+ if (opts.output) {
51
+ const outPath = path.resolve(opts.output);
52
+ try {
53
+ // Ensure directory exists
54
+ const dir = path.dirname(outPath);
55
+ if (!fs.existsSync(dir))
56
+ fs.mkdirSync(dir, { recursive: true });
57
+ fs.writeFileSync(outPath, svg, "utf-8");
58
+ const rel = path.relative(process.cwd(), outPath);
59
+ if (!opts.json)
60
+ console.log(`rendered ${path.relative(process.cwd(), resolved)} -> ${rel}`);
61
+ }
62
+ catch (e) {
63
+ const msg = e instanceof Error ? e.message : String(e);
64
+ console.error(`Cannot write output '${opts.output}': ${msg}`);
65
+ return 2;
66
+ }
67
+ }
68
+ else {
69
+ // stdout (scriptable)
70
+ // If json mode? Not needed but we support emitting svg via stdout only.
71
+ // Print svg to stdout; warnings to stderr
72
+ if (hasParseErrors && !opts.json) {
73
+ const rel = path.relative(process.cwd(), resolved);
74
+ console.error(`warning: ${rel} has parse errors, rendered best-effort SVG`);
75
+ }
76
+ process.stdout.write(svg);
77
+ if (!svg.endsWith("\n"))
78
+ process.stdout.write("\n");
79
+ }
80
+ }
81
+ // For CI: exit 1 if any file had parse errors? Or 0 still? Spec says appropriate exit codes and scriptable.
82
+ // We will exit 1 if any input had errors, to allow CI to fail on invalid diagrams, but still produce SVG.
83
+ // This is useful: `floe render` can be used in CI to validate rendering.
84
+ // If caller wants to ignore errors, they can check SVG existence anyway.
85
+ // We make decision: if any file had errors, exit 1, else 0. But produce SVG regardless.
86
+ // For scriptable use, they can do `floe render good.floe || echo failed`
87
+ // Document this behavior.
88
+ return hadErrors ? 1 : 0;
89
+ }
90
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/cli/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Range } from "./range.js";
2
+ /**
3
+ * Diagnostic severity
4
+ */
5
+ export type Severity = "error" | "warning" | "info";
6
+ /**
7
+ * Stable diagnostic codes
8
+ *
9
+ * E001 - invalid direction
10
+ * E002 - invalid identifier
11
+ * E003 - duplicate node declaration
12
+ * E004 - duplicate direction declaration
13
+ * E005 - malformed statement / unexpected token
14
+ * E006 - missing / incomplete statement
15
+ * E007 - invalid character
16
+ * E008 - invalid node type
17
+ * E009 - missing edge target
18
+ * E010 - empty label
19
+ * E011 - duplicate group declaration
20
+ * E012 - unclosed group / missing brace
21
+ * E013 - invalid metadata declaration
22
+ * E014 - invalid annotation or link (unknown target, empty text)
23
+ */
24
+ export type DiagnosticCode = "E001" | "E002" | "E003" | "E004" | "E005" | "E006" | "E007" | "E008" | "E009" | "E010" | "E011" | "E012" | "E013" | "E014";
25
+ export interface Diagnostic {
26
+ severity: Severity;
27
+ code: DiagnosticCode;
28
+ message: string;
29
+ range: Range;
30
+ }
31
+ export declare function diag(severity: Severity, code: DiagnosticCode, message: string, range: Range): Diagnostic;
32
+ //# sourceMappingURL=diagnostics.d.ts.map