@codegraft/core 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -0
  3. package/dist/assert.d.ts +8 -0
  4. package/dist/assert.d.ts.map +1 -0
  5. package/dist/assert.js +11 -0
  6. package/dist/assert.js.map +1 -0
  7. package/dist/collection.d.ts +164 -0
  8. package/dist/collection.d.ts.map +1 -0
  9. package/dist/collection.js +570 -0
  10. package/dist/collection.js.map +1 -0
  11. package/dist/comment-attachment.d.ts +25 -0
  12. package/dist/comment-attachment.d.ts.map +1 -0
  13. package/dist/comment-attachment.js +94 -0
  14. package/dist/comment-attachment.js.map +1 -0
  15. package/dist/edit-collector.d.ts +31 -0
  16. package/dist/edit-collector.d.ts.map +1 -0
  17. package/dist/edit-collector.js +75 -0
  18. package/dist/edit-collector.js.map +1 -0
  19. package/dist/evaluate.d.ts +15 -0
  20. package/dist/evaluate.d.ts.map +1 -0
  21. package/dist/evaluate.js +95 -0
  22. package/dist/evaluate.js.map +1 -0
  23. package/dist/extensions.d.ts +3 -0
  24. package/dist/extensions.d.ts.map +1 -0
  25. package/dist/extensions.js +19 -0
  26. package/dist/extensions.js.map +1 -0
  27. package/dist/generated/node-types.d.ts +31 -0
  28. package/dist/generated/node-types.d.ts.map +1 -0
  29. package/dist/generated/node-types.js +5 -0
  30. package/dist/generated/node-types.js.map +1 -0
  31. package/dist/helpers.d.ts +13 -0
  32. package/dist/helpers.d.ts.map +1 -0
  33. package/dist/helpers.js +27 -0
  34. package/dist/helpers.js.map +1 -0
  35. package/dist/index.d.ts +6 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +4 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/internal.d.ts +6 -0
  40. package/dist/internal.d.ts.map +1 -0
  41. package/dist/internal.js +9 -0
  42. package/dist/internal.js.map +1 -0
  43. package/dist/parser.d.ts +30 -0
  44. package/dist/parser.d.ts.map +1 -0
  45. package/dist/parser.js +125 -0
  46. package/dist/parser.js.map +1 -0
  47. package/dist/resolver.d.ts +27 -0
  48. package/dist/resolver.d.ts.map +1 -0
  49. package/dist/resolver.js +241 -0
  50. package/dist/resolver.js.map +1 -0
  51. package/dist/rich-node.d.ts +5 -0
  52. package/dist/rich-node.d.ts.map +1 -0
  53. package/dist/rich-node.js +101 -0
  54. package/dist/rich-node.js.map +1 -0
  55. package/dist/types.d.ts +112 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +2 -0
  58. package/dist/types.js.map +1 -0
  59. package/dist/zone-splitter.d.ts +12 -0
  60. package/dist/zone-splitter.d.ts.map +1 -0
  61. package/dist/zone-splitter.js +23 -0
  62. package/dist/zone-splitter.js.map +1 -0
  63. package/package.json +62 -0
  64. package/wasm/tree-sitter-tsx.wasm +0 -0
  65. package/wasm/tree-sitter-typescript.wasm +0 -0
  66. package/wasm/tree-sitter-yaml.wasm +0 -0
@@ -0,0 +1,27 @@
1
+ import { assert } from './assert.js';
2
+ // TypeScript type-position navigation, so a rewrite needn't know tree-sitter field
3
+ // names. Public helpers a codemod body can call.
4
+ export function getPropertySignatures(objectType) {
5
+ return objectType.children.filter((child) => child.type === 'property_signature');
6
+ }
7
+ export function getPropertyName(signature) {
8
+ return signature.child('name')?.text ?? null;
9
+ }
10
+ /**
11
+ * The `{ name, type }` branches of an object type, with each property's `: T` annotation
12
+ * unwrapped to `T`. The canonical use is collapsing a `BATI.If<{ featureA: T; default: U }>`
13
+ * conditional type to the branch whose name is an enabled feature (else `default`).
14
+ */
15
+ export function getConditionalBranches(objectType) {
16
+ const branches = [];
17
+ for (const signature of getPropertySignatures(objectType)) {
18
+ const type = signature.child('type')?.children[0];
19
+ if (!type)
20
+ continue; // a property without a type annotation isn't a branch
21
+ const name = getPropertyName(signature);
22
+ assert(name !== null, 'a property_signature is always named');
23
+ branches.push({ name, type });
24
+ }
25
+ return branches;
26
+ }
27
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,mFAAmF;AACnF,iDAAiD;AAEjD,MAAM,UAAU,qBAAqB,CAAC,UAAoB;IACxD,OAAO,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAA;AACnF,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAmB;IACjD,OAAO,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,IAAI,IAAI,CAAA;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAAoB;IACzD,MAAM,QAAQ,GAA4C,EAAE,CAAA;IAC5D,KAAK,MAAM,SAAS,IAAI,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;QACjD,IAAI,CAAC,IAAI;YAAE,SAAQ,CAAC,sDAAsD;QAC1E,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;QACvC,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,sCAAsC,CAAC,CAAA;QAC7D,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/B,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { Collection, createCodemodTransformer } from './collection.js';
2
+ export { evaluate } from './evaluate.js';
3
+ export { getPropertySignatures, getPropertyName, getConditionalBranches } from './helpers.js';
4
+ export type { GrammarId, Point, ZoneSplitter, RichNode, Zone, SourceMap, Transformer, LazyTransformer, } from './types.js';
5
+ export type { NodeType, NodeTypeAll, FieldName, NodeTypeOf, NodeTypeAllOf, FieldNameOf, JavascriptNodeType, TypescriptNodeType, TsxNodeType, HtmlNodeType, CssNodeType, } from './generated/node-types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAC7F,YAAY,EACV,SAAS,EACT,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,SAAS,EACT,UAAU,EACV,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,2BAA2B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { Collection, createCodemodTransformer } from './collection.js';
2
+ export { evaluate } from './evaluate.js';
3
+ export { getPropertySignatures, getPropertyName, getConditionalBranches } from './helpers.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { Parser, grammarPackage } from './parser.js';
2
+ export { EXTENSION_GRAMMAR } from './extensions.js';
3
+ export { wrapNode } from './rich-node.js';
4
+ export { assert } from './assert.js';
5
+ export type { Node, Tree } from 'web-tree-sitter';
6
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,9 @@
1
+ // Internal primitives for first-party build-time packages (@codegraft/cli, @codegraft/vue,
2
+ // @codegraft/unplugin). These are NOT part of the public consumer API — they are exposed only
3
+ // through the "@codegraft/core/internal" subpath (e.g. EXTENSION_GRAMMAR for the bundler plugin,
4
+ // grammarPackage for the CLI) so they need not duplicate the Parser/RichNode the runtime uses.
5
+ export { Parser, grammarPackage } from './parser.js';
6
+ export { EXTENSION_GRAMMAR } from './extensions.js';
7
+ export { wrapNode } from './rich-node.js';
8
+ export { assert } from './assert.js';
9
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,8FAA8F;AAC9F,iGAAiG;AACjG,+FAA+F;AAC/F,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,30 @@
1
+ import type { Tree } from 'web-tree-sitter';
2
+ import type { GrammarId } from './types.js';
3
+ /** Idempotent. Loads the web-tree-sitter WASM runtime once per process. */
4
+ declare function init(): Promise<void>;
5
+ /**
6
+ * Lazily load a grammar, idempotent per `id`. Built-in {@link GrammarId}s resolve
7
+ * their own `.wasm`; an external grammar (e.g. a {@link ZoneSplitter}'s shell
8
+ * grammar) passes its `wasmPath` and an arbitrary `id` used as the cache key.
9
+ */
10
+ declare function loadGrammar(id: GrammarId | string, wasmPath?: string): Promise<void>;
11
+ /** The npm package a consumer must install for a built-in grammar, or `null` for a vendored
12
+ * grammar that ships with `@codegraft/core`. */
13
+ export declare function grammarPackage(id: GrammarId): string | null;
14
+ /** Parse `source` with an already-loaded grammar. Reuses one parser instance; safe
15
+ * because transforms run synchronously and trees are independent of the parser. */
16
+ declare function parse(source: string, id: GrammarId | string): Tree;
17
+ /** The subtypes of a grammar supertype, expanded transitively (`statement` → `declaration` →
18
+ * `lexical_declaration`, …), or `[]` if `typeName` is not a supertype. Intermediate supertype
19
+ * names are kept too — harmless, since only concrete types appear in a tree. Memoised per grammar,
20
+ * so a `find` can call it per node. */
21
+ declare function subtypesOf(id: GrammarId | string, typeName: string): string[];
22
+ /** Singleton confining every web-tree-sitter init/load concern to this module. */
23
+ export declare const Parser: {
24
+ init: typeof init;
25
+ loadGrammar: typeof loadGrammar;
26
+ parse: typeof parse;
27
+ subtypesOf: typeof subtypesOf;
28
+ };
29
+ export {};
30
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAsC3C,2EAA2E;AAC3E,iBAAe,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAGnC;AAED;;;;GAIG;AACH,iBAAe,WAAW,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQnF;AAQD;iDACiD;AACjD,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAG3D;AAeD;oFACoF;AACpF,iBAAS,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAQ3D;AAED;;;wCAGwC;AACxC,iBAAS,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAsBtE;AAED,kFAAkF;AAClF,eAAO,MAAM,MAAM;;;;;CAA2C,CAAA"}
package/dist/parser.js ADDED
@@ -0,0 +1,125 @@
1
+ import { createRequire } from 'node:module';
2
+ import { readFileSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Language, Parser as TreeSitter } from 'web-tree-sitter';
5
+ import { assert } from './assert.js';
6
+ // web-tree-sitter resolves the grammar `.wasm` from its npm package at runtime; the
7
+ // engine wasm (`tree-sitter.wasm`) is self-located by `Parser.init()`.
8
+ const require = createRequire(import.meta.url);
9
+ /**
10
+ * The typescript/tsx grammars are **vendored** here (resolved relative to this module): the npm
11
+ * `tree-sitter-typescript` ships an ABI-14 wasm, which web-tree-sitter loads without supertype
12
+ * metadata (so `find` can't expand `expression` etc.). We ship an ABI-15 rebuild — see
13
+ * `scripts/regen-ts-wasm.sh` — so they impose no peer dependency.
14
+ */
15
+ const VENDORED_WASM = {
16
+ typescript: 'tree-sitter-typescript.wasm',
17
+ tsx: 'tree-sitter-tsx.wasm',
18
+ // tree-sitter-yaml ships no prebuilt wasm on the bare `tree-sitter-yaml` package; we vendor the
19
+ // one from `@tree-sitter-grammars/tree-sitter-yaml` so YAML imposes no peer dependency.
20
+ yaml: 'tree-sitter-yaml.wasm',
21
+ };
22
+ /**
23
+ * The npm specifier of each remaining built-in grammar's `.wasm` (these already ship the ABI we
24
+ * need). Optional peer dependencies: resolved only when the grammar is requested, and a missing
25
+ * package becomes an actionable error in `resolveBuiltinWasm`.
26
+ */
27
+ const PEER_WASM = {
28
+ javascript: 'tree-sitter-javascript/tree-sitter-javascript.wasm',
29
+ html: 'tree-sitter-html/tree-sitter-html.wasm',
30
+ css: 'tree-sitter-css/tree-sitter-css.wasm',
31
+ };
32
+ let initPromise = null;
33
+ let parser = null;
34
+ const languages = new Map();
35
+ const loads = new Map();
36
+ const subtypeCache = new Map();
37
+ /** Idempotent. Loads the web-tree-sitter WASM runtime once per process. */
38
+ async function init() {
39
+ initPromise ??= TreeSitter.init();
40
+ await initPromise;
41
+ }
42
+ /**
43
+ * Lazily load a grammar, idempotent per `id`. Built-in {@link GrammarId}s resolve
44
+ * their own `.wasm`; an external grammar (e.g. a {@link ZoneSplitter}'s shell
45
+ * grammar) passes its `wasmPath` and an arbitrary `id` used as the cache key.
46
+ */
47
+ async function loadGrammar(id, wasmPath) {
48
+ if (languages.has(id))
49
+ return;
50
+ let pending = loads.get(id);
51
+ if (!pending) {
52
+ pending = loadLanguage(id, wasmPath);
53
+ loads.set(id, pending);
54
+ }
55
+ languages.set(id, await pending);
56
+ }
57
+ async function loadLanguage(id, wasmPath) {
58
+ await init();
59
+ const path = wasmPath ?? resolveBuiltinWasm(id);
60
+ return Language.load(readFileSync(path));
61
+ }
62
+ /** The npm package a consumer must install for a built-in grammar, or `null` for a vendored
63
+ * grammar that ships with `@codegraft/core`. */
64
+ export function grammarPackage(id) {
65
+ const spec = PEER_WASM[id];
66
+ return spec ? spec.slice(0, spec.indexOf('/')) : null;
67
+ }
68
+ function resolveBuiltinWasm(id) {
69
+ const vendored = VENDORED_WASM[id];
70
+ if (vendored)
71
+ return fileURLToPath(new URL(`../wasm/${vendored}`, import.meta.url));
72
+ const spec = PEER_WASM[id];
73
+ assert(spec, `grammar '${id}' is not built in; a ZoneSplitter must pass its own wasmPath to loadGrammar`);
74
+ try {
75
+ return require.resolve(spec);
76
+ }
77
+ catch {
78
+ const pkg = spec.slice(0, spec.indexOf('/'));
79
+ throw new Error(`[codegraft] grammar '${id}' requires the optional peer '${pkg}'; add it to your dependencies`);
80
+ }
81
+ }
82
+ /** Parse `source` with an already-loaded grammar. Reuses one parser instance; safe
83
+ * because transforms run synchronously and trees are independent of the parser. */
84
+ function parse(source, id) {
85
+ const language = languages.get(id);
86
+ assert(language, `grammar '${id}' not loaded; call loadGrammar('${id}') first`);
87
+ parser ??= new TreeSitter();
88
+ parser.setLanguage(language);
89
+ const tree = parser.parse(source);
90
+ assert(tree, `parsing produced no tree for grammar '${id}'`);
91
+ return tree;
92
+ }
93
+ /** The subtypes of a grammar supertype, expanded transitively (`statement` → `declaration` →
94
+ * `lexical_declaration`, …), or `[]` if `typeName` is not a supertype. Intermediate supertype
95
+ * names are kept too — harmless, since only concrete types appear in a tree. Memoised per grammar,
96
+ * so a `find` can call it per node. */
97
+ function subtypesOf(id, typeName) {
98
+ const language = languages.get(id);
99
+ assert(language, `grammar '${id}' not loaded; call loadGrammar('${id}') first`);
100
+ let perGrammar = subtypeCache.get(id);
101
+ if (!perGrammar)
102
+ subtypeCache.set(id, (perGrammar = new Map()));
103
+ let names = perGrammar.get(typeName);
104
+ if (!names) {
105
+ const supertypes = new Set(language.supertypes);
106
+ const root = language.idForNodeType(typeName, true);
107
+ const out = new Set();
108
+ const queue = root !== null && supertypes.has(root) ? [root] : [];
109
+ for (let sym = queue.pop(); sym !== undefined; sym = queue.pop()) {
110
+ for (const sub of language.subtypes(sym)) {
111
+ const name = language.nodeTypeForId(sub);
112
+ if (!name || out.has(name))
113
+ continue;
114
+ out.add(name);
115
+ if (supertypes.has(sub))
116
+ queue.push(sub); // nested supertype — expand to its leaves
117
+ }
118
+ }
119
+ perGrammar.set(typeName, (names = [...out]));
120
+ }
121
+ return names;
122
+ }
123
+ /** Singleton confining every web-tree-sitter init/load concern to this module. */
124
+ export const Parser = { init, loadGrammar, parse, subtypesOf };
125
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAGhE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,oFAAoF;AACpF,uEAAuE;AACvE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,aAAa,GAAuC;IACxD,UAAU,EAAE,6BAA6B;IACzC,GAAG,EAAE,sBAAsB;IAC3B,gGAAgG;IAChG,wFAAwF;IACxF,IAAI,EAAE,uBAAuB;CAC9B,CAAA;AAED;;;;GAIG;AACH,MAAM,SAAS,GAAuC;IACpD,UAAU,EAAE,oDAAoD;IAChE,IAAI,EAAE,wCAAwC;IAC9C,GAAG,EAAE,sCAAsC;CAC5C,CAAA;AAED,IAAI,WAAW,GAAyB,IAAI,CAAA;AAC5C,IAAI,MAAM,GAAsB,IAAI,CAAA;AACpC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAA;AAC7C,MAAM,KAAK,GAAG,IAAI,GAAG,EAA6B,CAAA;AAClD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAiC,CAAA;AAE7D,2EAA2E;AAC3E,KAAK,UAAU,IAAI;IACjB,WAAW,KAAK,UAAU,CAAC,IAAI,EAAE,CAAA;IACjC,MAAM,WAAW,CAAA;AACnB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,EAAsB,EAAE,QAAiB;IAClE,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QAAE,OAAM;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;QACpC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IACxB,CAAC;IACD,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAA;AAClC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,EAAU,EAAE,QAAiB;IACvD,MAAM,IAAI,EAAE,CAAA;IACZ,MAAM,IAAI,GAAG,QAAQ,IAAI,kBAAkB,CAAC,EAAE,CAAC,CAAA;IAC/C,OAAO,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;AAC1C,CAAC;AAED;iDACiD;AACjD,MAAM,UAAU,cAAc,CAAC,EAAa;IAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC,CAAA;IAC1B,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACvD,CAAC;AAED,SAAS,kBAAkB,CAAC,EAAU;IACpC,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAe,CAAC,CAAA;IAC/C,IAAI,QAAQ;QAAE,OAAO,aAAa,CAAC,IAAI,GAAG,CAAC,WAAW,QAAQ,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACnF,MAAM,IAAI,GAAG,SAAS,CAAC,EAAe,CAAC,CAAA;IACvC,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,6EAA6E,CAAC,CAAA;IACzG,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5C,MAAM,IAAI,KAAK,CAAC,wBAAwB,EAAE,iCAAiC,GAAG,gCAAgC,CAAC,CAAA;IACjH,CAAC;AACH,CAAC;AAED;oFACoF;AACpF,SAAS,KAAK,CAAC,MAAc,EAAE,EAAsB;IACnD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAClC,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,mCAAmC,EAAE,UAAU,CAAC,CAAA;IAC/E,MAAM,KAAK,IAAI,UAAU,EAAE,CAAA;IAC3B,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACjC,MAAM,CAAC,IAAI,EAAE,yCAAyC,EAAE,GAAG,CAAC,CAAA;IAC5D,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;wCAGwC;AACxC,SAAS,UAAU,CAAC,EAAsB,EAAE,QAAgB;IAC1D,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAClC,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,mCAAmC,EAAE,UAAU,CAAC,CAAA;IAC/E,IAAI,UAAU,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACrC,IAAI,CAAC,UAAU;QAAE,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;IAC/D,IAAI,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;QAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACnD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAA;QAC7B,MAAM,KAAK,GAAG,IAAI,KAAK,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACjE,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,KAAK,SAAS,EAAE,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;YACjE,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;gBACxC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,SAAQ;gBACpC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;gBACb,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA,CAAC,0CAA0C;YACrF,CAAC;QACH,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;IAC9C,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA"}
@@ -0,0 +1,27 @@
1
+ import type { RichNode } from './types.js';
2
+ /**
3
+ * Lexical binding resolution for one parsed tree — **JS/TS/TSX only**, syntactic (no types).
4
+ *
5
+ * Confident-or-abstain: a query returns `null` whenever the tree contains a construct the
6
+ * resolver does not fully model (`with`, `eval`, a TS namespace/ambient module, an unknown binding
7
+ * form, or an occurrence that can't be renamed in place such as an object shorthand). A codemod
8
+ * treats `null` as "do not proceed", so a rename never fires on a guess. (A TS `enum` is modelled —
9
+ * its name binds like a class — so it does not force abstention.)
10
+ *
11
+ * Value vs type is mostly free here: tree-sitter spells type references `type_identifier`, so
12
+ * collecting `identifier` nodes naturally excludes them.
13
+ */
14
+ export interface Resolver {
15
+ /** Every occurrence (declaration + value references) of the binding `decl` introduces; `null`
16
+ * to abstain. */
17
+ references(decl: RichNode): RichNode[] | null;
18
+ /** The declaration a value reference resolves to; `null` for a global or to abstain. */
19
+ definition(ref: RichNode): RichNode | null;
20
+ /** The declaration `name` resolves to from `at`'s position; `null` for a global or to abstain. */
21
+ lookup(at: RichNode, name: string): RichNode | null;
22
+ /** Every binding visible at `at` (inner shadows outer), or `null` to abstain. */
23
+ bindingsInScope(at: RichNode): RichNode[] | null;
24
+ }
25
+ /** A resolver for `root`'s tree, or `null` if the language has no binding model. */
26
+ export declare function createResolver(root: RichNode): Resolver | null;
27
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,QAAQ;IACvB;sBACkB;IAClB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAA;IAC7C,wFAAwF;IACxF,UAAU,CAAC,GAAG,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAA;IAC1C,kGAAkG;IAClG,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAA;IACnD,iFAAiF;IACjF,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAA;CACjD;AAID,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAE9D"}
@@ -0,0 +1,241 @@
1
+ const SUPPORTED = new Set(['javascript', 'typescript', 'tsx']);
2
+ /** A resolver for `root`'s tree, or `null` if the language has no binding model. */
3
+ export function createResolver(root) {
4
+ return SUPPORTED.has(root.language) ? new ScopeResolver(root) : null;
5
+ }
6
+ class ScopeResolver {
7
+ #abstain = false;
8
+ #root;
9
+ /** scope-owning node → its scope (the only nodes recorded; `#scopeAt` walks up to them). */
10
+ #scopes = new Map();
11
+ constructor(root) {
12
+ this.#root = { node: root, parent: null, bindings: new Map() };
13
+ this.#scopes.set(root, this.#root);
14
+ this.#walk(root, this.#root, this.#root);
15
+ }
16
+ definition(ref) {
17
+ if (this.#abstain || ref.type !== 'identifier')
18
+ return null;
19
+ return this.lookup(ref, ref.text);
20
+ }
21
+ references(decl) {
22
+ if (this.#abstain || decl.type !== 'identifier')
23
+ return null;
24
+ const name = decl.text;
25
+ if (this.#scopeAt(decl).bindings.get(name) !== decl)
26
+ return null; // not a binding we own
27
+ const out = [];
28
+ let abstain = false;
29
+ const collect = (node) => {
30
+ if (abstain)
31
+ return;
32
+ if (node.text === name) {
33
+ // an object shorthand referencing this binding can't be renamed in place
34
+ if (node.type === 'shorthand_property_identifier' && this.lookup(node, name) === decl) {
35
+ abstain = true;
36
+ return;
37
+ }
38
+ if (node.type === 'identifier' && this.lookup(node, name) === decl)
39
+ out.push(node);
40
+ }
41
+ for (const child of node.allChildren)
42
+ collect(child);
43
+ };
44
+ collect(this.#scopeAt(decl).node);
45
+ return abstain ? null : out;
46
+ }
47
+ lookup(at, name) {
48
+ if (this.#abstain)
49
+ return null;
50
+ for (let s = this.#scopeAt(at); s; s = s.parent) {
51
+ const binding = s.bindings.get(name);
52
+ if (binding)
53
+ return binding;
54
+ }
55
+ return null;
56
+ }
57
+ bindingsInScope(at) {
58
+ if (this.#abstain)
59
+ return null;
60
+ const visible = new Map();
61
+ for (let s = this.#scopeAt(at); s; s = s.parent) {
62
+ for (const [name, decl] of s.bindings)
63
+ if (!visible.has(name))
64
+ visible.set(name, decl); // inner shadows outer
65
+ }
66
+ return [...visible.values()];
67
+ }
68
+ #scopeAt(node) {
69
+ for (let n = node; n; n = n.parent) {
70
+ const scope = this.#scopes.get(n);
71
+ if (scope)
72
+ return scope;
73
+ }
74
+ return this.#root;
75
+ }
76
+ #newScope(node, parent) {
77
+ const scope = { node, parent, bindings: new Map() };
78
+ this.#scopes.set(node, scope);
79
+ return scope;
80
+ }
81
+ #walk(node, scope, fnScope) {
82
+ if (this.#abstain)
83
+ return;
84
+ switch (node.type) {
85
+ // `with` makes any bare name a possible property; a TS namespace/ambient-module exposes its
86
+ // members as `X.m` (so a partial rename corrupts). Both are beyond syntactic resolution.
87
+ case 'with_statement':
88
+ case 'internal_module': // namespace X {}
89
+ case 'module': // module 'x' {}
90
+ this.#abstain = true;
91
+ return;
92
+ case 'call_expression':
93
+ if (node.child('function')?.text === 'eval') {
94
+ this.#abstain = true;
95
+ return;
96
+ }
97
+ this.#walkChildren(node, scope, fnScope);
98
+ return;
99
+ case 'function_declaration':
100
+ case 'generator_function_declaration': {
101
+ this.#bind(fnScope, node.child('name')); // hoisted to the enclosing function scope
102
+ const inner = this.#newScope(node, scope);
103
+ this.#bindParams(node, inner);
104
+ this.#walkChildren(node.child('body'), inner, inner);
105
+ return;
106
+ }
107
+ case 'function_expression':
108
+ case 'generator_function':
109
+ case 'arrow_function':
110
+ case 'method_definition': {
111
+ const inner = this.#newScope(node, scope);
112
+ this.#bind(inner, node.child('name')); // optional function-expression name
113
+ this.#bindParams(node, inner);
114
+ this.#walkChildren(node.child('body'), inner, inner);
115
+ return;
116
+ }
117
+ // A class/enum name binds in the enclosing scope; their members are `property_identifier`
118
+ // (reached as `X.member`), never free identifiers, so walking the body here is safe.
119
+ case 'class_declaration':
120
+ case 'enum_declaration': {
121
+ this.#bind(scope, node.child('name'));
122
+ this.#walkChildren(node.child('body'), scope, fnScope);
123
+ return;
124
+ }
125
+ case 'lexical_declaration': // let / const
126
+ for (const d of node.children) {
127
+ if (d.type !== 'variable_declarator')
128
+ continue;
129
+ this.#bindPattern(d.child('name'), scope);
130
+ this.#walkChildren(d.child('value'), scope, fnScope);
131
+ }
132
+ return;
133
+ case 'variable_declaration': // var → hoisted
134
+ for (const d of node.children) {
135
+ if (d.type !== 'variable_declarator')
136
+ continue;
137
+ this.#bindPattern(d.child('name'), fnScope);
138
+ this.#walkChildren(d.child('value'), scope, fnScope);
139
+ }
140
+ return;
141
+ case 'import_statement':
142
+ this.#bindImports(node);
143
+ return;
144
+ case 'statement_block': {
145
+ this.#walkChildren(node, this.#newScope(node, scope), fnScope);
146
+ return;
147
+ }
148
+ case 'for_statement':
149
+ case 'for_in_statement': {
150
+ this.#walkChildren(node, this.#newScope(node, scope), fnScope);
151
+ return;
152
+ }
153
+ case 'catch_clause': {
154
+ const inner = this.#newScope(node, scope);
155
+ this.#bindPattern(node.child('parameter'), inner);
156
+ this.#walkChildren(node.child('body'), inner, fnScope);
157
+ return;
158
+ }
159
+ default:
160
+ this.#walkChildren(node, scope, fnScope);
161
+ }
162
+ }
163
+ #walkChildren(node, scope, fnScope) {
164
+ if (!node)
165
+ return;
166
+ for (const child of node.allChildren)
167
+ this.#walk(child, scope, fnScope);
168
+ }
169
+ #bind(scope, name) {
170
+ if (name?.type === 'identifier')
171
+ scope.bindings.set(name.text, name);
172
+ }
173
+ #bindParams(fn, scope) {
174
+ const params = fn.child('parameters');
175
+ if (params) {
176
+ for (const p of params.children)
177
+ this.#bindPattern(unwrapParameter(p), scope);
178
+ return;
179
+ }
180
+ this.#bindPattern(fn.child('parameter'), scope); // arrow `x => …`
181
+ }
182
+ #bindImports(node) {
183
+ const walk = (n) => {
184
+ if (n.type === 'identifier') {
185
+ this.#root.bindings.set(n.text, n); // default / namespace local
186
+ return;
187
+ }
188
+ if (n.type === 'import_specifier') {
189
+ const local = n.child('alias') ?? n.child('name');
190
+ if (local?.type === 'identifier')
191
+ this.#root.bindings.set(local.text, local);
192
+ return;
193
+ }
194
+ for (const child of n.allChildren)
195
+ walk(child);
196
+ };
197
+ walk(node);
198
+ }
199
+ /** Bind every name a binding pattern introduces; abstain on an unknown pattern form. */
200
+ #bindPattern(node, scope) {
201
+ if (!node)
202
+ return;
203
+ switch (node.type) {
204
+ case 'identifier':
205
+ scope.bindings.set(node.text, node);
206
+ return;
207
+ case 'shorthand_property_identifier_pattern':
208
+ scope.bindings.set(node.text, node);
209
+ return;
210
+ case 'object_pattern':
211
+ for (const child of node.children) {
212
+ if (child.type === 'pair_pattern')
213
+ this.#bindPattern(child.child('value'), scope);
214
+ else
215
+ this.#bindPattern(child, scope);
216
+ }
217
+ return;
218
+ case 'array_pattern':
219
+ for (const child of node.children)
220
+ this.#bindPattern(child, scope);
221
+ return;
222
+ case 'rest_pattern':
223
+ this.#bindPattern(node.children[0] ?? null, scope);
224
+ return;
225
+ case 'assignment_pattern':
226
+ case 'object_assignment_pattern':
227
+ this.#bindPattern(node.child('left') ?? node.children[0] ?? null, scope);
228
+ return;
229
+ default:
230
+ this.#abstain = true; // a binding form we don't model — abstain rather than mis-resolve
231
+ }
232
+ }
233
+ }
234
+ /** TS wraps params as `required_parameter`/`optional_parameter` { pattern }; JS is the bare pattern. */
235
+ function unwrapParameter(param) {
236
+ if (param.type === 'required_parameter' || param.type === 'optional_parameter') {
237
+ return param.child('pattern') ?? param.children[0] ?? param;
238
+ }
239
+ return param;
240
+ }
241
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Node } from 'web-tree-sitter';
2
+ import type { GrammarId, RichNode } from './types.js';
3
+ /** Wrap a parsed tree's root. Children are created lazily as the tree is walked. */
4
+ export declare function wrapNode(node: Node, language: GrammarId, startOffset: number): RichNode;
5
+ //# sourceMappingURL=rich-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rich-node.d.ts","sourceRoot":"","sources":["../src/rich-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAS,QAAQ,EAAE,MAAM,YAAY,CAAA;AA2G5D,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,CAEvF"}
@@ -0,0 +1,101 @@
1
+ var _a;
2
+ import { COMMENT_TYPES } from './comment-attachment.js';
3
+ import { assert } from './assert.js';
4
+ /**
5
+ * Lazy wrapper over a web-tree-sitter `Node`. Scalar accessors (type/text/positions)
6
+ * read straight through to the backing node; `allChildren` and `children` are built
7
+ * once and cached, so there is exactly one `RichNodeImpl` per backing node within a
8
+ * subtree — which is what lets the comment-attachment pass write onto the same
9
+ * instances that pattern matching and rewrites later see.
10
+ *
11
+ * The class is internal; callers receive the `RichNode` interface via `wrapNode`.
12
+ */
13
+ class RichNodeImpl {
14
+ language;
15
+ // Filled in by the comment-attachment pass; the arrays are mutable, the bindings are not.
16
+ leadingComments = [];
17
+ trailingComments = [];
18
+ innerComments = [];
19
+ #node;
20
+ #startOffset;
21
+ #parent;
22
+ #allChildren;
23
+ #children;
24
+ constructor(node, language, startOffset, parent) {
25
+ this.#node = node;
26
+ this.language = language;
27
+ this.#startOffset = startOffset;
28
+ this.#parent = parent;
29
+ }
30
+ get type() {
31
+ // The grammar guarantees the raw string is one of its node types; assert it into the union.
32
+ return this.#node.type;
33
+ }
34
+ get isNamed() {
35
+ return this.#node.isNamed;
36
+ }
37
+ get text() {
38
+ return this.#node.text;
39
+ }
40
+ get startIndex() {
41
+ return this.#node.startIndex;
42
+ }
43
+ get endIndex() {
44
+ return this.#node.endIndex;
45
+ }
46
+ get startPosition() {
47
+ return this.#node.startPosition;
48
+ }
49
+ get endPosition() {
50
+ return this.#node.endPosition;
51
+ }
52
+ get parent() {
53
+ return this.#parent;
54
+ }
55
+ get documentStartIndex() {
56
+ return this.#node.startIndex + this.#startOffset;
57
+ }
58
+ get documentEndIndex() {
59
+ return this.#node.endIndex + this.#startOffset;
60
+ }
61
+ /** Full CST: every child, including anonymous punctuation and comments. */
62
+ get allChildren() {
63
+ return this.#computeAllChildren();
64
+ }
65
+ /** Named structural children with comments removed — the surface pattern matching
66
+ * walks, so neither punctuation nor comments can perturb a match. */
67
+ get children() {
68
+ const comments = COMMENT_TYPES[this.language];
69
+ this.#children ??= this.#computeAllChildren().filter((n) => n.isNamed && !comments.has(n.type));
70
+ return this.#children;
71
+ }
72
+ child(field) {
73
+ const target = this.#node.childForFieldName(field);
74
+ return target === null ? null : this.#wrapperFor(target, field);
75
+ }
76
+ childrenForField(field) {
77
+ return this.#node
78
+ .childrenForFieldName(field)
79
+ .filter((n) => n !== null)
80
+ .map((target) => this.#wrapperFor(target, field));
81
+ }
82
+ #computeAllChildren() {
83
+ this.#allChildren ??= this.#node.children
84
+ .filter((c) => c !== null)
85
+ .map((c) => new _a(c, this.language, this.#startOffset, this));
86
+ return this.#allChildren;
87
+ }
88
+ /** Map a backing field-child back to its cached wrapper, so identity (and any
89
+ * attached comments) is shared rather than re-wrapped. */
90
+ #wrapperFor(target, field) {
91
+ const wrapped = this.#computeAllChildren().find((c) => c.#node.equals(target));
92
+ assert(wrapped, `field '${field}' resolved to a node absent from allChildren`);
93
+ return wrapped;
94
+ }
95
+ }
96
+ _a = RichNodeImpl;
97
+ /** Wrap a parsed tree's root. Children are created lazily as the tree is walked. */
98
+ export function wrapNode(node, language, startOffset) {
99
+ return new RichNodeImpl(node, language, startOffset, null);
100
+ }
101
+ //# sourceMappingURL=rich-node.js.map