zmod-ember 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/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # zmod-ember
2
+
3
+ This repo provides an adapter for [zmod](https://github.com/NaamuKim/zmod) for ember's gjs and gts files via [ember-estree](https://github.com/NullVoxPopuli/ember-estree) as zmod's default parser is [oxc](https://github.com/oxc-project/oxc)-parser, which is ESTree-compatible.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add zmod-ember zmod
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### With `z.withParser()`
14
+
15
+ ```ts
16
+ import { z } from "zmod";
17
+ import { emberParser } from "zmod-ember";
18
+
19
+ const j = z.withParser(emberParser);
20
+
21
+ const source = `import Component from '@glimmer/component';
22
+
23
+ export default class OldComponent extends Component {
24
+ <template>
25
+ <h1>Hello {{@name}}</h1>
26
+ </template>
27
+ }
28
+ `;
29
+
30
+ const root = j(source, { filePath: "my-component.gjs" });
31
+
32
+ root.find(j.Identifier, { name: "OldComponent" }).replaceWith("NewComponent");
33
+
34
+ console.log(root.toSource());
35
+ ```
36
+
37
+ ### As a transform module
38
+
39
+ ```ts
40
+ import type { Transform } from "zmod";
41
+ import { emberParser } from "zmod-ember";
42
+
43
+ // Export the parser so zmod's `run()` uses it for all files
44
+ export const parser = emberParser;
45
+
46
+ const transform: Transform = ({ source, path }, { z }) => {
47
+ const root = z(source, { filePath: path });
48
+
49
+ root.find(z.Identifier, { name: "OldName" }).replaceWith("NewName");
50
+
51
+ return root.toSource();
52
+ };
53
+
54
+ export default transform;
55
+ ```
56
+
57
+ ### Operating on Glimmer nodes
58
+
59
+ Glimmer template nodes are exposed as `Glimmer*`-prefixed types and can be found using string-based type queries:
60
+
61
+ ```ts
62
+ import { z } from "zmod";
63
+ import { emberParser } from "zmod-ember";
64
+
65
+ const j = z.withParser(emberParser);
66
+
67
+ const source = `<template>
68
+ <OldComponent @oldArg={{this.value}}>
69
+ <:header>Header</:header>
70
+ </OldComponent>
71
+ </template>
72
+ `;
73
+
74
+ const root = j(source, { filePath: "component.gjs" });
75
+
76
+ // Rename a component
77
+ root.find("GlimmerElementNode", { tag: "OldComponent" }).forEach((path) => {
78
+ path.node.tag = "NewComponent";
79
+ });
80
+
81
+ // Rename an argument
82
+ root.find("GlimmerAttrNode", { name: "@oldArg" }).replaceWith("@newArg={{this.value}}");
83
+
84
+ // Rename a named block
85
+ root.find("GlimmerElementNode", { tag: ":header" }).replaceWith("<:title>Header</:title>");
86
+
87
+ console.log(root.toSource());
88
+ ```
89
+
90
+ Other Glimmer node types you can query include `GlimmerMustacheStatement`, `GlimmerBlockStatement`, `GlimmerPathExpression`, `GlimmerTextNode`, `GlimmerElementModifierStatement`, `GlimmerSubExpression`, `GlimmerHashPair`, `GlimmerStringLiteral`, `GlimmerNumberLiteral`, and `GlimmerBlockParam`.
91
+
92
+ ### Running transforms
93
+
94
+ ```ts
95
+ import { run } from "zmod";
96
+ import transform from "./my-transform.js";
97
+
98
+ const result = await run(transform, {
99
+ include: ["src/**/*.gjs", "src/**/*.gts"],
100
+ });
101
+
102
+ console.log(result.files);
103
+ ```
104
+
105
+ ## How it works
106
+
107
+ The adapter wraps [ember-estree](https://github.com/NullVoxPopuli/ember-estree)'s `toTree()` to implement zmod's [`Parser` interface](https://github.com/NaamuKim/zmod/blob/main/packages/zmod/src/parser.ts):
108
+
109
+ - **`parse(source, options)`** — Calls `toTree` and returns an ESTree-compatible AST with embedded Glimmer template nodes. All nodes are guaranteed to have `start`/`end` byte-offset properties required by zmod's span-based patching. Handles both top-level and class body `<template>` tags.
110
+ - **`print(node)`** — Serializes AST nodes back to source code. Handles standard ESTree nodes and Glimmer template nodes (e.g., `GlimmerElementNode`, `GlimmerMustacheStatement`).
111
+
112
+ Pass `{ filePath: 'name.gjs' }` or `{ filePath: 'name.gts' }` in the parse options to control the file type.
113
+
114
+ > **Note:** Use zmod's default parser for plain `.js` and `.ts` files — `zmod-ember` is only needed for `.gjs` and `.gts` files that contain `<template>` tags. For codemods that target both standard JS/TS and Ember template files, use `zmod-ember` only for the `.gjs`/`.gts` files:
115
+ >
116
+ > ```ts
117
+ > import { z, run } from "zmod";
118
+ > import { emberParser } from "zmod-ember";
119
+ >
120
+ > // For .gjs/.gts files, use the ember parser
121
+ > const gjsTransform = ({ source, path }, { z }) => {
122
+ > return z(source, { filePath: path })
123
+ > .find(z.Identifier, { name: "OldName" })
124
+ > .replaceWith("NewName")
125
+ > .toSource();
126
+ > };
127
+ > gjsTransform.parser = emberParser;
128
+ >
129
+ > // For .js/.ts files, use zmod's default parser (no parser export needed)
130
+ > const jsTransform = ({ source }, { z }) => {
131
+ > return z(source).find(z.Identifier, { name: "OldName" }).replaceWith("NewName").toSource();
132
+ > };
133
+ > ```
134
+
135
+ ## Peer dependencies
136
+
137
+ | Package | Required | Notes |
138
+ | ------- | -------- | -------------------- |
139
+ | `zmod` | Yes | Core codemod toolkit |
@@ -0,0 +1,40 @@
1
+ import type { Parser } from "zmod";
2
+ /**
3
+ * A zmod `Parser` adapter for Ember's `.gjs` and `.gts` files.
4
+ *
5
+ * Uses `ember-estree` to parse files containing `<template>` tags
6
+ * into an ESTree-compatible AST with embedded Glimmer template nodes.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { z } from 'zmod';
11
+ * import { emberParser } from 'zmod-ember';
12
+ *
13
+ * const j = z.withParser(emberParser);
14
+ * const root = j(gjsSource, { filePath: 'my-component.gjs' });
15
+ *
16
+ * root.find(j.Identifier, { name: 'OldName' })
17
+ * .replaceWith('NewName');
18
+ *
19
+ * console.log(root.toSource());
20
+ * ```
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // As a transform module export
25
+ * import type { Transform } from 'zmod';
26
+ * import { emberParser } from 'zmod-ember';
27
+ *
28
+ * export const parser = emberParser;
29
+ *
30
+ * const transform: Transform = ({ source }, { z }) => {
31
+ * const root = z(source);
32
+ * // ... transform logic
33
+ * return root.toSource();
34
+ * };
35
+ *
36
+ * export default transform;
37
+ * ```
38
+ */
39
+ export declare const emberParser: Parser;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,MAAM,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,WAAW,EAAE,MAOzB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ import { toTree, print as emberPrint } from "ember-estree";
2
+ /**
3
+ * A zmod `Parser` adapter for Ember's `.gjs` and `.gts` files.
4
+ *
5
+ * Uses `ember-estree` to parse files containing `<template>` tags
6
+ * into an ESTree-compatible AST with embedded Glimmer template nodes.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { z } from 'zmod';
11
+ * import { emberParser } from 'zmod-ember';
12
+ *
13
+ * const j = z.withParser(emberParser);
14
+ * const root = j(gjsSource, { filePath: 'my-component.gjs' });
15
+ *
16
+ * root.find(j.Identifier, { name: 'OldName' })
17
+ * .replaceWith('NewName');
18
+ *
19
+ * console.log(root.toSource());
20
+ * ```
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // As a transform module export
25
+ * import type { Transform } from 'zmod';
26
+ * import { emberParser } from 'zmod-ember';
27
+ *
28
+ * export const parser = emberParser;
29
+ *
30
+ * const transform: Transform = ({ source }, { z }) => {
31
+ * const root = z(source);
32
+ * // ... transform logic
33
+ * return root.toSource();
34
+ * };
35
+ *
36
+ * export default transform;
37
+ * ```
38
+ */
39
+ export const emberParser = {
40
+ parse(source, options) {
41
+ return toTree(source, options);
42
+ },
43
+ print(node) {
44
+ return emberPrint(node);
45
+ },
46
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "zmod-ember",
3
+ "version": "0.1.0",
4
+ "description": "zmod parser adapter for Ember's .gjs and .gts files via ember-estree",
5
+ "keywords": [
6
+ "codemod",
7
+ "ember",
8
+ "gjs",
9
+ "glimmer",
10
+ "gts",
11
+ "parser",
12
+ "zmod"
13
+ ],
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/NullVoxPopuli/zmod-ember.git"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "src"
22
+ ],
23
+ "type": "module",
24
+ "main": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "import": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ }
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "ember-estree": "^0.2.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^25.5.0",
39
+ "oxfmt": "^0.40.0",
40
+ "oxlint": "^1.55.0",
41
+ "release-plan": "^0.17.4",
42
+ "typescript": "^5.3.3",
43
+ "vitest": "^3.2.1",
44
+ "zmod": "^0.3.1"
45
+ },
46
+ "peerDependencies": {
47
+ "zmod": "^0.3.1"
48
+ },
49
+ "engines": {
50
+ "node": ">=20.19.0"
51
+ },
52
+ "publishConfig": {
53
+ "registry": "https://registry.npmjs.org",
54
+ "access": "public"
55
+ },
56
+ "scripts": {
57
+ "format": "oxfmt",
58
+ "format:check": "oxfmt --check",
59
+ "lint": "oxlint && pnpm format:check",
60
+ "lint:fix": "oxlint --fix && oxfmt",
61
+ "test": "vitest run"
62
+ }
63
+ }
package/src/index.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { toTree, print as emberPrint } from "ember-estree";
2
+ import type { Parser, ParseOptions } from "zmod";
3
+
4
+ /**
5
+ * A zmod `Parser` adapter for Ember's `.gjs` and `.gts` files.
6
+ *
7
+ * Uses `ember-estree` to parse files containing `<template>` tags
8
+ * into an ESTree-compatible AST with embedded Glimmer template nodes.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { z } from 'zmod';
13
+ * import { emberParser } from 'zmod-ember';
14
+ *
15
+ * const j = z.withParser(emberParser);
16
+ * const root = j(gjsSource, { filePath: 'my-component.gjs' });
17
+ *
18
+ * root.find(j.Identifier, { name: 'OldName' })
19
+ * .replaceWith('NewName');
20
+ *
21
+ * console.log(root.toSource());
22
+ * ```
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * // As a transform module export
27
+ * import type { Transform } from 'zmod';
28
+ * import { emberParser } from 'zmod-ember';
29
+ *
30
+ * export const parser = emberParser;
31
+ *
32
+ * const transform: Transform = ({ source }, { z }) => {
33
+ * const root = z(source);
34
+ * // ... transform logic
35
+ * return root.toSource();
36
+ * };
37
+ *
38
+ * export default transform;
39
+ * ```
40
+ */
41
+ export const emberParser: Parser = {
42
+ parse(source: string, options?: ParseOptions): any {
43
+ return toTree(source, options as any);
44
+ },
45
+ print(node: any): string {
46
+ return emberPrint(node);
47
+ },
48
+ };