ember-estree 0.6.1 → 0.6.2
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/package.json +4 -4
- package/src/parse.js +72 -41
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-estree",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "ESTree generator for gjs and gts file used by ember",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"AST",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
"@glimmer/env": "^0.1.7",
|
|
34
34
|
"@glimmer/syntax": "^0.95.0",
|
|
35
35
|
"content-tag": "^4.1.0",
|
|
36
|
-
"oxc-parser": "^0.119.0"
|
|
37
|
-
"zimmerframe": "^1.1.4"
|
|
36
|
+
"oxc-parser": "^0.119.0"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
39
|
"@tsconfig/node-lts": "^22.0.2",
|
|
@@ -45,7 +44,8 @@
|
|
|
45
44
|
"publint": "^0.3.18",
|
|
46
45
|
"release-plan": "^0.18.0",
|
|
47
46
|
"typescript": "^5.9.3",
|
|
48
|
-
"vitest": "^3.2.4"
|
|
47
|
+
"vitest": "^3.2.4",
|
|
48
|
+
"zimmerframe": "^1.1.4"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"bench": "node --expose-gc tests/parser.bench.mjs",
|
package/src/parse.js
CHANGED
|
@@ -9,12 +9,24 @@
|
|
|
9
9
|
* 6. Done
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { parseSync } from "oxc-parser";
|
|
12
|
+
import { parseSync, visitorKeys as oxcVisitorKeys } from "oxc-parser";
|
|
13
13
|
import { Preprocessor } from "content-tag";
|
|
14
|
-
import { walk } from "zimmerframe";
|
|
15
14
|
|
|
16
15
|
import { processTemplate, DocumentLines, glimmerVisitorKeys, setParent } from "./transforms.js";
|
|
17
16
|
|
|
17
|
+
// Base visitor-keys map for the outer-AST walk: oxc-parser's own keys (covers
|
|
18
|
+
// standard ESTree + TS), plus the `File` wrapper we add on the default path,
|
|
19
|
+
// plus Glimmer's keys. Used to iterate only declared child slots instead of
|
|
20
|
+
// every enumerable property on every node.
|
|
21
|
+
//
|
|
22
|
+
// When `options.parser` returns `visitorKeys`, callers merge on top — but if
|
|
23
|
+
// their parser's AST is oxc-compatible, this base is already sufficient.
|
|
24
|
+
const DEFAULT_VISITOR_KEYS = {
|
|
25
|
+
...oxcVisitorKeys,
|
|
26
|
+
File: ["program"],
|
|
27
|
+
...glimmerVisitorKeys,
|
|
28
|
+
};
|
|
29
|
+
|
|
18
30
|
// Swap `oldNode` for `newNode` in whichever slot of `parent` currently holds it.
|
|
19
31
|
// Used to splice a GlimmerTemplate directly into the outer AST without
|
|
20
32
|
// allocating new ancestor objects — keeps WeakMap-keyed data (scope manager,
|
|
@@ -55,7 +67,9 @@ const PLACEHOLDER_TYPES = new Set([
|
|
|
55
67
|
* @param {string} [options.filePath] - File path for language detection
|
|
56
68
|
* @param {boolean} [options.tokens] - Generate a flat token stream on the AST (needed by ESLint; skipped by default)
|
|
57
69
|
* @param {boolean} [options.templateOnly] - Parse as raw Glimmer template content (for .hbs)
|
|
58
|
-
* @param {function} [options.parser] - Custom JS/TS parser: (placeholderJS) => { ast, scopeManager?, visitorKeys?, services?, ... }
|
|
70
|
+
* @param {function} [options.parser] - Custom JS/TS parser: (placeholderJS) => { ast, scopeManager?, visitorKeys?, services?, ... }.
|
|
71
|
+
* Recommended to return `visitorKeys` describing the parser's AST; when omitted, oxc-parser's
|
|
72
|
+
* keys are used (fine for oxc-compatible ASTs, incomplete for parsers that emit bespoke node types).
|
|
59
73
|
* @param {object|function} [options.visitors] - Either a map of `{ [Type]: (node, path) => void }`
|
|
60
74
|
* handlers, or a factory `(outerAst) => handlers` invoked once after parsing (before any
|
|
61
75
|
* template splicing) to give callers a view of the raw JS/TS tree. Handlers fire on every
|
|
@@ -206,49 +220,66 @@ export function toTree(source, options = {}) {
|
|
|
206
220
|
return parseResult;
|
|
207
221
|
}
|
|
208
222
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
223
|
+
// Walk the outer AST keyed on visitorKeys — iterating only declared child
|
|
224
|
+
// slots instead of every enumerable property on every node. Custom parsers
|
|
225
|
+
// may supply their own keys; those override the defaults for types they
|
|
226
|
+
// recognise, and Glimmer keys stay on top for the spliced subtrees.
|
|
227
|
+
const allVisitorKeys =
|
|
228
|
+
useCustomParser && result.visitorKeys
|
|
229
|
+
? { ...DEFAULT_VISITOR_KEYS, ...result.visitorKeys, ...glimmerVisitorKeys }
|
|
230
|
+
: DEFAULT_VISITOR_KEYS;
|
|
231
|
+
|
|
232
|
+
function walkWithKeys(node, parentPath) {
|
|
233
|
+
if (!node || !node.type) return;
|
|
234
|
+
|
|
235
|
+
if (hasTemplates && PLACEHOLDER_TYPES.has(node.type)) {
|
|
236
|
+
const parseResult = matchPlaceholder(node);
|
|
237
|
+
if (parseResult) {
|
|
238
|
+
// Splice in place: write the GlimmerTemplate directly into the parent's
|
|
239
|
+
// slot instead of allocating new ancestor objects. This preserves node
|
|
240
|
+
// identity for every ancestor, which matters for WeakMap-keyed data
|
|
241
|
+
// held by custom parsers (scope manager, esTreeNodeToTSNodeMap).
|
|
242
|
+
const ast = processPlaceholder(parseResult, node);
|
|
243
|
+
const parent = parentPath?.node ?? null;
|
|
244
|
+
if (parent) replaceInParent(parent, node, ast);
|
|
245
|
+
setParent(ast, parent);
|
|
246
|
+
// Recurse into the Glimmer subtree so visitors fire on its nodes too.
|
|
247
|
+
// The Glimmer root's parentPath reflects its true JS parent — the
|
|
248
|
+
// placeholder (TemplateLiteral / StaticBlock) is an internal artifact.
|
|
249
|
+
if (hasVisitors) walkWithKeys(ast, parentPath);
|
|
250
|
+
return;
|
|
232
251
|
}
|
|
252
|
+
}
|
|
233
253
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
254
|
+
const path = { node, parent: parentPath?.node ?? null, parentPath };
|
|
255
|
+
|
|
256
|
+
if (hasVisitors && !seen.has(node)) {
|
|
257
|
+
seen.add(node);
|
|
258
|
+
const handler = visitors[node.type];
|
|
259
|
+
if (handler) handler(node, path);
|
|
260
|
+
if ("blockParams" in node && visitors.GlimmerBlockParams) {
|
|
261
|
+
visitors.GlimmerBlockParams(node, path);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const keys = allVisitorKeys[node.type];
|
|
266
|
+
if (!keys) return;
|
|
267
|
+
for (const key of keys) {
|
|
268
|
+
const child = node[key];
|
|
269
|
+
if (!child) continue;
|
|
270
|
+
if (Array.isArray(child)) {
|
|
271
|
+
for (const item of child) {
|
|
272
|
+
if (item && typeof item === "object" && item.type) {
|
|
273
|
+
walkWithKeys(item, path);
|
|
274
|
+
}
|
|
246
275
|
}
|
|
276
|
+
} else if (typeof child === "object" && child.type) {
|
|
277
|
+
walkWithKeys(child, path);
|
|
247
278
|
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
248
281
|
|
|
249
|
-
|
|
250
|
-
},
|
|
251
|
-
});
|
|
282
|
+
walkWithKeys(result.ast, null);
|
|
252
283
|
|
|
253
284
|
// Splice template tokens into the AST token stream.
|
|
254
285
|
//
|