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.
- package/LICENSE +21 -0
- package/README.md +386 -0
- package/bin/flowscript +12 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +463 -0
- package/dist/cli.js.map +1 -0
- package/dist/errors/indentation-error.d.ts +11 -0
- package/dist/errors/indentation-error.d.ts.map +1 -0
- package/dist/errors/indentation-error.js +22 -0
- package/dist/errors/indentation-error.js.map +1 -0
- package/dist/grammar.ohm +132 -0
- package/dist/hash.d.ts +21 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +82 -0
- package/dist/hash.js.map +1 -0
- package/dist/indentation-scanner.d.ts +81 -0
- package/dist/indentation-scanner.d.ts.map +1 -0
- package/dist/indentation-scanner.js +290 -0
- package/dist/indentation-scanner.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/linter.d.ts +71 -0
- package/dist/linter.d.ts.map +1 -0
- package/dist/linter.js +122 -0
- package/dist/linter.js.map +1 -0
- package/dist/memory.d.ts +506 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +1802 -0
- package/dist/memory.js.map +1 -0
- package/dist/parser.d.ts +53 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +1184 -0
- package/dist/parser.js.map +1 -0
- package/dist/query-engine.d.ts +320 -0
- package/dist/query-engine.d.ts.map +1 -0
- package/dist/query-engine.js +884 -0
- package/dist/query-engine.js.map +1 -0
- package/dist/rules/alternatives-without-decision.d.ts +24 -0
- package/dist/rules/alternatives-without-decision.d.ts.map +1 -0
- package/dist/rules/alternatives-without-decision.js +58 -0
- package/dist/rules/alternatives-without-decision.js.map +1 -0
- package/dist/rules/causal-cycles.d.ts +23 -0
- package/dist/rules/causal-cycles.d.ts.map +1 -0
- package/dist/rules/causal-cycles.js +83 -0
- package/dist/rules/causal-cycles.js.map +1 -0
- package/dist/rules/deep-nesting.d.ts +23 -0
- package/dist/rules/deep-nesting.d.ts.map +1 -0
- package/dist/rules/deep-nesting.js +55 -0
- package/dist/rules/deep-nesting.js.map +1 -0
- package/dist/rules/index.d.ts +15 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +29 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/invalid-syntax.d.ts +22 -0
- package/dist/rules/invalid-syntax.d.ts.map +1 -0
- package/dist/rules/invalid-syntax.js +52 -0
- package/dist/rules/invalid-syntax.js.map +1 -0
- package/dist/rules/long-causal-chains.d.ts +25 -0
- package/dist/rules/long-causal-chains.d.ts.map +1 -0
- package/dist/rules/long-causal-chains.js +75 -0
- package/dist/rules/long-causal-chains.js.map +1 -0
- package/dist/rules/missing-recommended-fields.d.ts +21 -0
- package/dist/rules/missing-recommended-fields.d.ts.map +1 -0
- package/dist/rules/missing-recommended-fields.js +45 -0
- package/dist/rules/missing-recommended-fields.js.map +1 -0
- package/dist/rules/missing-required-fields.d.ts +22 -0
- package/dist/rules/missing-required-fields.d.ts.map +1 -0
- package/dist/rules/missing-required-fields.js +46 -0
- package/dist/rules/missing-required-fields.js.map +1 -0
- package/dist/rules/orphaned-nodes.d.ts +22 -0
- package/dist/rules/orphaned-nodes.d.ts.map +1 -0
- package/dist/rules/orphaned-nodes.js +76 -0
- package/dist/rules/orphaned-nodes.js.map +1 -0
- package/dist/rules/unlabeled-tension.d.ts +20 -0
- package/dist/rules/unlabeled-tension.d.ts.map +1 -0
- package/dist/rules/unlabeled-tension.js +37 -0
- package/dist/rules/unlabeled-tension.js.map +1 -0
- package/dist/serializer.d.ts +40 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/serializer.js +368 -0
- package/dist/serializer.js.map +1 -0
- package/dist/tokenizer.d.ts +26 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +213 -0
- package/dist/tokenizer.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +50 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +18 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +68 -0
- package/dist/validate.js.map +1 -0
- 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"}
|