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":"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
|
package/dist/hash.js.map
ADDED
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/linter.d.ts
ADDED
|
@@ -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"}
|