@smeltjs/core 0.1.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 +202 -0
- package/README.md +55 -0
- package/THIRD-PARTY.md +140 -0
- package/dist/apply.d.ts +145 -0
- package/dist/apply.d.ts.map +1 -0
- package/dist/apply.js +244 -0
- package/dist/apply.js.map +1 -0
- package/dist/cache/prefix.d.ts +164 -0
- package/dist/cache/prefix.d.ts.map +1 -0
- package/dist/cache/prefix.js +361 -0
- package/dist/cache/prefix.js.map +1 -0
- package/dist/cli/args.d.ts +71 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +308 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +161 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/config.d.ts +73 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +144 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/init.d.ts +56 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +449 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/report.d.ts +44 -0
- package/dist/cli/report.d.ts.map +1 -0
- package/dist/cli/report.js +113 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/resolve.d.ts +103 -0
- package/dist/cli/resolve.d.ts.map +1 -0
- package/dist/cli/resolve.js +106 -0
- package/dist/cli/resolve.js.map +1 -0
- package/dist/cli/run.d.ts +99 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +351 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/detect.d.ts +16 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +18 -0
- package/dist/detect.js.map +1 -0
- package/dist/errors.d.ts +88 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +107 -0
- package/dist/errors.js.map +1 -0
- package/dist/hash.d.ts +13 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +16 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/lang/bash.d.ts +3 -0
- package/dist/lang/bash.d.ts.map +1 -0
- package/dist/lang/bash.js +28 -0
- package/dist/lang/bash.js.map +1 -0
- package/dist/lang/c.d.ts +3 -0
- package/dist/lang/c.d.ts.map +1 -0
- package/dist/lang/c.js +39 -0
- package/dist/lang/c.js.map +1 -0
- package/dist/lang/c_sharp.d.ts +3 -0
- package/dist/lang/c_sharp.d.ts.map +1 -0
- package/dist/lang/c_sharp.js +37 -0
- package/dist/lang/c_sharp.js.map +1 -0
- package/dist/lang/cpp.d.ts +3 -0
- package/dist/lang/cpp.d.ts.map +1 -0
- package/dist/lang/cpp.js +46 -0
- package/dist/lang/cpp.js.map +1 -0
- package/dist/lang/go.d.ts +3 -0
- package/dist/lang/go.d.ts.map +1 -0
- package/dist/lang/go.js +31 -0
- package/dist/lang/go.js.map +1 -0
- package/dist/lang/java.d.ts +3 -0
- package/dist/lang/java.d.ts.map +1 -0
- package/dist/lang/java.js +34 -0
- package/dist/lang/java.js.map +1 -0
- package/dist/lang/javascript.d.ts +3 -0
- package/dist/lang/javascript.d.ts.map +1 -0
- package/dist/lang/javascript.js +28 -0
- package/dist/lang/javascript.js.map +1 -0
- package/dist/lang/kotlin.d.ts +3 -0
- package/dist/lang/kotlin.d.ts.map +1 -0
- package/dist/lang/kotlin.js +37 -0
- package/dist/lang/kotlin.js.map +1 -0
- package/dist/lang/php.d.ts +3 -0
- package/dist/lang/php.d.ts.map +1 -0
- package/dist/lang/php.js +37 -0
- package/dist/lang/php.js.map +1 -0
- package/dist/lang/profile.d.ts +130 -0
- package/dist/lang/profile.d.ts.map +1 -0
- package/dist/lang/profile.js +2 -0
- package/dist/lang/profile.js.map +1 -0
- package/dist/lang/python.d.ts +3 -0
- package/dist/lang/python.d.ts.map +1 -0
- package/dist/lang/python.js +33 -0
- package/dist/lang/python.js.map +1 -0
- package/dist/lang/registry.d.ts +31 -0
- package/dist/lang/registry.d.ts.map +1 -0
- package/dist/lang/registry.js +89 -0
- package/dist/lang/registry.js.map +1 -0
- package/dist/lang/ruby.d.ts +3 -0
- package/dist/lang/ruby.d.ts.map +1 -0
- package/dist/lang/ruby.js +47 -0
- package/dist/lang/ruby.js.map +1 -0
- package/dist/lang/rust.d.ts +3 -0
- package/dist/lang/rust.d.ts.map +1 -0
- package/dist/lang/rust.js +45 -0
- package/dist/lang/rust.js.map +1 -0
- package/dist/lang/swift.d.ts +3 -0
- package/dist/lang/swift.d.ts.map +1 -0
- package/dist/lang/swift.js +34 -0
- package/dist/lang/swift.js.map +1 -0
- package/dist/lang/tsx.d.ts +4 -0
- package/dist/lang/tsx.d.ts.map +1 -0
- package/dist/lang/tsx.js +11 -0
- package/dist/lang/tsx.js.map +1 -0
- package/dist/lang/typescript.d.ts +18 -0
- package/dist/lang/typescript.d.ts.map +1 -0
- package/dist/lang/typescript.js +61 -0
- package/dist/lang/typescript.js.map +1 -0
- package/dist/net/policy.d.ts +49 -0
- package/dist/net/policy.d.ts.map +1 -0
- package/dist/net/policy.js +120 -0
- package/dist/net/policy.js.map +1 -0
- package/dist/plan/grammar.d.ts +38 -0
- package/dist/plan/grammar.d.ts.map +1 -0
- package/dist/plan/grammar.js +85 -0
- package/dist/plan/grammar.js.map +1 -0
- package/dist/plan/lexical.d.ts +51 -0
- package/dist/plan/lexical.d.ts.map +1 -0
- package/dist/plan/lexical.js +167 -0
- package/dist/plan/lexical.js.map +1 -0
- package/dist/plan/planners.d.ts +35 -0
- package/dist/plan/planners.d.ts.map +1 -0
- package/dist/plan/planners.js +26 -0
- package/dist/plan/planners.js.map +1 -0
- package/dist/plan/structural.d.ts +68 -0
- package/dist/plan/structural.d.ts.map +1 -0
- package/dist/plan/structural.js +458 -0
- package/dist/plan/structural.js.map +1 -0
- package/dist/repomap/cache.d.ts +53 -0
- package/dist/repomap/cache.d.ts.map +1 -0
- package/dist/repomap/cache.js +139 -0
- package/dist/repomap/cache.js.map +1 -0
- package/dist/repomap/map.d.ts +161 -0
- package/dist/repomap/map.d.ts.map +1 -0
- package/dist/repomap/map.js +302 -0
- package/dist/repomap/map.js.map +1 -0
- package/dist/repomap/rank.d.ts +52 -0
- package/dist/repomap/rank.d.ts.map +1 -0
- package/dist/repomap/rank.js +155 -0
- package/dist/repomap/rank.js.map +1 -0
- package/dist/repomap/tags.d.ts +47 -0
- package/dist/repomap/tags.d.ts.map +1 -0
- package/dist/repomap/tags.js +101 -0
- package/dist/repomap/tags.js.map +1 -0
- package/dist/retrieve.d.ts +14 -0
- package/dist/retrieve.d.ts.map +1 -0
- package/dist/retrieve.js +44 -0
- package/dist/retrieve.js.map +1 -0
- package/dist/stages.d.ts +22 -0
- package/dist/stages.d.ts.map +1 -0
- package/dist/stages.js +33 -0
- package/dist/stages.js.map +1 -0
- package/dist/stats.d.ts +40 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +37 -0
- package/dist/stats.js.map +1 -0
- package/dist/store-dir.d.ts +98 -0
- package/dist/store-dir.d.ts.map +1 -0
- package/dist/store-dir.js +379 -0
- package/dist/store-dir.js.map +1 -0
- package/dist/store.d.ts +36 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +56 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +298 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-c_sharp.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-go.wasm +0 -0
- package/grammars/tree-sitter-java.wasm +0 -0
- package/grammars/tree-sitter-javascript.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-php.wasm +0 -0
- package/grammars/tree-sitter-python.wasm +0 -0
- package/grammars/tree-sitter-ruby.wasm +0 -0
- package/grammars/tree-sitter-rust.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/grammars/tree-sitter-tsx.wasm +0 -0
- package/grammars/tree-sitter-typescript.wasm +0 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planners.d.ts","sourceRoot":"","sources":["../../src/plan/planners.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,wBAAwB,CAAC;CAChD;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ;gCACA,qBAAqB,KAAG,OAAO;mCAC5B,qBAAqB,KAAG,OAAO;CAEyB,CAAC;AAEjF,2FAA2F;AAC3F,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,QAAQ,CAAC;AAE7C,mFAAmF;AACnF,eAAO,MAAM,UAAU,EAA4B,SAAS,QAAQ,EAAE,CAAC;AAEvE,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,QAAQ,CAE3D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { LexicalPlanner } from './lexical.js';
|
|
2
|
+
import { StructuralPlanner } from './structural.js';
|
|
3
|
+
/**
|
|
4
|
+
* The one registry of planner strategies — string in, constructed {@link Planner} out.
|
|
5
|
+
*
|
|
6
|
+
* This object is the single place the strategy names live. `createSmelter` builds from
|
|
7
|
+
* it, `--strategy` and `smelt.config.json` validation accept exactly its keys, and the
|
|
8
|
+
* `--help` text renders its keys — so a strategy cannot exist in one of those faces and
|
|
9
|
+
* be missing from another. Before this registry the pair was restated in three places,
|
|
10
|
+
* which is how help text rots.
|
|
11
|
+
*
|
|
12
|
+
* `'structural'` parses every language named in {@link STRUCTURAL_LANGUAGES} with a
|
|
13
|
+
* bundled grammar and throws {@link GrammarUnavailableError} for anything else — never
|
|
14
|
+
* a silent lexical fallback. See {@link StructuralPlanner}.
|
|
15
|
+
*/
|
|
16
|
+
export const PLANNERS = {
|
|
17
|
+
lexical: (options) => new LexicalPlanner(options.lexical ?? {}),
|
|
18
|
+
structural: (options) => new StructuralPlanner(options.structural ?? {}),
|
|
19
|
+
};
|
|
20
|
+
/** The registry's keys, in declaration order, for help text and error messages. */
|
|
21
|
+
export const STRATEGIES = Object.keys(PLANNERS);
|
|
22
|
+
/** The one membership test `--strategy` and config validation both use. */
|
|
23
|
+
export function isStrategy(value) {
|
|
24
|
+
return Object.hasOwn(PLANNERS, value);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=planners.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planners.js","sourceRoot":"","sources":["../../src/plan/planners.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAYpD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,CAAC,OAA8B,EAAW,EAAE,CAAC,IAAI,cAAc,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IAC/F,UAAU,EAAE,CAAC,OAA8B,EAAW,EAAE,CACtD,IAAI,iBAAiB,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;CAC6B,CAAC;AAKjF,mFAAmF;AACnF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAwB,CAAC;AAEvE,2EAA2E;AAC3E,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ElisionPlan, LanguageId, PlanInput, Planner } from '../types.ts';
|
|
2
|
+
export declare const STRUCTURAL_PLANNER_ID = "structural/v1";
|
|
3
|
+
/**
|
|
4
|
+
* The languages this planner actually parses — a derived view of the registry: every
|
|
5
|
+
* {@link LanguageProfile} that carries a `structure` section, in registry order. A
|
|
6
|
+
* language appears here only once its node kinds are mapped in its profile
|
|
7
|
+
* (`src/lang/<id>.ts`), because claiming a language before that would produce markers
|
|
8
|
+
* that mislabel what they collapsed.
|
|
9
|
+
*
|
|
10
|
+
* Exported for the totality guard (`test/guards/structural-totality.test.ts`): every
|
|
11
|
+
* language named here must have a fixture, a snapshot and a doc-comment case, so a
|
|
12
|
+
* language cannot be claimed without tests.
|
|
13
|
+
*/
|
|
14
|
+
export declare const STRUCTURAL_LANGUAGES: readonly LanguageId[];
|
|
15
|
+
/**
|
|
16
|
+
* Historically the union of the claimed ids; every `LanguageId` carries a profile
|
|
17
|
+
* now, so the compile-time totality this type enforced lives on the registry
|
|
18
|
+
* (`Record<LanguageId, LanguageProfile>`) instead.
|
|
19
|
+
*/
|
|
20
|
+
export type StructuralLanguage = LanguageId;
|
|
21
|
+
export interface StructuralPlannerOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Never collapse a sibling group smaller than this. Defaults to 1 — the byte
|
|
24
|
+
* profitability check already refuses collapses that would not pay for their marker.
|
|
25
|
+
*/
|
|
26
|
+
readonly minSiblings?: number;
|
|
27
|
+
/** Focus matching is substring, case-insensitive by default — same as lexical. */
|
|
28
|
+
readonly caseSensitive?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The structural planner — the reason smelt exists.
|
|
32
|
+
*
|
|
33
|
+
* It parses with the language's tree-sitter grammar, finds the top-level declarations
|
|
34
|
+
* whose text matches the caller's focus, keeps each match whole — signature line,
|
|
35
|
+
* attached doc comment, body — and collapses each contiguous run of non-matching
|
|
36
|
+
* *siblings* into one marker that names them from the parse tree: `collapsed 3 sibling
|
|
37
|
+
* functions`. Structure is what makes that explanation possible; a line window can only
|
|
38
|
+
* ever say "collapsed 40 lines".
|
|
39
|
+
*
|
|
40
|
+
* It throws {@link GrammarUnavailableError} rather than falling back to the lexical
|
|
41
|
+
* planner, and that is the deliberate part. A silent fallback would mean a caller who
|
|
42
|
+
* asked for structural planning, and whose grammar failed to load, gets line-window
|
|
43
|
+
* output labelled `structural/v1` — plausible, wrong, and undetectable from the
|
|
44
|
+
* outside. A caller who wants the fallback asks for it, by planning lexically itself.
|
|
45
|
+
*/
|
|
46
|
+
export declare class StructuralPlanner implements Planner {
|
|
47
|
+
readonly id = "structural/v1";
|
|
48
|
+
readonly options: StructuralPlannerOptions;
|
|
49
|
+
constructor(options?: StructuralPlannerOptions);
|
|
50
|
+
plan(input: PlanInput): Promise<ElisionPlan>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The planner as a function, exported like {@link planLexical} so it can be tested and
|
|
54
|
+
* reused directly. Deterministic: same text, same language, same focus, same options —
|
|
55
|
+
* byte-identical plan.
|
|
56
|
+
*
|
|
57
|
+
* `budgetBytes` is a target, not a guarantee, for the same reason it is in the lexical
|
|
58
|
+
* planner: once every non-matching sibling run is collapsed there is nothing left to
|
|
59
|
+
* cut except the declarations the caller asked to keep, and an optimizer that silently
|
|
60
|
+
* drops the thing you searched for is the exact failure this design refuses. Callers
|
|
61
|
+
* who need a hard ceiling check `outputBytes` and decide.
|
|
62
|
+
*
|
|
63
|
+
* @throws {GrammarUnavailableError} when the language is not one this planner parses,
|
|
64
|
+
* when the grammar cannot be loaded, or when the parser produces no tree. Never a
|
|
65
|
+
* lexical fallback.
|
|
66
|
+
*/
|
|
67
|
+
export declare function planStructural(input: PlanInput, options?: StructuralPlannerOptions): Promise<ElisionPlan>;
|
|
68
|
+
//# sourceMappingURL=structural.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structural.d.ts","sourceRoot":"","sources":["../../src/plan/structural.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EAEV,SAAS,EAET,OAAO,EACR,MAAM,aAAa,CAAC;AAIrB,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,UAAU,EAA0B,CAAC;AAEjF;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAQ5C,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC;AA+BD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,YAAW,OAAO;IAC/C,QAAQ,CAAC,EAAE,mBAAyB;IACpC,QAAQ,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAE3C,YAAY,OAAO,GAAE,wBAA6B,EAEjD;IAED,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAE3C;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,WAAW,CAAC,CA8BtB"}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import { Parser } from 'web-tree-sitter';
|
|
2
|
+
import { GrammarUnavailableError, MissingMarkerPricingError } from '../errors.js';
|
|
3
|
+
import { profileFor, structuralLanguages } from '../lang/registry.js';
|
|
4
|
+
import { loadGrammar } from './grammar.js';
|
|
5
|
+
export const STRUCTURAL_PLANNER_ID = 'structural/v1';
|
|
6
|
+
/**
|
|
7
|
+
* The languages this planner actually parses — a derived view of the registry: every
|
|
8
|
+
* {@link LanguageProfile} that carries a `structure` section, in registry order. A
|
|
9
|
+
* language appears here only once its node kinds are mapped in its profile
|
|
10
|
+
* (`src/lang/<id>.ts`), because claiming a language before that would produce markers
|
|
11
|
+
* that mislabel what they collapsed.
|
|
12
|
+
*
|
|
13
|
+
* Exported for the totality guard (`test/guards/structural-totality.test.ts`): every
|
|
14
|
+
* language named here must have a fixture, a snapshot and a doc-comment case, so a
|
|
15
|
+
* language cannot be claimed without tests.
|
|
16
|
+
*/
|
|
17
|
+
export const STRUCTURAL_LANGUAGES = structuralLanguages();
|
|
18
|
+
/**
|
|
19
|
+
* Every elision this planner produces carries this rule id, and the profitability
|
|
20
|
+
* check below prices the marker that rule would earn — so the two must not drift.
|
|
21
|
+
*/
|
|
22
|
+
const SIBLING_COLLAPSE_RULE = 'sibling-collapse';
|
|
23
|
+
/**
|
|
24
|
+
* The structural planner — the reason smelt exists.
|
|
25
|
+
*
|
|
26
|
+
* It parses with the language's tree-sitter grammar, finds the top-level declarations
|
|
27
|
+
* whose text matches the caller's focus, keeps each match whole — signature line,
|
|
28
|
+
* attached doc comment, body — and collapses each contiguous run of non-matching
|
|
29
|
+
* *siblings* into one marker that names them from the parse tree: `collapsed 3 sibling
|
|
30
|
+
* functions`. Structure is what makes that explanation possible; a line window can only
|
|
31
|
+
* ever say "collapsed 40 lines".
|
|
32
|
+
*
|
|
33
|
+
* It throws {@link GrammarUnavailableError} rather than falling back to the lexical
|
|
34
|
+
* planner, and that is the deliberate part. A silent fallback would mean a caller who
|
|
35
|
+
* asked for structural planning, and whose grammar failed to load, gets line-window
|
|
36
|
+
* output labelled `structural/v1` — plausible, wrong, and undetectable from the
|
|
37
|
+
* outside. A caller who wants the fallback asks for it, by planning lexically itself.
|
|
38
|
+
*/
|
|
39
|
+
export class StructuralPlanner {
|
|
40
|
+
id = STRUCTURAL_PLANNER_ID;
|
|
41
|
+
options;
|
|
42
|
+
constructor(options = {}) {
|
|
43
|
+
this.options = options;
|
|
44
|
+
}
|
|
45
|
+
plan(input) {
|
|
46
|
+
return planStructural(input, this.options);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The planner as a function, exported like {@link planLexical} so it can be tested and
|
|
51
|
+
* reused directly. Deterministic: same text, same language, same focus, same options —
|
|
52
|
+
* byte-identical plan.
|
|
53
|
+
*
|
|
54
|
+
* `budgetBytes` is a target, not a guarantee, for the same reason it is in the lexical
|
|
55
|
+
* planner: once every non-matching sibling run is collapsed there is nothing left to
|
|
56
|
+
* cut except the declarations the caller asked to keep, and an optimizer that silently
|
|
57
|
+
* drops the thing you searched for is the exact failure this design refuses. Callers
|
|
58
|
+
* who need a hard ceiling check `outputBytes` and decide.
|
|
59
|
+
*
|
|
60
|
+
* @throws {GrammarUnavailableError} when the language is not one this planner parses,
|
|
61
|
+
* when the grammar cannot be loaded, or when the parser produces no tree. Never a
|
|
62
|
+
* lexical fallback.
|
|
63
|
+
*/
|
|
64
|
+
export async function planStructural(input, options = {}) {
|
|
65
|
+
const language = assertStructuralLanguage(input.language);
|
|
66
|
+
// The runtime backstop for JS callers: TypeScript makes `pricing` required, but a
|
|
67
|
+
// JS caller can omit it, and the honest answer is a named refusal rather than the
|
|
68
|
+
// planner quietly pricing markers itself — the inversion the seam removed.
|
|
69
|
+
const pricing = input.pricing;
|
|
70
|
+
if (pricing === undefined)
|
|
71
|
+
throw new MissingMarkerPricingError(STRUCTURAL_PLANNER_ID);
|
|
72
|
+
const grammar = await loadGrammar(language);
|
|
73
|
+
const parser = new Parser();
|
|
74
|
+
let tree = null;
|
|
75
|
+
try {
|
|
76
|
+
parser.setLanguage(grammar);
|
|
77
|
+
tree = parser.parse(input.text);
|
|
78
|
+
if (tree === null) {
|
|
79
|
+
throw new GrammarUnavailableError(`smelt: the ${language} parser returned no tree. Structural planning cannot ` +
|
|
80
|
+
`proceed, and it does not fall back to lexical — a caller who wants the ` +
|
|
81
|
+
`fallback plans lexically itself.`);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
planner: STRUCTURAL_PLANNER_ID,
|
|
85
|
+
language: input.language,
|
|
86
|
+
elisions: planFromTree(tree, input, options, language),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
tree?.delete();
|
|
91
|
+
parser.delete();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function assertStructuralLanguage(language) {
|
|
95
|
+
for (const supported of STRUCTURAL_LANGUAGES) {
|
|
96
|
+
if (language === supported)
|
|
97
|
+
return supported;
|
|
98
|
+
}
|
|
99
|
+
const named = `${STRUCTURAL_LANGUAGES.slice(0, -1).join(', ')} and ${STRUCTURAL_LANGUAGES[STRUCTURAL_LANGUAGES.length - 1]}`;
|
|
100
|
+
throw new GrammarUnavailableError(`smelt: structural planning covers ${named} in this ` +
|
|
101
|
+
`slice; got "${language}". It does not fall back to the lexical planner — output ` +
|
|
102
|
+
`labelled structural/v1 that is really line windows would be undetectable from ` +
|
|
103
|
+
`the outside. Use the lexical planner explicitly if that is what you want.`);
|
|
104
|
+
}
|
|
105
|
+
function planFromTree(tree, input, options, language) {
|
|
106
|
+
const profile = profileFor(language);
|
|
107
|
+
// assertStructuralLanguage admits only languages whose profile carries a
|
|
108
|
+
// `structure` section — that is the definition of a structural language — so the
|
|
109
|
+
// assertion states a fact the seam already proved.
|
|
110
|
+
const structure = profile.structure;
|
|
111
|
+
const pricing = input.pricing;
|
|
112
|
+
// The marker lands as a line comment in every structural language (the profile's
|
|
113
|
+
// markerLeader), and a line comment comments out everything to the end of its
|
|
114
|
+
// line — so a collapse is only legal where nothing kept follows on the marker's
|
|
115
|
+
// own line. See the flush below.
|
|
116
|
+
const markerIsLineComment = profile.markerLeader !== undefined;
|
|
117
|
+
const units = unitsOf(tree.rootNode, input.text, structure);
|
|
118
|
+
const matched = matchUnits(units, input, options);
|
|
119
|
+
const minSiblings = options.minSiblings ?? 1;
|
|
120
|
+
const toByte = utf8OffsetIndex(input.text, units.flatMap((unit) => [unit.start, unit.end]));
|
|
121
|
+
const elisions = [];
|
|
122
|
+
let run = [];
|
|
123
|
+
const flush = () => {
|
|
124
|
+
if (run.length === 0)
|
|
125
|
+
return;
|
|
126
|
+
const group = run;
|
|
127
|
+
run = [];
|
|
128
|
+
if (group.length < minSiblings)
|
|
129
|
+
return;
|
|
130
|
+
// A line-comment marker swallows the rest of its line. When the run's last unit
|
|
131
|
+
// ends mid-line — python's `stmt_a(); stmt_b()` puts two top-level statements on
|
|
132
|
+
// one line — the marker's `# ` leader would comment out the *kept* code after it.
|
|
133
|
+
// Refusing the collapse is the honest move; extending the range would elide code
|
|
134
|
+
// no unit accounted for.
|
|
135
|
+
if (markerIsLineComment && !restOfLineIsBlank(input.text, group[group.length - 1].end)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const start = toByte.get(group[0].start);
|
|
139
|
+
const end = toByte.get(group[group.length - 1].end);
|
|
140
|
+
const cutBytes = end - start;
|
|
141
|
+
const explanation = explain(group);
|
|
142
|
+
// Profitability, priced rather than estimated: ask the MarkerPricing seam for the
|
|
143
|
+
// exact cost of the marker this cut would earn — the explanation's length varies
|
|
144
|
+
// with kind diversity, and the pricing carries the language's comment leader (or a
|
|
145
|
+
// caller's custom builder), so a fixed estimate can pass a cut whose marker is
|
|
146
|
+
// bigger than what it removes, and a marker that costs more than it removes grows
|
|
147
|
+
// the output.
|
|
148
|
+
const markerBytes = pricing.costBytes({ rule: SIBLING_COLLAPSE_RULE, explanation }, cutBytes);
|
|
149
|
+
if (cutBytes <= markerBytes)
|
|
150
|
+
return;
|
|
151
|
+
elisions.push({
|
|
152
|
+
range: { start, end },
|
|
153
|
+
reason: { rule: SIBLING_COLLAPSE_RULE, explanation },
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
for (let i = 0; i < units.length; i += 1) {
|
|
157
|
+
if (matched[i] === true || units[i].pinned === true) {
|
|
158
|
+
flush();
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
run.push(units[i]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
flush();
|
|
165
|
+
return elisions;
|
|
166
|
+
}
|
|
167
|
+
/** True when nothing but whitespace follows `index` on its own line. */
|
|
168
|
+
function restOfLineIsBlank(text, index) {
|
|
169
|
+
for (let i = index; i < text.length; i += 1) {
|
|
170
|
+
const ch = text[i];
|
|
171
|
+
if (ch === '\n')
|
|
172
|
+
return true;
|
|
173
|
+
if (!/\s/.test(ch))
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Group the root's named children into units: each declaration plus the comment block
|
|
180
|
+
* — and, in rust, the outer attributes — attached to it. A comment attaches when only
|
|
181
|
+
* blank-free whitespace separates it from what follows — one newline at most — so a doc
|
|
182
|
+
* comment travels with its declaration, while a comment left floating above a blank
|
|
183
|
+
* line stands alone.
|
|
184
|
+
*
|
|
185
|
+
* Attributes attach *unconditionally*: tree-sitter-rust parses `#[inline]` as a
|
|
186
|
+
* top-level sibling of the item it decorates, but the language's own rule is that an
|
|
187
|
+
* outer attribute modifies the next item, blank lines or not. So once an attribute is
|
|
188
|
+
* pending, the whole pending prefix (doc comments included) rides forward to the next
|
|
189
|
+
* declaration — treating it as its own unit would let a collapse strip `#[derive(…)]`
|
|
190
|
+
* and the doc comment above it off a kept declaration.
|
|
191
|
+
*/
|
|
192
|
+
function unitsOf(root, text, structure) {
|
|
193
|
+
const units = [];
|
|
194
|
+
/** Comments and attributes waiting to attach to the next declaration. */
|
|
195
|
+
let pending = [];
|
|
196
|
+
/** Once true, blank lines no longer detach the pending prefix — see above. */
|
|
197
|
+
let pendingHasAttribute = false;
|
|
198
|
+
const flushPending = () => {
|
|
199
|
+
if (pending.length === 0)
|
|
200
|
+
return;
|
|
201
|
+
units.push({
|
|
202
|
+
start: pending[0].startIndex,
|
|
203
|
+
end: pending[pending.length - 1].endIndex,
|
|
204
|
+
kind: pendingHasAttribute ? 'attribute' : 'comment',
|
|
205
|
+
pinned: !pendingHasAttribute && pending.some((node) => pinnedComment(node, text, structure)),
|
|
206
|
+
});
|
|
207
|
+
pending = [];
|
|
208
|
+
pendingHasAttribute = false;
|
|
209
|
+
};
|
|
210
|
+
for (const child of root.namedChildren) {
|
|
211
|
+
if (child === null)
|
|
212
|
+
continue;
|
|
213
|
+
if (structure.ridesBackwardTypes?.has(child.type) === true && units.length > 0) {
|
|
214
|
+
// A node that is grammatically part of the *previous* statement, parsed as a
|
|
215
|
+
// top-level sibling: tree-sitter-ruby emits a heredoc's body as a sibling of
|
|
216
|
+
// the statement holding its `<<~SQL` opener. Splitting them lets a collapse
|
|
217
|
+
// keep the opener and cut the body — an unterminated heredoc that swallows
|
|
218
|
+
// every kept declaration after it, without a single ERROR node to show for
|
|
219
|
+
// it. The body extends the preceding unit instead, so opener and body are
|
|
220
|
+
// kept whole or collapsed whole, always.
|
|
221
|
+
flushPending();
|
|
222
|
+
const last = units[units.length - 1];
|
|
223
|
+
units[units.length - 1] = { ...last, end: child.endIndex };
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (structure.pinnedTypes?.has(child.type) === true ||
|
|
227
|
+
pinnedDirective(child, text, structure)) {
|
|
228
|
+
// A pinned node (php's `<?php` tag, a `#!` shebang line, c's `#pragma once`)
|
|
229
|
+
// is its own uncollapsible unit — nothing attaches to it, and no run may
|
|
230
|
+
// swallow it.
|
|
231
|
+
flushPending();
|
|
232
|
+
units.push({
|
|
233
|
+
start: child.startIndex,
|
|
234
|
+
end: child.endIndex,
|
|
235
|
+
kind: kindOf(child, structure),
|
|
236
|
+
pinned: true,
|
|
237
|
+
});
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const isComment = structure.commentTypes.has(child.type);
|
|
241
|
+
const isAttribute = structure.attributeTypes.has(child.type);
|
|
242
|
+
if (isComment || isAttribute) {
|
|
243
|
+
if (pending.length > 0 &&
|
|
244
|
+
!pendingHasAttribute &&
|
|
245
|
+
!adjacent(text, pending[pending.length - 1].endIndex, child.startIndex)) {
|
|
246
|
+
flushPending();
|
|
247
|
+
}
|
|
248
|
+
pending.push(child);
|
|
249
|
+
pendingHasAttribute ||= isAttribute;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
// tree-sitter-kotlin extends the import_list node over a doc comment that
|
|
253
|
+
// follows it, so the KDoc of the first documented declaration after the imports
|
|
254
|
+
// would be collapsed *with the imports* — a kept declaration losing its attached
|
|
255
|
+
// doc comment. Split such trailing comments off: the unit ends at its last
|
|
256
|
+
// non-comment token, and the comments ride forward like any other pending block.
|
|
257
|
+
const { end: childEnd, trailing } = structure.trailingCommentSplitTypes?.has(child.type) === true
|
|
258
|
+
? splitTrailingComments(child, structure)
|
|
259
|
+
: { end: child.endIndex, trailing: [] };
|
|
260
|
+
const attached = pending.length > 0 &&
|
|
261
|
+
(pendingHasAttribute ||
|
|
262
|
+
adjacent(text, pending[pending.length - 1].endIndex, child.startIndex));
|
|
263
|
+
if (attached && pending.some((node) => pinnedComment(node, text, structure))) {
|
|
264
|
+
// A pinned comment (`//go:build`) governs the file, not the declaration it
|
|
265
|
+
// happens to touch — keep it a standalone, uncollapsible unit either way.
|
|
266
|
+
flushPending();
|
|
267
|
+
units.push({
|
|
268
|
+
start: child.startIndex,
|
|
269
|
+
end: childEnd,
|
|
270
|
+
kind: kindOf(child, structure),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
else if (attached) {
|
|
274
|
+
units.push({
|
|
275
|
+
start: pending[0].startIndex,
|
|
276
|
+
end: childEnd,
|
|
277
|
+
kind: kindOf(child, structure),
|
|
278
|
+
});
|
|
279
|
+
pending = [];
|
|
280
|
+
pendingHasAttribute = false;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
flushPending();
|
|
284
|
+
units.push({
|
|
285
|
+
start: child.startIndex,
|
|
286
|
+
end: childEnd,
|
|
287
|
+
kind: kindOf(child, structure),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
for (const comment of trailing)
|
|
291
|
+
pending.push(comment);
|
|
292
|
+
}
|
|
293
|
+
flushPending();
|
|
294
|
+
return units;
|
|
295
|
+
}
|
|
296
|
+
/** Whether this comment node is one the language pins to the file. See {@link Unit}. */
|
|
297
|
+
function pinnedComment(node, text, structure) {
|
|
298
|
+
if (structure.pinnedCommentPattern === undefined)
|
|
299
|
+
return false;
|
|
300
|
+
if (!structure.commentTypes.has(node.type))
|
|
301
|
+
return false;
|
|
302
|
+
return structure.pinnedCommentPattern.test(text.slice(node.startIndex, node.endIndex));
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Whether this non-comment node is pinned by a per-type text pattern. C's
|
|
306
|
+
* `#pragma once` is a `preproc_call` like any other pragma, but collapsing it
|
|
307
|
+
* silently changes header inclusion semantics — the same class as `//go:build`, on a
|
|
308
|
+
* node kind a comment pattern cannot reach.
|
|
309
|
+
*/
|
|
310
|
+
function pinnedDirective(node, text, structure) {
|
|
311
|
+
const pattern = structure.pinnedPatternsByType?.[node.type];
|
|
312
|
+
if (pattern === undefined)
|
|
313
|
+
return false;
|
|
314
|
+
return pattern.test(text.slice(node.startIndex, node.endIndex));
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* The end of `node`'s last non-comment token, and every comment node after it. Used
|
|
318
|
+
* for node types the grammar extends over comments that belong to what follows —
|
|
319
|
+
* kotlin's import_list swallowing the next declaration's KDoc.
|
|
320
|
+
*/
|
|
321
|
+
function splitTrailingComments(node, structure) {
|
|
322
|
+
const comments = [];
|
|
323
|
+
let end = node.startIndex;
|
|
324
|
+
const walk = (current) => {
|
|
325
|
+
if (structure.commentTypes.has(current.type)) {
|
|
326
|
+
comments.push(current);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
let hasChildren = false;
|
|
330
|
+
for (const child of current.children) {
|
|
331
|
+
if (child === null)
|
|
332
|
+
continue;
|
|
333
|
+
hasChildren = true;
|
|
334
|
+
walk(child);
|
|
335
|
+
}
|
|
336
|
+
if (!hasChildren && current.endIndex > end)
|
|
337
|
+
end = current.endIndex;
|
|
338
|
+
};
|
|
339
|
+
for (const child of node.children) {
|
|
340
|
+
if (child !== null)
|
|
341
|
+
walk(child);
|
|
342
|
+
}
|
|
343
|
+
return { end, trailing: comments.filter((comment) => comment.startIndex >= end) };
|
|
344
|
+
}
|
|
345
|
+
/** Nothing but whitespace between the two indices, and at most one newline. */
|
|
346
|
+
function adjacent(text, end, start) {
|
|
347
|
+
const between = text.slice(end, start);
|
|
348
|
+
if (!/^\s*$/.test(between))
|
|
349
|
+
return false;
|
|
350
|
+
return (between.match(/\n/g) ?? []).length <= 1;
|
|
351
|
+
}
|
|
352
|
+
function matchUnits(units, input, options) {
|
|
353
|
+
const caseSensitive = options.caseSensitive ?? false;
|
|
354
|
+
const focus = (input.focus ?? []).filter((term) => term.length > 0);
|
|
355
|
+
const needles = caseSensitive ? focus : focus.map((term) => term.toLowerCase());
|
|
356
|
+
return units.map((unit) => {
|
|
357
|
+
if (needles.length === 0)
|
|
358
|
+
return false;
|
|
359
|
+
const raw = input.text.slice(unit.start, unit.end);
|
|
360
|
+
const haystack = caseSensitive ? raw : raw.toLowerCase();
|
|
361
|
+
return needles.some((needle) => haystack.includes(needle));
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Law 2, for this rule: the explanation names the *kind* and the *count*, read off the
|
|
366
|
+
* parse tree — `collapsed 3 sibling functions` — never a line count as the claim. A
|
|
367
|
+
* mixed run says what it mixed: `collapsed 4 sibling declarations (3 functions,
|
|
368
|
+
* 1 class)` — and when the run holds anything that is not a declaration (a statement,
|
|
369
|
+
* a floating comment, an unparsed region), the heading says `nodes`, because calling
|
|
370
|
+
* a parse error a declaration would be the marker lying about the tree.
|
|
371
|
+
*/
|
|
372
|
+
function explain(group) {
|
|
373
|
+
const counts = new Map();
|
|
374
|
+
for (const unit of group)
|
|
375
|
+
counts.set(unit.kind, (counts.get(unit.kind) ?? 0) + 1);
|
|
376
|
+
const total = group.length;
|
|
377
|
+
if (counts.size === 1) {
|
|
378
|
+
const kind = group[0].kind;
|
|
379
|
+
return `collapsed ${String(total)} sibling ${countNoun(kind, total)}`;
|
|
380
|
+
}
|
|
381
|
+
const parts = [...counts.entries()].map(([kind, count]) => `${String(count)} ${countNoun(kind, count)}`);
|
|
382
|
+
const heading = [...counts.keys()].every((kind) => !NON_DECLARATION_KINDS.has(kind))
|
|
383
|
+
? 'declarations'
|
|
384
|
+
: 'nodes';
|
|
385
|
+
return `collapsed ${String(total)} sibling ${heading} (${parts.join(', ')})`;
|
|
386
|
+
}
|
|
387
|
+
/** The kind labels that are not declarations, so a mixed heading never overclaims. */
|
|
388
|
+
const NON_DECLARATION_KINDS = new Set([
|
|
389
|
+
'statement',
|
|
390
|
+
'comment',
|
|
391
|
+
'unparsed region',
|
|
392
|
+
'package clause',
|
|
393
|
+
'package header',
|
|
394
|
+
'package declaration',
|
|
395
|
+
'attribute',
|
|
396
|
+
'command',
|
|
397
|
+
'variable assignment',
|
|
398
|
+
'include directive',
|
|
399
|
+
'shebang',
|
|
400
|
+
'php tag',
|
|
401
|
+
'html section',
|
|
402
|
+
'heredoc body',
|
|
403
|
+
'preprocessor directive',
|
|
404
|
+
'preprocessor conditional',
|
|
405
|
+
]);
|
|
406
|
+
function countNoun(kind, count) {
|
|
407
|
+
if (count === 1)
|
|
408
|
+
return kind;
|
|
409
|
+
if (/[^aeiou]y$/.test(kind))
|
|
410
|
+
return `${kind.slice(0, -1)}ies`;
|
|
411
|
+
return /(?:s|sh|ch)$/.test(kind) ? `${kind}es` : `${kind}s`;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* The kind of a declaration, unwrapping wrappers (`export …`, `@decorator`) so the
|
|
415
|
+
* marker names what it hides. What the language's map does not name is still labelled
|
|
416
|
+
* honestly — see {@link LanguageStructure.kindLabels} for the labelling rules.
|
|
417
|
+
*/
|
|
418
|
+
function kindOf(node, structure) {
|
|
419
|
+
const wrapperFallback = structure.wrapperTypes[node.type];
|
|
420
|
+
if (wrapperFallback !== undefined) {
|
|
421
|
+
for (const child of node.namedChildren) {
|
|
422
|
+
if (child === null || structure.commentTypes.has(child.type))
|
|
423
|
+
continue;
|
|
424
|
+
const label = structure.kindLabels[child.type];
|
|
425
|
+
if (label !== undefined)
|
|
426
|
+
return label;
|
|
427
|
+
}
|
|
428
|
+
return wrapperFallback;
|
|
429
|
+
}
|
|
430
|
+
const label = structure.kindLabels[node.type];
|
|
431
|
+
if (label !== undefined)
|
|
432
|
+
return label;
|
|
433
|
+
if (node.type === 'ERROR')
|
|
434
|
+
return 'unparsed region';
|
|
435
|
+
if (node.type.endsWith('_statement') || node.type === 'statement_block')
|
|
436
|
+
return 'statement';
|
|
437
|
+
return 'declaration';
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
*
|
|
441
|
+
* web-tree-sitter reports positions in code units of the JS string it parsed;
|
|
442
|
+
* {@link ElisionPlan} ranges are UTF-8 bytes. Because every converted index is a parse
|
|
443
|
+
* node boundary, a range can never split a multi-byte character — a node boundary is
|
|
444
|
+
* always a character boundary. One forward pass, so the conversion is linear.
|
|
445
|
+
*/
|
|
446
|
+
function utf8OffsetIndex(text, indices) {
|
|
447
|
+
const sorted = [...new Set(indices)].toSorted((a, b) => a - b);
|
|
448
|
+
const map = new Map();
|
|
449
|
+
let previousIndex = 0;
|
|
450
|
+
let previousByte = 0;
|
|
451
|
+
for (const index of sorted) {
|
|
452
|
+
previousByte += Buffer.byteLength(text.slice(previousIndex, index), 'utf8');
|
|
453
|
+
previousIndex = index;
|
|
454
|
+
map.set(index, previousByte);
|
|
455
|
+
}
|
|
456
|
+
return map;
|
|
457
|
+
}
|
|
458
|
+
//# sourceMappingURL=structural.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structural.js","sourceRoot":"","sources":["../../src/plan/structural.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAGzC,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAElF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAUtE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAe,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA0B,mBAAmB,EAAE,CAAC;AASjF;;;GAGG;AACH,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAyCjD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,iBAAiB;IACnB,EAAE,GAAG,qBAAqB,CAAC;IAC3B,OAAO,CAA2B;IAE3C,YAAY,OAAO,GAA6B,EAAE;QAChD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,KAAgB;QACnB,OAAO,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAgB,EAChB,OAAO,GAA6B,EAAE;IAEtC,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC1D,kFAAkF;IAClF,kFAAkF;IAClF,2EAA2E;IAC3E,MAAM,OAAO,GAA8B,KAAK,CAAC,OAAO,CAAC;IACzD,IAAI,OAAO,KAAK,SAAS;QAAE,MAAM,IAAI,yBAAyB,CAAC,qBAAqB,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAC5B,IAAI,IAAI,GAAgB,IAAI,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC5B,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,uBAAuB,CAC/B,cAAc,QAAQ,uDAAuD;gBAC3E,yEAAyE;gBACzE,kCAAkC,CACrC,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,qBAAqB;YAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC;SACvD,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,CAAC,MAAM,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,QAA+B;IAC/D,KAAK,MAAM,SAAS,IAAI,oBAAoB,EAAE,CAAC;QAC7C,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;IAC/C,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAC3D,oBAAoB,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,CACtD,EAAE,CAAC;IACH,MAAM,IAAI,uBAAuB,CAC/B,qCAAqC,KAAK,WAAW;QACnD,eAAe,QAAQ,2DAA2D;QAClF,gFAAgF;QAChF,2EAA2E,CAC9E,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,IAAU,EACV,KAAgB,EAChB,OAAiC,EACjC,QAA4B;IAE5B,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACrC,yEAAyE;IACzE,iFAAiF;IACjF,mDAAmD;IACnD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAU,CAAC;IACrC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,iFAAiF;IACjF,8EAA8E;IAC9E,gFAAgF;IAChF,iCAAiC;IACjC,MAAM,mBAAmB,GAAG,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,eAAe,CAC5B,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAChD,CAAC;IAEF,MAAM,QAAQ,GAAqB,EAAE,CAAC;IACtC,IAAI,GAAG,GAAW,EAAE,CAAC;IAErB,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC7B,MAAM,KAAK,GAAG,GAAG,CAAC;QAClB,GAAG,GAAG,EAAE,CAAC;QACT,IAAI,KAAK,CAAC,MAAM,GAAG,WAAW;YAAE,OAAO;QACvC,gFAAgF;QAChF,iFAAiF;QACjF,kFAAkF;QAClF,iFAAiF;QACjF,yBAAyB;QACzB,IAAI,mBAAmB,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACxF,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,KAAK,CAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,CAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC;QAC7B,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QACnC,kFAAkF;QAClF,iFAAiF;QACjF,mFAAmF;QACnF,+EAA+E;QAC/E,kFAAkF;QAClF,cAAc;QACd,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC9F,IAAI,QAAQ,IAAI,WAAW;YAAE,OAAO;QACpC,QAAQ,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;YACrB,MAAM,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE;SACrD,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAE,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACrD,KAAK,EAAE,CAAC;QACV,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,KAAK,EAAE,CAAC;IACR,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,wEAAwE;AACxE,SAAS,iBAAiB,CAAC,IAAY,EAAE,KAAa;IACpD,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACpB,IAAI,EAAE,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,OAAO,CAAC,IAAU,EAAE,IAAY,EAAE,SAA4B;IACrE,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,yEAAyE;IACzE,IAAI,OAAO,GAAW,EAAE,CAAC;IACzB,8EAA8E;IAC9E,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAEhC,MAAM,YAAY,GAAG,GAAS,EAAE;QAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACjC,KAAK,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,OAAO,CAAC,CAAC,CAAE,CAAC,UAAU;YAC7B,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,QAAQ;YAC1C,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;YACnD,MAAM,EAAE,CAAC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;SAC7F,CAAC,CAAC;QACH,OAAO,GAAG,EAAE,CAAC;QACb,mBAAmB,GAAG,KAAK,CAAC;IAC9B,CAAC,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvC,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,IAAI,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/E,6EAA6E;YAC7E,6EAA6E;YAC7E,4EAA4E;YAC5E,2EAA2E;YAC3E,2EAA2E;YAC3E,0EAA0E;YAC1E,yCAAyC;YACzC,YAAY,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;YACtC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC3D,SAAS;QACX,CAAC;QACD,IACE,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI;YAC/C,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,EACvC,CAAC;YACD,6EAA6E;YAC7E,yEAAyE;YACzE,cAAc;YACd,YAAY,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK,EAAE,KAAK,CAAC,UAAU;gBACvB,GAAG,EAAE,KAAK,CAAC,QAAQ;gBACnB,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC;gBAC9B,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7D,IAAI,SAAS,IAAI,WAAW,EAAE,CAAC;YAC7B,IACE,OAAO,CAAC,MAAM,GAAG,CAAC;gBAClB,CAAC,mBAAmB;gBACpB,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,EACxE,CAAC;gBACD,YAAY,EAAE,CAAC;YACjB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,mBAAmB,KAAK,WAAW,CAAC;YACpC,SAAS;QACX,CAAC;QAED,0EAA0E;QAC1E,gFAAgF;QAChF,iFAAiF;QACjF,2EAA2E;QAC3E,iFAAiF;QACjF,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAC/B,SAAS,CAAC,yBAAyB,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI;YAC3D,CAAC,CAAC,qBAAqB,CAAC,KAAK,EAAE,SAAS,CAAC;YACzC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAE5C,MAAM,QAAQ,GACZ,OAAO,CAAC,MAAM,GAAG,CAAC;YAClB,CAAC,mBAAmB;gBAClB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QAC7E,IAAI,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;YAC7E,2EAA2E;YAC3E,0EAA0E;YAC1E,YAAY,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK,EAAE,KAAK,CAAC,UAAU;gBACvB,GAAG,EAAE,QAAQ;gBACb,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK,EAAE,OAAO,CAAC,CAAC,CAAE,CAAC,UAAU;gBAC7B,GAAG,EAAE,QAAQ;gBACb,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC;aAC/B,CAAC,CAAC;YACH,OAAO,GAAG,EAAE,CAAC;YACb,mBAAmB,GAAG,KAAK,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,YAAY,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK,EAAE,KAAK,CAAC,UAAU;gBACvB,GAAG,EAAE,QAAQ;gBACb,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,QAAQ;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;IACD,YAAY,EAAE,CAAC;IACf,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wFAAwF;AACxF,SAAS,aAAa,CAAC,IAAU,EAAE,IAAY,EAAE,SAA4B;IAC3E,IAAI,SAAS,CAAC,oBAAoB,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC/D,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,OAAO,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzF,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAAU,EAAE,IAAY,EAAE,SAA4B;IAC7E,MAAM,OAAO,GAAG,SAAS,CAAC,oBAAoB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAC5B,IAAU,EACV,SAA4B;IAE5B,MAAM,QAAQ,GAAW,EAAE,CAAC;IAC5B,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;IAC1B,MAAM,IAAI,GAAG,CAAC,OAAa,EAAQ,EAAE;QACnC,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrC,IAAI,KAAK,KAAK,IAAI;gBAAE,SAAS;YAC7B,WAAW,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,GAAG;YAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;IACrE,CAAC,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,IAAI,KAAK,KAAK,IAAI;YAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,IAAI,GAAG,CAAC,EAAE,CAAC;AACpF,CAAC;AAED,+EAA+E;AAC/E,SAAS,QAAQ,CAAC,IAAY,EAAE,GAAW,EAAE,KAAa;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,UAAU,CACjB,KAAsB,EACtB,KAAgB,EAChB,OAAiC;IAEjC,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,KAAK,CAAC;IACrD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAEhF,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACvC,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QACzD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,OAAO,CAAC,KAAsB;IACrC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAElF,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;IAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC;QAC5B,OAAO,aAAa,MAAM,CAAC,KAAK,CAAC,YAAY,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;IACxE,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CACrC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAChE,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClF,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,OAAO,CAAC;IACZ,OAAO,aAAa,MAAM,CAAC,KAAK,CAAC,YAAY,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/E,CAAC;AAED,sFAAsF;AACtF,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC;IACzD,WAAW;IACX,SAAS;IACT,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;IAChB,qBAAqB;IACrB,WAAW;IACX,SAAS;IACT,qBAAqB;IACrB,mBAAmB;IACnB,SAAS;IACT,SAAS;IACT,cAAc;IACd,cAAc;IACd,wBAAwB;IACxB,0BAA0B;CAC3B,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,IAAY,EAAE,KAAa;IAC5C,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7B,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9D,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC;AAC9D,CAAC;AAED;;;;GAIG;AACH,SAAS,MAAM,CAAC,IAAU,EAAE,SAA4B;IACtD,MAAM,eAAe,GAAG,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvC,IAAI,KAAK,KAAK,IAAI,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YACvE,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;QACxC,CAAC;QACD,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,iBAAiB,CAAC;IACpD,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,WAAW,CAAC;IAC5F,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,IAAY,EAAE,OAA0B;IAC/D,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,YAAY,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5E,aAAa,GAAG,KAAK,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { FileTags } from './tags.ts';
|
|
2
|
+
import type { LanguageId } from '../types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The repo map's disk cache — per-file tags, keyed by content hash, JSON on disk.
|
|
5
|
+
*
|
|
6
|
+
* Modelled on Aider's repo-map tags cache (https://aider.chat/docs/repomap.html),
|
|
7
|
+
* with one deliberate substitution: Aider persists through SQLite; this repo ships
|
|
8
|
+
* zero new runtime dependencies, so entries are plain JSON files under a directory
|
|
9
|
+
* **the caller explicitly hands in**. smelt never writes outside a store or cache it
|
|
10
|
+
* was handed — no default location, no home-directory guessing.
|
|
11
|
+
*
|
|
12
|
+
* The key is a content hash over the tag-format version, the language, and the file's
|
|
13
|
+
* exact text. That is the whole invalidation story: edit a file and its key changes,
|
|
14
|
+
* so the stale entry is simply never looked up again. Nothing needs a timestamp.
|
|
15
|
+
*
|
|
16
|
+
* A corrupt entry — unparseable JSON, or JSON of the wrong shape — is **discarded
|
|
17
|
+
* loudly, never trusted**: the entry file is deleted, the tags are re-extracted from
|
|
18
|
+
* source, and the caller's result carries a warning naming the file. Trusting a
|
|
19
|
+
* damaged cache would silently drop symbols from the map, which is this project's
|
|
20
|
+
* signature failure mode.
|
|
21
|
+
*/
|
|
22
|
+
/** The format name every cache entry carries. */
|
|
23
|
+
export declare const TAGS_CACHE_FORMAT = "smelt-repomap-tags";
|
|
24
|
+
/** Bump this when the tag shape changes: old entries then miss instead of misleading. */
|
|
25
|
+
export declare const TAGS_CACHE_VERSION = 1;
|
|
26
|
+
/**
|
|
27
|
+
* The cache key for one file's tags. The version and language are part of the hashed
|
|
28
|
+
* material, so a format bump or a re-detected language can never resurrect an entry
|
|
29
|
+
* extracted under different rules.
|
|
30
|
+
*/
|
|
31
|
+
export declare function tagsCacheKey(language: LanguageId, content: string): string;
|
|
32
|
+
/** What `read()` reports about one lookup. */
|
|
33
|
+
export type TagsCacheLookup = FileTags | 'corrupt' | undefined;
|
|
34
|
+
export declare class TagsCache {
|
|
35
|
+
#private;
|
|
36
|
+
/** `dir` is the directory the caller handed in; entries live under `<dir>/tags/`. */
|
|
37
|
+
constructor(dir: string);
|
|
38
|
+
/**
|
|
39
|
+
* The cached tags under `key`, `undefined` on a miss, `'corrupt'` when an entry
|
|
40
|
+
* existed but could not be trusted — in which case it has already been deleted, so
|
|
41
|
+
* the corruption is reported exactly once and never re-read.
|
|
42
|
+
*/
|
|
43
|
+
read(key: string): TagsCacheLookup;
|
|
44
|
+
/**
|
|
45
|
+
* Persist one file's tags. Written to a temp name and renamed into place, so a
|
|
46
|
+
* concurrent reader never sees a half-written entry; both writers of the same key
|
|
47
|
+
* are writing identical bytes (the key covers the content), so last-rename-wins is
|
|
48
|
+
* harmless. No fsync: unlike the elision store, every entry here is derivable from
|
|
49
|
+
* source, so losing one to a crash costs a re-parse, not a broken promise.
|
|
50
|
+
*/
|
|
51
|
+
write(key: string, tags: FileTags): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/repomap/cache.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiB,QAAQ,EAAgB,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AAEH,iDAAiD;AACjD,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AAEtD,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,8CAA8C;AAC9C,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/D,qBAAa,SAAS;;IAGpB,qFAAqF;IACrF,YAAY,GAAG,EAAE,MAAM,EAGtB;IAED;;;;OAIG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAqBjC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAWvC;CAeF"}
|