ember-estree 0.0.0 → 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/package.json CHANGED
@@ -1,25 +1,51 @@
1
1
  {
2
2
  "name": "ember-estree",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "description": "ESTree generator for gjs and gts file used by ember",
5
+ "keywords": [
6
+ "AST",
7
+ "codemod",
8
+ "ember",
9
+ "estree",
10
+ "glimmer",
11
+ "traversal",
12
+ "walker"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "NullVoxPopuli",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git@github.com:NullVoxPopuli/ember-estree.git"
19
+ },
20
+ "files": [
21
+ "src"
22
+ ],
5
23
  "type": "module",
6
- "main": "index.js",
7
- "keywords": [],
8
- "author": "",
9
- "license": "ISC",
24
+ "main": "src/index.js",
25
+ "exports": {
26
+ ".": "./src/index.js"
27
+ },
10
28
  "dependencies": {
11
- "@babel/core": "^7.28.4",
12
- "@babel/parser": "^7.28.4",
13
- "@babel/plugin-transform-typescript": "^7.28.0",
14
29
  "@glimmer/syntax": "^0.95.0",
15
- "content-tag": "^4.0.0",
16
- "content-tag-utils": "^0.4.1",
17
- "decorator-transforms": "^2.3.0"
30
+ "content-tag-utils": "^0.5.1",
31
+ "ember-template-recast": "^6.1.5",
32
+ "oxc-parser": "^0.119.0",
33
+ "zimmerframe": "^1.1.4"
18
34
  },
19
35
  "devDependencies": {
36
+ "@tsconfig/node-lts": "^22.0.2",
37
+ "oxfmt": "^0.40.0",
38
+ "oxlint": "^1.55.0",
39
+ "publint": "^0.3.18",
40
+ "release-plan": "^0.17.4",
41
+ "typescript": "^5.9.3",
20
42
  "vitest": "^3.2.4"
21
43
  },
22
44
  "scripts": {
23
- "test": "echo \"Error: no test specified\" && exit 1"
45
+ "format": "oxfmt",
46
+ "format:check": "oxfmt --check",
47
+ "lint": "oxlint && pnpm format:check && publint",
48
+ "lint:fix": "oxlint --fix && oxfmt",
49
+ "test": "vitest run"
24
50
  }
25
51
  }
package/src/index.js CHANGED
@@ -1,15 +1,3 @@
1
- /**
2
- * The Strategy:
3
- *
4
- * 1. parse out the <template>...</template> regions
5
- * - we haven't shipped "content-tag" through TC39, so for now, gjs and gts are invalid JavaScript
6
- * 2. create a new string/contents of the file with a placeholder for the template regisions
7
- * - this will be used later to splice in the Template AST Nodes
8
- * - the placeholder should be the same dimensions as the template region
9
- * 3. parse the string/contents as js/ts to generate an ESTree
10
- * 4. parse each template region to generate an AST from that
11
- * 5. convert the AST from `@glimmer/syntax` to ESTree
12
- * - NOTE: it may already be ESTree
13
- * 6. splice in the template ESTrees into the JS/TS ESTree
14
- * 7. Done
15
- */
1
+ export { toTree, parse } from "./parse.js";
2
+ export { print } from "./print.js";
3
+ export { buildGlimmerVisitorKeys, DocumentLines } from "./transforms.js";
package/src/parse.js ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * The Strategy:
3
+ *
4
+ * 1. parse out the <template>...</template> regions
5
+ * - we haven't shipped "content-tag" through TC39, so for now, gjs and gts are invalid JavaScript
6
+ *
7
+ * 2. create a new string/contents of the file with a placeholder for the template regisions
8
+ * - this will be used later to splice in the Template AST Nodes
9
+ * - the placeholder should be the same dimensions as the template region
10
+ *
11
+ * 3. parse the string/contents as js/ts to generate an ESTree
12
+ *
13
+ * 4. parse each template region to generate an AST from that
14
+ *
15
+ * 5. convert the AST from `@glimmer/syntax` to ESTree
16
+ * - NOTE: it may already be ESTree
17
+ *
18
+ * 6. splice in the template ESTrees into the JS/TS ESTree
19
+ *
20
+ * 7. Done
21
+ */
22
+
23
+ /**
24
+ * Docs for dependencies:
25
+ * - https://github.com/embroider-build/content-tag/
26
+ */
27
+
28
+ import { parseSync } from "oxc-parser";
29
+ import templateRecast from "ember-template-recast";
30
+ import { Transformer } from "content-tag-utils";
31
+ import { walk } from "zimmerframe";
32
+
33
+ import { processGlimmerTemplate } from "./transforms.js";
34
+
35
+ /**
36
+ * @param {string} source
37
+ * @param {object} options
38
+ * @return {object} A File-like AST with a `.program` property
39
+ */
40
+ export function toTree(source, options = {}) {
41
+ let t = new Transformer(source);
42
+ let js = t.toString({ placeholders: true });
43
+
44
+ let filename = options.filePath || "input.ts";
45
+ let oxcResult = parseSync(filename, js);
46
+
47
+ // Wrap in a File-like node to match the expected structure
48
+ let outerAST = {
49
+ type: "File",
50
+ program: oxcResult.program,
51
+ comments: oxcResult.comments || [],
52
+ start: oxcResult.program.start,
53
+ end: oxcResult.program.end,
54
+ };
55
+
56
+ let parseResults = t.parseResults;
57
+
58
+ outerAST = walk(outerAST, null, {
59
+ _(node, { next }) {
60
+ if (isExpressionPlaceholder(node)) {
61
+ let parseResult = parseResults.find((r) => {
62
+ // WARNING: these are byte ranges
63
+ return node.start === r.range.start && node.end === r.range.end;
64
+ });
65
+
66
+ let content = t.stringUtils.originalContentOf(parseResult);
67
+ let templateAST = templateRecast.parse(content);
68
+
69
+ let contentOffset = parseResult.contentRange.start;
70
+ let templateRange = [parseResult.range.start, parseResult.range.end];
71
+
72
+ return processGlimmerTemplate(templateAST, {
73
+ contentOffset,
74
+ templateRange,
75
+ source,
76
+ });
77
+ }
78
+ next();
79
+ },
80
+ });
81
+
82
+ let ast = outerAST;
83
+
84
+ return ast;
85
+ }
86
+
87
+ /**
88
+ * Parse Ember .gjs/.gts source code into an ESTree-compatible AST
89
+ * with embedded Glimmer template nodes.
90
+ *
91
+ * @param {string} source - The source code to parse
92
+ * @param {object} [options] - Parse options
93
+ * @return {object} The ESTree-compatible AST
94
+ */
95
+ export function parse(source, options = {}) {
96
+ let ast = toTree(source, options);
97
+
98
+ return ast;
99
+ }
100
+
101
+ //////////////////////////////////////////////////
102
+ //
103
+ // Helpers
104
+ //
105
+ //////////////////////////////////////////////////
106
+
107
+ function isExpressionPlaceholder(node) {
108
+ if (node.type !== "CallExpression") return;
109
+
110
+ return node.callee.name === "TEMPLATE_TEMPLATE";
111
+ }