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":"missing-recommended-fields.d.ts","sourceRoot":"","sources":["../../src/rules/missing-recommended-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAErD,qBAAa,4BAA6B,SAAQ,YAAY;IAC5D,IAAI,SAAgC;IACpC,IAAI,SAAU;IACd,QAAQ,EAAG,SAAS,CAAU;IAE9B,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE;CAyB5B"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /**
3
+ * W001: Missing Recommended State Fields Rule
4
+ *
5
+ * Specification: spec/linter-rules.md lines 747-803
6
+ *
7
+ * State marker [parking] SHOULD include recommended fields:
8
+ * - why - Why is this parked?
9
+ * - until - When to revisit?
10
+ *
11
+ * Missing these fields doesn't break semantics, but reduces clarity.
12
+ * Parking without explanation = easy to forget why.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.MissingRecommendedFieldsRule = void 0;
16
+ const linter_1 = require("../linter");
17
+ class MissingRecommendedFieldsRule extends linter_1.BaseLintRule {
18
+ constructor() {
19
+ super(...arguments);
20
+ this.name = 'missing-recommended-fields';
21
+ this.code = 'W001';
22
+ this.severity = 'WARNING';
23
+ }
24
+ check(ir) {
25
+ const results = [];
26
+ for (const state of ir.states) {
27
+ if (state.type === 'parking') {
28
+ const missing = [];
29
+ if (!state.fields.why)
30
+ missing.push('why');
31
+ if (!state.fields.until)
32
+ missing.push('until');
33
+ if (missing.length > 0) {
34
+ results.push(this.createResult(`[parking] missing recommended field${missing.length > 1 ? 's' : ''}: ${missing.join(', ')}`, {
35
+ file: state.provenance.source_file,
36
+ line: state.provenance.line_number
37
+ }, `Add recommended fields: ${missing.map(f => `${f}: "..."`).join(', ')}`));
38
+ }
39
+ }
40
+ }
41
+ return results;
42
+ }
43
+ }
44
+ exports.MissingRecommendedFieldsRule = MissingRecommendedFieldsRule;
45
+ //# sourceMappingURL=missing-recommended-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-recommended-fields.js","sourceRoot":"","sources":["../../src/rules/missing-recommended-fields.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAGH,sCAAqD;AAErD,MAAa,4BAA6B,SAAQ,qBAAY;IAA9D;;QACE,SAAI,GAAG,4BAA4B,CAAC;QACpC,SAAI,GAAG,MAAM,CAAC;QACd,aAAQ,GAAG,SAAkB,CAAC;IA2BhC,CAAC;IAzBC,KAAK,CAAC,EAAM;QACV,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;gBAE7B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG;oBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;oBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAE/C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAC5B,sCAAsC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAC5F;wBACE,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;wBAClC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;qBACnC,EACD,2BAA2B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AA9BD,oEA8BC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * E002: Missing Required State Fields Rule
3
+ *
4
+ * Specification: spec/linter-rules.md lines 150-243
5
+ *
6
+ * State markers with REQUIRED fields must include them:
7
+ * - [decided] → MUST have 'rationale' and 'on'
8
+ * - [blocked] → MUST have 'reason' and 'since'
9
+ *
10
+ * This forcing function prevents "we decided" without explaining why,
11
+ * or "blocked" without tracking when/why.
12
+ */
13
+ import { IR } from '../types';
14
+ import { BaseLintRule, LintResult } from '../linter';
15
+ export declare class MissingRequiredFieldsRule extends BaseLintRule {
16
+ name: string;
17
+ code: string;
18
+ severity: "ERROR";
19
+ private requiredFields;
20
+ check(ir: IR): LintResult[];
21
+ }
22
+ //# sourceMappingURL=missing-required-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-required-fields.d.ts","sourceRoot":"","sources":["../../src/rules/missing-required-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAErD,qBAAa,yBAA0B,SAAQ,YAAY;IACzD,IAAI,SAA6B;IACjC,IAAI,SAAU;IACd,QAAQ,EAAG,OAAO,CAAU;IAE5B,OAAO,CAAC,cAAc,CAGpB;IAEF,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE;CAuB5B"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /**
3
+ * E002: Missing Required State Fields Rule
4
+ *
5
+ * Specification: spec/linter-rules.md lines 150-243
6
+ *
7
+ * State markers with REQUIRED fields must include them:
8
+ * - [decided] → MUST have 'rationale' and 'on'
9
+ * - [blocked] → MUST have 'reason' and 'since'
10
+ *
11
+ * This forcing function prevents "we decided" without explaining why,
12
+ * or "blocked" without tracking when/why.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.MissingRequiredFieldsRule = void 0;
16
+ const linter_1 = require("../linter");
17
+ class MissingRequiredFieldsRule extends linter_1.BaseLintRule {
18
+ constructor() {
19
+ super(...arguments);
20
+ this.name = 'missing-required-fields';
21
+ this.code = 'E002';
22
+ this.severity = 'ERROR';
23
+ this.requiredFields = {
24
+ 'decided': ['rationale', 'on'],
25
+ 'blocked': ['reason', 'since']
26
+ };
27
+ }
28
+ check(ir) {
29
+ const results = [];
30
+ for (const state of ir.states) {
31
+ const required = this.requiredFields[state.type];
32
+ if (!required)
33
+ continue; // No required fields for this type
34
+ const missing = required.filter(field => !state.fields[field]);
35
+ if (missing.length > 0) {
36
+ results.push(this.createResult(`[${state.type}] state missing required field${missing.length > 1 ? 's' : ''}: ${missing.join(', ')}`, {
37
+ file: state.provenance.source_file,
38
+ line: state.provenance.line_number
39
+ }, `Add required fields: ${missing.map(f => `${f}: "..."`).join(', ')}`));
40
+ }
41
+ }
42
+ return results;
43
+ }
44
+ }
45
+ exports.MissingRequiredFieldsRule = MissingRequiredFieldsRule;
46
+ //# sourceMappingURL=missing-required-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-required-fields.js","sourceRoot":"","sources":["../../src/rules/missing-required-fields.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAGH,sCAAqD;AAErD,MAAa,yBAA0B,SAAQ,qBAAY;IAA3D;;QACE,SAAI,GAAG,yBAAyB,CAAC;QACjC,SAAI,GAAG,MAAM,CAAC;QACd,aAAQ,GAAG,OAAgB,CAAC;QAEpB,mBAAc,GAA6B;YACjD,SAAS,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC;YAC9B,SAAS,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;SAC/B,CAAC;IAyBJ,CAAC;IAvBC,KAAK,CAAC,EAAM;QACV,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,CAAC,QAAQ;gBAAE,SAAS,CAAE,mCAAmC;YAE7D,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAE/D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAC5B,IAAI,KAAK,CAAC,IAAI,iCAAiC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACrG;oBACE,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;oBAClC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;iBACnC,EACD,wBAAwB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAjCD,8DAiCC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * E004: Orphaned Nodes Rule
3
+ *
4
+ * Specification: spec/linter-rules.md lines 347-483
5
+ *
6
+ * Nodes with zero relationships (no edges in or out) are orphaned.
7
+ * This indicates isolated thought with no connections.
8
+ *
9
+ * FlowScript is about relationships between thoughts.
10
+ * Isolated nodes break the graph structure.
11
+ *
12
+ * Exception: Root questions and standalone insights may be degree 0.
13
+ */
14
+ import { IR } from '../types';
15
+ import { BaseLintRule, LintResult } from '../linter';
16
+ export declare class OrphanedNodesRule extends BaseLintRule {
17
+ name: string;
18
+ code: string;
19
+ severity: "ERROR";
20
+ check(ir: IR): LintResult[];
21
+ }
22
+ //# sourceMappingURL=orphaned-nodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orphaned-nodes.d.ts","sourceRoot":"","sources":["../../src/rules/orphaned-nodes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAErD,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,IAAI,SAAoB;IACxB,IAAI,SAAU;IACd,QAAQ,EAAG,OAAO,CAAU;IAE5B,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE;CA4D5B"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * E004: Orphaned Nodes Rule
4
+ *
5
+ * Specification: spec/linter-rules.md lines 347-483
6
+ *
7
+ * Nodes with zero relationships (no edges in or out) are orphaned.
8
+ * This indicates isolated thought with no connections.
9
+ *
10
+ * FlowScript is about relationships between thoughts.
11
+ * Isolated nodes break the graph structure.
12
+ *
13
+ * Exception: Root questions and standalone insights may be degree 0.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.OrphanedNodesRule = void 0;
17
+ const linter_1 = require("../linter");
18
+ class OrphanedNodesRule extends linter_1.BaseLintRule {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.name = 'orphaned-nodes';
22
+ this.code = 'E004';
23
+ this.severity = 'ERROR';
24
+ }
25
+ check(ir) {
26
+ const results = [];
27
+ // Build set of connected node IDs
28
+ const connectedIds = new Set();
29
+ // 1. Add nodes connected via explicit relationships (-> <- <-> => ><[axis])
30
+ for (const rel of ir.relationships) {
31
+ connectedIds.add(rel.source);
32
+ connectedIds.add(rel.target);
33
+ }
34
+ // 2. Add nodes connected via block hierarchies (parent-child relationships)
35
+ for (const node of ir.nodes) {
36
+ if (node.type === 'block' && node.ext?.children && Array.isArray(node.ext.children)) {
37
+ // Mark the block as connected
38
+ connectedIds.add(node.id);
39
+ // Mark all children as connected
40
+ for (const child of node.ext.children) {
41
+ connectedIds.add(child.id);
42
+ }
43
+ }
44
+ }
45
+ // 3. Add nodes connected via hierarchical children arrays (spec-compliant)
46
+ for (const node of ir.nodes) {
47
+ if (node.children && node.children.length > 0) {
48
+ // Mark the parent as connected
49
+ connectedIds.add(node.id);
50
+ // Mark all children as connected
51
+ for (const childId of node.children) {
52
+ connectedIds.add(childId);
53
+ }
54
+ }
55
+ }
56
+ // Check each node for connections
57
+ for (const node of ir.nodes) {
58
+ if (!connectedIds.has(node.id)) {
59
+ // Exempt action and completion nodes from orphan detection
60
+ // These are metadata (todos, tracking) not graph semantics
61
+ // Spec Pattern 2 demonstrates this: action nodes as todo lists
62
+ if (node.type === 'action' || node.type === 'completion') {
63
+ continue;
64
+ }
65
+ // Node has degree 0 (no edges)
66
+ results.push(this.createResult(`Orphaned node detected (no relationships): "${node.content}"`, {
67
+ file: node.provenance.source_file,
68
+ line: node.provenance.line_number
69
+ }, `Connect with relationship: ${node.content} -> {target} OR {source} -> ${node.content}`));
70
+ }
71
+ }
72
+ return results;
73
+ }
74
+ }
75
+ exports.OrphanedNodesRule = OrphanedNodesRule;
76
+ //# sourceMappingURL=orphaned-nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orphaned-nodes.js","sourceRoot":"","sources":["../../src/rules/orphaned-nodes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAGH,sCAAqD;AAErD,MAAa,iBAAkB,SAAQ,qBAAY;IAAnD;;QACE,SAAI,GAAG,gBAAgB,CAAC;QACxB,SAAI,GAAG,MAAM,CAAC;QACd,aAAQ,GAAG,OAAgB,CAAC;IA8D9B,CAAC;IA5DC,KAAK,CAAC,EAAM;QACV,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,kCAAkC;QAClC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;QAEvC,6EAA6E;QAC7E,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC;YACnC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;QAED,4EAA4E;QAC5E,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpF,8BAA8B;gBAC9B,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1B,iCAAiC;gBACjC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;oBACtC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;QACH,CAAC;QAED,2EAA2E;QAC3E,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9C,+BAA+B;gBAC/B,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1B,iCAAiC;gBACjC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACpC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/B,2DAA2D;gBAC3D,2DAA2D;gBAC3D,+DAA+D;gBAC/D,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACzD,SAAS;gBACX,CAAC;gBAED,+BAA+B;gBAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAC5B,+CAA+C,IAAI,CAAC,OAAO,GAAG,EAC9D;oBACE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW;oBACjC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW;iBAClC,EACD,8BAA8B,IAAI,CAAC,OAAO,+BAA+B,IAAI,CAAC,OAAO,EAAE,CACxF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAjED,8CAiEC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * E001: Unlabeled Tension Rule
3
+ *
4
+ * Specification: spec/linter-rules.md lines 69-146
5
+ *
6
+ * Tension marker ><` MUST include axis label in brackets.
7
+ * This forcing function ensures explicit articulation of tradeoff dimension.
8
+ *
9
+ * INVALID: A >< B
10
+ * VALID: A ><[axis label] B
11
+ */
12
+ import { IR } from '../types';
13
+ import { BaseLintRule, LintResult } from '../linter';
14
+ export declare class UnlabeledTensionRule extends BaseLintRule {
15
+ name: string;
16
+ code: string;
17
+ severity: "ERROR";
18
+ check(ir: IR): LintResult[];
19
+ }
20
+ //# sourceMappingURL=unlabeled-tension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlabeled-tension.d.ts","sourceRoot":"","sources":["../../src/rules/unlabeled-tension.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAErD,qBAAa,oBAAqB,SAAQ,YAAY;IACpD,IAAI,SAAuB;IAC3B,IAAI,SAAU;IACd,QAAQ,EAAG,OAAO,CAAU;IAE5B,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,UAAU,EAAE;CAkB5B"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /**
3
+ * E001: Unlabeled Tension Rule
4
+ *
5
+ * Specification: spec/linter-rules.md lines 69-146
6
+ *
7
+ * Tension marker ><` MUST include axis label in brackets.
8
+ * This forcing function ensures explicit articulation of tradeoff dimension.
9
+ *
10
+ * INVALID: A >< B
11
+ * VALID: A ><[axis label] B
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.UnlabeledTensionRule = void 0;
15
+ const linter_1 = require("../linter");
16
+ class UnlabeledTensionRule extends linter_1.BaseLintRule {
17
+ constructor() {
18
+ super(...arguments);
19
+ this.name = 'unlabeled-tension';
20
+ this.code = 'E001';
21
+ this.severity = 'ERROR';
22
+ }
23
+ check(ir) {
24
+ const results = [];
25
+ for (const rel of ir.relationships) {
26
+ if (rel.type === 'tension' && !rel.axis_label) {
27
+ results.push(this.createResult('Tension marker >< missing required axis label', {
28
+ file: rel.provenance.source_file,
29
+ line: rel.provenance.line_number
30
+ }, 'Add axis label: ><[dimension of tradeoff]'));
31
+ }
32
+ }
33
+ return results;
34
+ }
35
+ }
36
+ exports.UnlabeledTensionRule = UnlabeledTensionRule;
37
+ //# sourceMappingURL=unlabeled-tension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlabeled-tension.js","sourceRoot":"","sources":["../../src/rules/unlabeled-tension.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAGH,sCAAqD;AAErD,MAAa,oBAAqB,SAAQ,qBAAY;IAAtD;;QACE,SAAI,GAAG,mBAAmB,CAAC;QAC3B,SAAI,GAAG,MAAM,CAAC;QACd,aAAQ,GAAG,OAAgB,CAAC;IAoB9B,CAAC;IAlBC,KAAK,CAAC,EAAM;QACV,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC;YACnC,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;gBAC9C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAC5B,+CAA+C,EAC/C;oBACE,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,WAAW;oBAChC,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,WAAW;iBACjC,EACD,2CAA2C,CAC5C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAvBD,oDAuBC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * FlowScript IR → .fs Serializer
3
+ *
4
+ * Converts an IR (Intermediate Representation) back to valid FlowScript text.
5
+ * The produced text, when re-parsed, should produce a semantically equivalent IR.
6
+ *
7
+ * Design:
8
+ * - Walks the node graph in provenance order (line numbers)
9
+ * - Reconstructs nesting from children arrays
10
+ * - Renders relationships as continuation lines (-> target) under source nodes
11
+ * - Places state markers before their annotated nodes (separate line if provenance differs)
12
+ * - Preserves modifiers, axis labels, and state fields
13
+ * - Typed relationship targets preserve both operator and type (-> thought: content)
14
+ *
15
+ * KNOWN LIMITATION — Cross-Reference Drops (Graph vs Tree):
16
+ * .fs text is indentation-based (tree structure). The IR is a graph (nodes can have
17
+ * multiple incoming edges). When a node is the target of relationships from multiple
18
+ * sources, only the parent-child relationship is rendered. Cross-cutting relationships
19
+ * (A -> B where B is already a child of C) are silently dropped during serialization.
20
+ *
21
+ * This is a fundamental format limitation, not a bug. The IR JSON preserves the full
22
+ * graph; .fs is a lossy tree projection. This MUST be addressed when building the
23
+ * Memory class — the Memory API will produce cross-cutting graphs that need either:
24
+ * (a) ID-based reference syntax in .fs (grammar extension)
25
+ * (b) Accepting .fs as lossy with JSON as canonical
26
+ * (c) A cross-references section at the end of .fs output
27
+ * See: https://github.com/phillipclapham/flowscript — design decision pending.
28
+ */
29
+ import { IR } from './types';
30
+ export interface SerializeOptions {
31
+ /** Indentation string per level (default: ' ' — two spaces) */
32
+ indent?: string;
33
+ /** Whether to include blank lines between top-level elements (default: true) */
34
+ blankLinesBetween?: boolean;
35
+ }
36
+ /**
37
+ * Serialize an IR back to FlowScript text.
38
+ */
39
+ export declare function serialize(ir: IR, options?: SerializeOptions): string;
40
+ //# sourceMappingURL=serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,EAAE,EAAqD,MAAM,SAAS,CAAC;AAEhF,MAAM,WAAW,gBAAgB;IAC/B,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CA0FxE"}