flowscript-core 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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +386 -0
  3. package/bin/flowscript +12 -0
  4. package/dist/cli.d.ts +12 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +463 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/errors/indentation-error.d.ts +11 -0
  9. package/dist/errors/indentation-error.d.ts.map +1 -0
  10. package/dist/errors/indentation-error.js +22 -0
  11. package/dist/errors/indentation-error.js.map +1 -0
  12. package/dist/grammar.ohm +132 -0
  13. package/dist/hash.d.ts +21 -0
  14. package/dist/hash.d.ts.map +1 -0
  15. package/dist/hash.js +82 -0
  16. package/dist/hash.js.map +1 -0
  17. package/dist/indentation-scanner.d.ts +81 -0
  18. package/dist/indentation-scanner.d.ts.map +1 -0
  19. package/dist/indentation-scanner.js +290 -0
  20. package/dist/indentation-scanner.js.map +1 -0
  21. package/dist/index.d.ts +15 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +49 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/linter.d.ts +71 -0
  26. package/dist/linter.d.ts.map +1 -0
  27. package/dist/linter.js +122 -0
  28. package/dist/linter.js.map +1 -0
  29. package/dist/memory.d.ts +506 -0
  30. package/dist/memory.d.ts.map +1 -0
  31. package/dist/memory.js +1802 -0
  32. package/dist/memory.js.map +1 -0
  33. package/dist/parser.d.ts +53 -0
  34. package/dist/parser.d.ts.map +1 -0
  35. package/dist/parser.js +1184 -0
  36. package/dist/parser.js.map +1 -0
  37. package/dist/query-engine.d.ts +320 -0
  38. package/dist/query-engine.d.ts.map +1 -0
  39. package/dist/query-engine.js +884 -0
  40. package/dist/query-engine.js.map +1 -0
  41. package/dist/rules/alternatives-without-decision.d.ts +24 -0
  42. package/dist/rules/alternatives-without-decision.d.ts.map +1 -0
  43. package/dist/rules/alternatives-without-decision.js +58 -0
  44. package/dist/rules/alternatives-without-decision.js.map +1 -0
  45. package/dist/rules/causal-cycles.d.ts +23 -0
  46. package/dist/rules/causal-cycles.d.ts.map +1 -0
  47. package/dist/rules/causal-cycles.js +83 -0
  48. package/dist/rules/causal-cycles.js.map +1 -0
  49. package/dist/rules/deep-nesting.d.ts +23 -0
  50. package/dist/rules/deep-nesting.d.ts.map +1 -0
  51. package/dist/rules/deep-nesting.js +55 -0
  52. package/dist/rules/deep-nesting.js.map +1 -0
  53. package/dist/rules/index.d.ts +15 -0
  54. package/dist/rules/index.d.ts.map +1 -0
  55. package/dist/rules/index.js +29 -0
  56. package/dist/rules/index.js.map +1 -0
  57. package/dist/rules/invalid-syntax.d.ts +22 -0
  58. package/dist/rules/invalid-syntax.d.ts.map +1 -0
  59. package/dist/rules/invalid-syntax.js +52 -0
  60. package/dist/rules/invalid-syntax.js.map +1 -0
  61. package/dist/rules/long-causal-chains.d.ts +25 -0
  62. package/dist/rules/long-causal-chains.d.ts.map +1 -0
  63. package/dist/rules/long-causal-chains.js +75 -0
  64. package/dist/rules/long-causal-chains.js.map +1 -0
  65. package/dist/rules/missing-recommended-fields.d.ts +21 -0
  66. package/dist/rules/missing-recommended-fields.d.ts.map +1 -0
  67. package/dist/rules/missing-recommended-fields.js +45 -0
  68. package/dist/rules/missing-recommended-fields.js.map +1 -0
  69. package/dist/rules/missing-required-fields.d.ts +22 -0
  70. package/dist/rules/missing-required-fields.d.ts.map +1 -0
  71. package/dist/rules/missing-required-fields.js +46 -0
  72. package/dist/rules/missing-required-fields.js.map +1 -0
  73. package/dist/rules/orphaned-nodes.d.ts +22 -0
  74. package/dist/rules/orphaned-nodes.d.ts.map +1 -0
  75. package/dist/rules/orphaned-nodes.js +76 -0
  76. package/dist/rules/orphaned-nodes.js.map +1 -0
  77. package/dist/rules/unlabeled-tension.d.ts +20 -0
  78. package/dist/rules/unlabeled-tension.d.ts.map +1 -0
  79. package/dist/rules/unlabeled-tension.js +37 -0
  80. package/dist/rules/unlabeled-tension.js.map +1 -0
  81. package/dist/serializer.d.ts +40 -0
  82. package/dist/serializer.d.ts.map +1 -0
  83. package/dist/serializer.js +368 -0
  84. package/dist/serializer.js.map +1 -0
  85. package/dist/tokenizer.d.ts +26 -0
  86. package/dist/tokenizer.d.ts.map +1 -0
  87. package/dist/tokenizer.js +213 -0
  88. package/dist/tokenizer.js.map +1 -0
  89. package/dist/types.d.ts +96 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +50 -0
  92. package/dist/types.js.map +1 -0
  93. package/dist/validate.d.ts +18 -0
  94. package/dist/validate.d.ts.map +1 -0
  95. package/dist/validate.js +68 -0
  96. package/dist/validate.js.map +1 -0
  97. package/package.json +69 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAa7C"}
package/dist/hash.js ADDED
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /**
3
+ * FlowScript Content Hashing
4
+ *
5
+ * Generates deterministic SHA-256 content hashes for nodes, relationships, and states.
6
+ * Enables automatic deduplication: same semantic content = same ID.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.hashContent = hashContent;
43
+ const crypto = __importStar(require("crypto"));
44
+ /**
45
+ * Generate a SHA-256 content hash for any data object.
46
+ *
47
+ * The hash is deterministic - same input always produces same hash.
48
+ * This enables automatic deduplication in the IR graph.
49
+ *
50
+ * @param data - Any object to hash
51
+ * @returns 64-character lowercase hex string (SHA-256 hash)
52
+ *
53
+ * @example
54
+ * hashContent({ type: 'statement', content: 'Test' })
55
+ * // => 'a7f2c8d1b4e9f6a3c5d8e2b7f1a4c9d6e3b8a2f7c1d5e9b4a8f2c6d1e5a9b3f7'
56
+ */
57
+ function hashContent(data) {
58
+ // Normalize: recursively sort object keys for deterministic JSON
59
+ // Note: the previous implementation used an array replacer which
60
+ // only whitelists top-level keys — nested object fields were silently
61
+ // dropped. This recursive sort handles all nesting depths correctly.
62
+ const normalized = JSON.stringify(sortKeys(data));
63
+ // Generate SHA-256 hash
64
+ const hash = crypto.createHash('sha256');
65
+ hash.update(normalized);
66
+ // Return lowercase hex (64 chars)
67
+ return hash.digest('hex');
68
+ }
69
+ /** Recursively sort object keys for deterministic serialization */
70
+ function sortKeys(obj) {
71
+ if (obj === null || obj === undefined)
72
+ return obj;
73
+ if (Array.isArray(obj))
74
+ return obj.map(sortKeys);
75
+ if (typeof obj !== 'object')
76
+ return obj;
77
+ return Object.keys(obj).sort().reduce((acc, key) => {
78
+ acc[key] = sortKeys(obj[key]);
79
+ return acc;
80
+ }, {});
81
+ }
82
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBH,kCAaC;AA5BD,+CAAiC;AAEjC;;;;;;;;;;;;GAYG;AACH,SAAgB,WAAW,CAAC,IAAS;IACnC,iEAAiE;IACjE,iEAAiE;IACjE,sEAAsE;IACtE,qEAAqE;IACrE,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAElD,wBAAwB;IACxB,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAExB,kCAAkC;IAClC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,mEAAmE;AACnE,SAAS,QAAQ,CAAC,GAAQ;IACxB,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IAClD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,GAAwB,EAAE,GAAG,EAAE,EAAE;QACtE,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * IndentationScanner - Python-style indentation preprocessor for FlowScript
3
+ *
4
+ * Transforms indentation-based syntax into explicit block syntax by inserting
5
+ * implicit { } around indented sections. Uses stack-based INDENT/DEDENT algorithm
6
+ * proven in Python, Haskell, and F# implementations.
7
+ *
8
+ * Example transformation:
9
+ * INPUT: TRANSFORMED:
10
+ * A A
11
+ * B {B
12
+ * C C
13
+ * }
14
+ *
15
+ * Specification: See /spec/indentation.md
16
+ * Session: 4a-continued-2 (Preprocessor Core Implementation)
17
+ */
18
+ export interface IndentationScannerOptions {
19
+ /** Number of spaces per indentation level (default: 2) */
20
+ indentSize?: number;
21
+ }
22
+ /**
23
+ * Result of indentation preprocessing
24
+ */
25
+ export interface IndentationScannerResult {
26
+ /** Transformed source with explicit { } blocks */
27
+ transformed: string;
28
+ /** Maps transformed line number → original line number */
29
+ lineMap: Map<number, number>;
30
+ }
31
+ /**
32
+ * IndentationScanner preprocessor
33
+ *
34
+ * Transforms indentation-based FlowScript syntax into explicit block syntax
35
+ * by inserting { } around indented sections. This allows the existing parser
36
+ * to handle indented code without grammar changes.
37
+ */
38
+ export declare class IndentationScanner {
39
+ private indentStack;
40
+ private readonly indentSize;
41
+ private explicitBlockDepth;
42
+ private blockBaseIndent;
43
+ private savedIndentStack;
44
+ /**
45
+ * Create a new IndentationScanner
46
+ * @param options - Configuration options
47
+ */
48
+ constructor(options?: IndentationScannerOptions);
49
+ /**
50
+ * Process FlowScript input and transform indentation to explicit blocks
51
+ *
52
+ * @param input - FlowScript source code with indentation
53
+ * @returns Transformed source with explicit { } blocks and line mapping
54
+ */
55
+ process(input: string): IndentationScannerResult;
56
+ /**
57
+ * Process a single line of input
58
+ *
59
+ * @param line - Line of FlowScript source
60
+ * @param lineNum - Line number (1-indexed) in original source
61
+ * @returns Array of output lines with original line numbers (may include inserted { or })
62
+ */
63
+ private processLine;
64
+ /**
65
+ * Finalize processing by closing all remaining indentation levels
66
+ *
67
+ * Called at end of file to emit closing braces for any open indentation.
68
+ * @param lastOriginalLine - The last non-blank original line number (for provenance)
69
+ * @returns Array of closing braces with original line mapping
70
+ */
71
+ private finalize;
72
+ /**
73
+ * Count leading spaces in a line
74
+ *
75
+ * Stops at first non-space character or tab.
76
+ * @param line - Line to count spaces in
77
+ * @returns Number of leading spaces
78
+ */
79
+ private countLeadingSpaces;
80
+ }
81
+ //# sourceMappingURL=indentation-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indentation-scanner.d.ts","sourceRoot":"","sources":["../src/indentation-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,WAAW,yBAAyB;IACxC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,gBAAgB,CAAkB;IAE1C;;;OAGG;gBACS,OAAO,GAAE,yBAA8B;IAInD;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB;IAsDhD;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IA2LnB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IAehB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;CAW3B"}
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ /**
3
+ * IndentationScanner - Python-style indentation preprocessor for FlowScript
4
+ *
5
+ * Transforms indentation-based syntax into explicit block syntax by inserting
6
+ * implicit { } around indented sections. Uses stack-based INDENT/DEDENT algorithm
7
+ * proven in Python, Haskell, and F# implementations.
8
+ *
9
+ * Example transformation:
10
+ * INPUT: TRANSFORMED:
11
+ * A A
12
+ * B {B
13
+ * C C
14
+ * }
15
+ *
16
+ * Specification: See /spec/indentation.md
17
+ * Session: 4a-continued-2 (Preprocessor Core Implementation)
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.IndentationScanner = void 0;
21
+ const indentation_error_1 = require("./errors/indentation-error");
22
+ /**
23
+ * IndentationScanner preprocessor
24
+ *
25
+ * Transforms indentation-based FlowScript syntax into explicit block syntax
26
+ * by inserting { } around indented sections. This allows the existing parser
27
+ * to handle indented code without grammar changes.
28
+ */
29
+ class IndentationScanner {
30
+ /**
31
+ * Create a new IndentationScanner
32
+ * @param options - Configuration options
33
+ */
34
+ constructor(options = {}) {
35
+ this.indentStack = [0]; // Stack of active indentation levels
36
+ this.explicitBlockDepth = 0; // Track nesting depth of explicit {} blocks
37
+ this.blockBaseIndent = null; // Base indentation when inside explicit block
38
+ this.savedIndentStack = []; // Stack of indent stacks for nested explicit blocks
39
+ this.indentSize = options.indentSize ?? 2;
40
+ }
41
+ /**
42
+ * Process FlowScript input and transform indentation to explicit blocks
43
+ *
44
+ * @param input - FlowScript source code with indentation
45
+ * @returns Transformed source with explicit { } blocks and line mapping
46
+ */
47
+ process(input) {
48
+ // Handle empty input specially
49
+ if (input === '') {
50
+ return {
51
+ transformed: '',
52
+ lineMap: new Map()
53
+ };
54
+ }
55
+ const lines = input.split('\n');
56
+ const transformedLines = [];
57
+ const lineMap = new Map();
58
+ // Reset state for new processing
59
+ this.indentStack = [0];
60
+ this.explicitBlockDepth = 0;
61
+ this.blockBaseIndent = null;
62
+ this.savedIndentStack = [];
63
+ // Track the last non-blank original line for EOF closing
64
+ let lastOriginalLine = lines.length;
65
+ // Process each line
66
+ for (let i = 0; i < lines.length; i++) {
67
+ const originalLineNum = i + 1; // 1-indexed for user-facing errors
68
+ const processedLines = this.processLine(lines[i], originalLineNum);
69
+ // Track last non-blank line
70
+ if (lines[i].trim() !== '') {
71
+ lastOriginalLine = originalLineNum;
72
+ }
73
+ // Add each processed line with its original line mapping
74
+ for (const { line, originalLine } of processedLines) {
75
+ const outputLineNum = transformedLines.length + 1;
76
+ lineMap.set(outputLineNum, originalLine);
77
+ transformedLines.push(line);
78
+ }
79
+ }
80
+ // Close all remaining indentation levels at EOF
81
+ const finalLines = this.finalize(lastOriginalLine);
82
+ for (const { line, originalLine } of finalLines) {
83
+ const outputLineNum = transformedLines.length + 1;
84
+ lineMap.set(outputLineNum, originalLine);
85
+ transformedLines.push(line);
86
+ }
87
+ return {
88
+ transformed: transformedLines.join('\n'),
89
+ lineMap
90
+ };
91
+ }
92
+ /**
93
+ * Process a single line of input
94
+ *
95
+ * @param line - Line of FlowScript source
96
+ * @param lineNum - Line number (1-indexed) in original source
97
+ * @returns Array of output lines with original line numbers (may include inserted { or })
98
+ */
99
+ processLine(line, lineNum) {
100
+ // 1. Skip blank lines (whitespace-only or empty)
101
+ if (line.trim() === '') {
102
+ return [{ line, originalLine: lineNum }];
103
+ }
104
+ // 2. Track explicit block depth
105
+ const openBraces = (line.match(/\{/g) || []).length;
106
+ const closeBraces = (line.match(/\}/g) || []).length;
107
+ // Update depth and track transitions
108
+ const depthBeforeLine = this.explicitBlockDepth;
109
+ this.explicitBlockDepth += openBraces - closeBraces;
110
+ // 3. Handle lines with braces
111
+ if (openBraces > 0 || closeBraces > 0) {
112
+ const output = [];
113
+ // FIRST: Check if this line's indentation needs implicit blocks
114
+ // (before handling the explicit braces)
115
+ if (depthBeforeLine === 0) {
116
+ // We're not inside an explicit block, check for indentation change
117
+ const indent = this.countLeadingSpaces(line);
118
+ const prevIndent = this.indentStack[this.indentStack.length - 1];
119
+ if (indent > prevIndent) {
120
+ // INDENT: Indentation increased - add implicit opening brace
121
+ this.indentStack.push(indent);
122
+ // PREFIX '{' to the current line (same line, not separate!)
123
+ const currentIndent = this.countLeadingSpaces(line);
124
+ const content = line.trimStart();
125
+ output.push({ line: ' '.repeat(currentIndent) + '{' + content, originalLine: lineNum });
126
+ // Now handle the explicit brace on this line
127
+ if (openBraces > closeBraces) {
128
+ // Save stack and reset for explicit block
129
+ this.savedIndentStack.push([...this.indentStack]);
130
+ this.indentStack = [0];
131
+ this.blockBaseIndent = null;
132
+ }
133
+ return output;
134
+ }
135
+ else if (indent < prevIndent) {
136
+ // DEDENT: Close implicit blocks before processing this line
137
+ while (this.indentStack.length > 1 &&
138
+ this.indentStack[this.indentStack.length - 1] > indent) {
139
+ const closingIndent = this.indentStack[this.indentStack.length - 1];
140
+ this.indentStack.pop();
141
+ // Closing braces credit to the line that caused the dedent
142
+ output.push({ line: ' '.repeat(closingIndent) + '}', originalLine: lineNum });
143
+ }
144
+ // Verify dedent to valid level
145
+ if (this.indentStack[this.indentStack.length - 1] !== indent) {
146
+ const validLevels = this.indentStack.join(', ');
147
+ throw new indentation_error_1.IndentationError(`Invalid dedent to level ${indent}. Expected one of: [${validLevels}].`, lineNum);
148
+ }
149
+ // The line itself
150
+ output.push({ line, originalLine: lineNum });
151
+ // Now handle the explicit brace on this line
152
+ if (openBraces > closeBraces) {
153
+ // Save stack and reset for explicit block
154
+ this.savedIndentStack.push([...this.indentStack]);
155
+ this.indentStack = [0];
156
+ this.blockBaseIndent = null;
157
+ }
158
+ return output;
159
+ }
160
+ }
161
+ // SECOND: Handle explicit block exits (close implicit blocks first)
162
+ if (closeBraces > openBraces && this.blockBaseIndent !== null) {
163
+ // Close all implicit blocks opened within this explicit block
164
+ while (this.indentStack.length > 1 &&
165
+ this.indentStack[this.indentStack.length - 1] > this.blockBaseIndent) {
166
+ const closingIndent = this.indentStack[this.indentStack.length - 1];
167
+ this.indentStack.pop();
168
+ // Credit to current line (the explicit close brace line)
169
+ output.push({ line: ' '.repeat(closingIndent) + '}', originalLine: lineNum });
170
+ }
171
+ // Restore indent stack from before entering the explicit block
172
+ if (this.savedIndentStack.length > 0) {
173
+ this.indentStack = this.savedIndentStack.pop();
174
+ }
175
+ else {
176
+ this.indentStack = [0];
177
+ }
178
+ this.blockBaseIndent = null;
179
+ }
180
+ // THIRD: Handle explicit block entries
181
+ if (openBraces > closeBraces) {
182
+ // Save current indent stack before entering explicit block
183
+ this.savedIndentStack.push([...this.indentStack]);
184
+ this.indentStack = [0];
185
+ this.blockBaseIndent = null; // Will be set by next non-brace line
186
+ }
187
+ // Finally: The line with braces itself passes through
188
+ output.push({ line, originalLine: lineNum });
189
+ return output;
190
+ }
191
+ // 4. Inside explicit block: establish base indentation on first content line
192
+ if (this.explicitBlockDepth > 0 && this.blockBaseIndent === null) {
193
+ const indent = this.countLeadingSpaces(line);
194
+ this.blockBaseIndent = indent;
195
+ this.indentStack = [indent]; // Base level for this block
196
+ return [{ line, originalLine: lineNum }]; // First line in block passes through unchanged
197
+ }
198
+ // 5. Detect tabs (ERROR - not silent conversion)
199
+ if (line.includes('\t')) {
200
+ throw new indentation_error_1.IndentationError(`Tabs not allowed. Use ${this.indentSize} spaces for indentation.`, lineNum);
201
+ }
202
+ // 6. Calculate current indentation level
203
+ const indent = this.countLeadingSpaces(line);
204
+ // 7. First line must be at column 0
205
+ if (lineNum === 1 && indent > 0) {
206
+ throw new indentation_error_1.IndentationError('First line cannot be indented.', 1);
207
+ }
208
+ // Note: We don't enforce "multiple of indentSize" because Python-style indentation
209
+ // allows any indentation amount, as long as dedents return to valid levels.
210
+ // The spec examples (e.g., "Simple indentation") use 5 spaces which is not
211
+ // a multiple of 2, confirming this flexible approach.
212
+ const prevIndent = this.indentStack[this.indentStack.length - 1];
213
+ const output = [];
214
+ // 8. Compare current indent to previous level
215
+ if (indent > prevIndent) {
216
+ // INDENT: New nested level
217
+ // Push new level onto stack and prefix '{' to current line
218
+ this.indentStack.push(indent);
219
+ // PREFIX '{' to the current line (same line, not separate!)
220
+ // Spec Example 2: " {B" not " {\n B"
221
+ const currentIndent = this.countLeadingSpaces(line);
222
+ const content = line.trimStart();
223
+ output.push({ line: ' '.repeat(currentIndent) + '{' + content, originalLine: lineNum });
224
+ }
225
+ else if (indent < prevIndent) {
226
+ // DEDENT: Closing one or more levels
227
+ // Pop stack until we reach the target level, emitting closing braces
228
+ while (this.indentStack.length > 1 &&
229
+ this.indentStack[this.indentStack.length - 1] > indent) {
230
+ const closingIndent = this.indentStack[this.indentStack.length - 1];
231
+ this.indentStack.pop();
232
+ // Emit '}' at the indentation level being closed
233
+ // Credit to the line that caused the dedent
234
+ output.push({ line: ' '.repeat(closingIndent) + '}', originalLine: lineNum });
235
+ }
236
+ // Verify we dedented to a valid level (must exist in stack history)
237
+ if (this.indentStack[this.indentStack.length - 1] !== indent) {
238
+ const validLevels = this.indentStack.join(', ');
239
+ throw new indentation_error_1.IndentationError(`Invalid dedent to level ${indent}. Expected one of: [${validLevels}].`, lineNum);
240
+ }
241
+ // The current line itself
242
+ output.push({ line, originalLine: lineNum });
243
+ }
244
+ else {
245
+ // EQUAL: Same indentation level, no change needed
246
+ output.push({ line, originalLine: lineNum });
247
+ }
248
+ return output;
249
+ }
250
+ /**
251
+ * Finalize processing by closing all remaining indentation levels
252
+ *
253
+ * Called at end of file to emit closing braces for any open indentation.
254
+ * @param lastOriginalLine - The last non-blank original line number (for provenance)
255
+ * @returns Array of closing braces with original line mapping
256
+ */
257
+ finalize(lastOriginalLine) {
258
+ const output = [];
259
+ // Close all levels except the base level (0)
260
+ while (this.indentStack.length > 1) {
261
+ const closingIndent = this.indentStack[this.indentStack.length - 1];
262
+ this.indentStack.pop();
263
+ // Emit '}' at the indentation level being closed
264
+ // Credit to the last non-blank line (EOF closing)
265
+ output.push({ line: ' '.repeat(closingIndent) + '}', originalLine: lastOriginalLine });
266
+ }
267
+ return output;
268
+ }
269
+ /**
270
+ * Count leading spaces in a line
271
+ *
272
+ * Stops at first non-space character or tab.
273
+ * @param line - Line to count spaces in
274
+ * @returns Number of leading spaces
275
+ */
276
+ countLeadingSpaces(line) {
277
+ let count = 0;
278
+ for (const char of line) {
279
+ if (char === ' ') {
280
+ count++;
281
+ }
282
+ else {
283
+ break; // Stop at first non-space (tab check happens separately)
284
+ }
285
+ }
286
+ return count;
287
+ }
288
+ }
289
+ exports.IndentationScanner = IndentationScanner;
290
+ //# sourceMappingURL=indentation-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indentation-scanner.js","sourceRoot":"","sources":["../src/indentation-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * FlowScript Toolchain - Main Library Exports
3
+ *
4
+ * Exports all public APIs for programmatic use.
5
+ * For CLI usage, see bin/flowscript
6
+ */
7
+ export { Parser } from './parser';
8
+ export { Linter, LintResult, LintRule, Severity, BaseLintRule } from './linter';
9
+ export { validateIR, ValidationResult } from './validate';
10
+ export { FlowScriptQueryEngine, WhyOptions, WhatIfOptions, TensionOptions, BlockedOptions, AlternativesOptions, CausalAncestry, MinimalWhy, ImpactAnalysis, ImpactSummary, TensionsResult, TensionDetail, BlockedResult, BlockerDetail, AlternativesResult, AlternativesResultComparison, AlternativesResultTree, AlternativesResultSimple, TreeAlternative, AlternativeDetail, TensionInfo } from './query-engine';
11
+ export { serialize, SerializeOptions } from './serializer';
12
+ export { Memory, NodeRef, MemoryOptions, TemporalConfig, TemporalTierConfig, DormancyConfig, TemporalTier, TemporalMeta, GardenReport, PruneReport, SnapshotEntry, SnapshotInfo, GraduationCandidate, GraduationResult, GraduationHandler, MemoryJSON, BudgetedSerializeOptions, ToolSchema, ToolResult, MemoryTool, AsToolsOptions, ExtractFn, FromTranscriptOptions, TranscriptExtraction, AuditEntry } from './memory';
13
+ export { hashContent } from './hash';
14
+ export * from './types';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGhF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,4BAA4B,EAC5B,sBAAsB,EACtB,wBAAwB,EACxB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAG3D,OAAO,EACL,MAAM,EACN,OAAO,EACP,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,wBAAwB,EACxB,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,EACX,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAGrC,cAAc,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * FlowScript Toolchain - Main Library Exports
4
+ *
5
+ * Exports all public APIs for programmatic use.
6
+ * For CLI usage, see bin/flowscript
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.hashContent = exports.NodeRef = exports.Memory = exports.serialize = exports.FlowScriptQueryEngine = exports.validateIR = exports.BaseLintRule = exports.Linter = exports.Parser = void 0;
24
+ // Parser
25
+ var parser_1 = require("./parser");
26
+ Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return parser_1.Parser; } });
27
+ // Linter
28
+ var linter_1 = require("./linter");
29
+ Object.defineProperty(exports, "Linter", { enumerable: true, get: function () { return linter_1.Linter; } });
30
+ Object.defineProperty(exports, "BaseLintRule", { enumerable: true, get: function () { return linter_1.BaseLintRule; } });
31
+ // Validator
32
+ var validate_1 = require("./validate");
33
+ Object.defineProperty(exports, "validateIR", { enumerable: true, get: function () { return validate_1.validateIR; } });
34
+ // Query Engine
35
+ var query_engine_1 = require("./query-engine");
36
+ Object.defineProperty(exports, "FlowScriptQueryEngine", { enumerable: true, get: function () { return query_engine_1.FlowScriptQueryEngine; } });
37
+ // Serializer (IR → .fs)
38
+ var serializer_1 = require("./serializer");
39
+ Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return serializer_1.serialize; } });
40
+ // Memory (programmatic builder + temporal intelligence)
41
+ var memory_1 = require("./memory");
42
+ Object.defineProperty(exports, "Memory", { enumerable: true, get: function () { return memory_1.Memory; } });
43
+ Object.defineProperty(exports, "NodeRef", { enumerable: true, get: function () { return memory_1.NodeRef; } });
44
+ // Hash utilities
45
+ var hash_1 = require("./hash");
46
+ Object.defineProperty(exports, "hashContent", { enumerable: true, get: function () { return hash_1.hashContent; } });
47
+ // Type definitions
48
+ __exportStar(require("./types"), exports);
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;AAEH,SAAS;AACT,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AAEf,SAAS;AACT,mCAAgF;AAAvE,gGAAA,MAAM,OAAA;AAAkC,sGAAA,YAAY,OAAA;AAE7D,YAAY;AACZ,uCAA0D;AAAjD,sGAAA,UAAU,OAAA;AAEnB,eAAe;AACf,+CAsBwB;AArBtB,qHAAA,qBAAqB,OAAA;AAuBvB,wBAAwB;AACxB,2CAA2D;AAAlD,uGAAA,SAAS,OAAA;AAElB,wDAAwD;AACxD,mCA0BkB;AAzBhB,gGAAA,MAAM,OAAA;AACN,iGAAA,OAAO,OAAA;AA0BT,iBAAiB;AACjB,+BAAqC;AAA5B,mGAAA,WAAW,OAAA;AAEpB,mBAAmB;AACnB,0CAAwB"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * FlowScript Semantic Linter
3
+ *
4
+ * Enforces semantic correctness beyond syntax validation.
5
+ * Implements 6 ERROR + 3 WARNING rules from spec/linter-rules.md
6
+ *
7
+ * Architecture: Two-pass validation
8
+ * - Pass 1: Syntax validation (handled by parser)
9
+ * - Pass 2: Semantic validation (this linter)
10
+ */
11
+ import { IR } from './types';
12
+ export type Severity = 'ERROR' | 'WARNING';
13
+ export interface LintResult {
14
+ severity: Severity;
15
+ rule: string;
16
+ message: string;
17
+ location?: {
18
+ file: string;
19
+ line: number;
20
+ };
21
+ suggestion?: string;
22
+ }
23
+ export interface LintRule {
24
+ name: string;
25
+ code: string;
26
+ severity: Severity;
27
+ check(ir: IR): LintResult[];
28
+ }
29
+ /**
30
+ * Base class for lint rules - provides helper methods
31
+ */
32
+ export declare abstract class BaseLintRule implements LintRule {
33
+ abstract name: string;
34
+ abstract code: string;
35
+ abstract severity: Severity;
36
+ abstract check(ir: IR): LintResult[];
37
+ protected createResult(message: string, location?: {
38
+ file: string;
39
+ line: number;
40
+ }, suggestion?: string): LintResult;
41
+ }
42
+ /**
43
+ * Main linter class - orchestrates all validation rules
44
+ */
45
+ export declare class Linter {
46
+ private rules;
47
+ constructor();
48
+ private registerRules;
49
+ /**
50
+ * Register a single rule (for testing or custom rules)
51
+ */
52
+ addRule(rule: LintRule): void;
53
+ /**
54
+ * Main linting entry point
55
+ */
56
+ lint(ir: IR): LintResult[];
57
+ /**
58
+ * Filter results by severity
59
+ */
60
+ getErrors(results: LintResult[]): LintResult[];
61
+ getWarnings(results: LintResult[]): LintResult[];
62
+ /**
63
+ * Check if linting passed (no errors)
64
+ */
65
+ hasErrors(results: LintResult[]): boolean;
66
+ /**
67
+ * Format results for display
68
+ */
69
+ formatResults(results: LintResult[]): string;
70
+ }
71
+ //# sourceMappingURL=linter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../src/linter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,8BAAsB,YAAa,YAAW,QAAQ;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE;IAEpC,SAAS,CAAC,YAAY,CACpB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EACzC,UAAU,CAAC,EAAE,MAAM,GAClB,UAAU;CASd;AAED;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAkB;;IAM/B,OAAO,CAAC,aAAa;IA4BrB;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAI7B;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE;IA0B1B;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE;IAI9C,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE;IAIhD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO;IAIzC;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM;CAwB7C"}