@praxisjs/vite-plugin 3.0.0 → 4.0.1
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/CHANGELOG.md +22 -0
- package/dist/__tests__/index.test.js +217 -48
- package/dist/__tests__/index.test.js.map +1 -1
- package/dist/decorators.d.ts +3 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +84 -0
- package/dist/decorators.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +7 -4
- package/src/__tests__/index.test.ts +249 -52
- package/src/decorators.ts +99 -0
- package/src/index.ts +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @praxisjs/vite-plugin
|
|
2
2
|
|
|
3
|
+
## 4.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 22d9a4e: Move `esbuild` from `devDependencies` to `dependencies`. It's imported at runtime by the CSS extraction step, so it was missing from `node_modules` in consumer projects (e.g. `create-praxisjs` scaffolds), causing `ERR_MODULE_NOT_FOUND: esbuild` on `vite dev`/`vite build`.
|
|
8
|
+
|
|
9
|
+
## 4.0.0
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- 9c2a7e0: Upgraded to Vite 8 (rolldown-vite). Vite 8's oxc-based transform doesn't lower TC39 (non-legacy) decorators yet ([oxc-project/oxc#9170](https://github.com/oxc-project/oxc/issues/9170)), so `praxisjs()` now uses the TypeScript compiler (`ts.transpileModule`) to lower decorator syntax into runtime-executable code, leaving JSX untouched for oxc's own JSX pipeline. No third-party decorator transform is bundled — TypeScript's decorator lowering keeps class fields as native ES2022 fields, so a decorated field's `addInitializer` callback already runs after `super()` in a derived class's explicit constructor without any extra fix-up pass.
|
|
14
|
+
|
|
15
|
+
The `esbuild` config key (deprecated in Vite 8) was replaced with `oxc` in the plugin's own `config()` hook.
|
|
16
|
+
|
|
17
|
+
`typescript` moved from a `devDependency` to a regular `dependency`, since the decorator-lowering pass now calls it at runtime — it's pulled in automatically, no action needed.
|
|
18
|
+
|
|
19
|
+
**Breaking:** `@praxisjs/vite-plugin` now requires Vite `^8.0.0`. Apps still on Vite 7 should stay on the previous `@praxisjs/vite-plugin` major version.
|
|
20
|
+
|
|
21
|
+
**Also requires `useDefineForClassFields: true`** in your `tsconfig.json` (previously `false`) — see the updated [Getting Started](/docs/guide/getting-started) guide. With `false`, oxc silently drops a class field's decorator during its own TypeScript stripping, before the lowering step ever sees it.
|
|
22
|
+
|
|
23
|
+
**`decoratorLoweringPlugin()` is now exported** alongside `praxisjs()`, so it can be registered directly in `vitest.config.ts` (or any other Vite-based tool) to lower decorator syntax outside of the full `praxisjs()` plugin — see [Using decorators in Vitest](/docs/tooling/vite-plugin#using-decorators-in-vitest).
|
|
24
|
+
|
|
3
25
|
## 3.0.0
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -1,68 +1,249 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
1
2
|
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { praxisjs } from "../index";
|
|
3
|
+
import { praxisjs, decoratorLoweringPlugin } from "../index";
|
|
4
|
+
// `ts.transpileModule`'s own types mark `diagnostics` and `sourceMapText` as
|
|
5
|
+
// optional regardless of the options passed in — wrapping it lets a couple
|
|
6
|
+
// of tests below simulate that contract even though it never happens with
|
|
7
|
+
// the fixed options `decoratorLoweringPlugin()` always calls it with.
|
|
8
|
+
vi.mock("typescript", async (importOriginal) => {
|
|
9
|
+
const actual = (await importOriginal());
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
default: {
|
|
13
|
+
...actual.default,
|
|
14
|
+
transpileModule: vi.fn(actual.default.transpileModule),
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
function transformedCode(result) {
|
|
19
|
+
if (result == null || typeof result === "string")
|
|
20
|
+
return result;
|
|
21
|
+
return result.code;
|
|
22
|
+
}
|
|
23
|
+
function findPlugin(plugins, name) {
|
|
24
|
+
const plugin = plugins.find((p) => p.name === name);
|
|
25
|
+
if (!plugin)
|
|
26
|
+
throw new Error(`plugin "${name}" not found`);
|
|
27
|
+
return plugin;
|
|
28
|
+
}
|
|
3
29
|
describe("praxisjs() plugin factory", () => {
|
|
4
|
-
it("returns
|
|
30
|
+
it("returns three plugins by default (decorators + core + hmr)", () => {
|
|
5
31
|
const plugins = praxisjs();
|
|
6
|
-
expect(plugins).toHaveLength(
|
|
32
|
+
expect(plugins).toHaveLength(3);
|
|
7
33
|
});
|
|
8
|
-
it("returns
|
|
34
|
+
it("returns two plugins when hmr is disabled", () => {
|
|
9
35
|
const plugins = praxisjs({ hmr: false });
|
|
10
|
-
expect(plugins).toHaveLength(
|
|
36
|
+
expect(plugins).toHaveLength(2);
|
|
11
37
|
});
|
|
12
38
|
it("core plugin has the correct name", () => {
|
|
13
|
-
const
|
|
39
|
+
const core = findPlugin(praxisjs(), "praxisjs:core");
|
|
14
40
|
expect(core.name).toBe("praxisjs:core");
|
|
15
41
|
});
|
|
16
42
|
it("core plugin enforces 'pre'", () => {
|
|
17
|
-
const
|
|
43
|
+
const core = findPlugin(praxisjs(), "praxisjs:core");
|
|
18
44
|
expect(core.enforce).toBe("pre");
|
|
19
45
|
});
|
|
20
46
|
it("hmr plugin has the correct name", () => {
|
|
21
|
-
const
|
|
47
|
+
const hmr = findPlugin(praxisjs(), "praxisjs:hmr");
|
|
22
48
|
expect(hmr.name).toBe("praxisjs:hmr");
|
|
23
49
|
});
|
|
24
50
|
it("hmr plugin enforces 'post'", () => {
|
|
25
|
-
const
|
|
51
|
+
const hmr = findPlugin(praxisjs(), "praxisjs:hmr");
|
|
26
52
|
expect(hmr.enforce).toBe("post");
|
|
27
53
|
});
|
|
54
|
+
it("omits the hmr plugin when hmr is disabled", () => {
|
|
55
|
+
const plugins = praxisjs({ hmr: false });
|
|
56
|
+
expect(plugins.find((p) => p.name === "praxisjs:hmr")).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
it("includes the decorator-lowering plugin", () => {
|
|
59
|
+
const plugins = praxisjs();
|
|
60
|
+
expect(findPlugin(plugins, "praxisjs:decorators")).toBeDefined();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe("decoratorLoweringPlugin() standalone export", () => {
|
|
64
|
+
it("is exported so it can be reused outside of praxisjs(), e.g. in vitest.config.ts", () => {
|
|
65
|
+
const plugin = decoratorLoweringPlugin();
|
|
66
|
+
expect(plugin.name).toBe("praxisjs:decorators");
|
|
67
|
+
});
|
|
68
|
+
it("lowers decorators the same way whether reused standalone or via praxisjs()", () => {
|
|
69
|
+
const code = `
|
|
70
|
+
function Dec() { return function (v, ctx) {}; }
|
|
71
|
+
class Foo {
|
|
72
|
+
@Dec()
|
|
73
|
+
accent = "red";
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
const standalone = decoratorLoweringPlugin();
|
|
77
|
+
const result = transformedCode(standalone.transform?.(code, "component.ts"));
|
|
78
|
+
expect(result).toBeTruthy();
|
|
79
|
+
expect(result).not.toContain("@Dec()");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe("praxisjs:decorators transform()", () => {
|
|
83
|
+
it("lowers a real decorator into runtime-executable code", () => {
|
|
84
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
85
|
+
const code = `
|
|
86
|
+
function Dec() { return function (v, ctx) {}; }
|
|
87
|
+
class Foo {
|
|
88
|
+
@Dec()
|
|
89
|
+
accent = "red";
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
92
|
+
const result = transformedCode(decorators.transform?.(code, "component.ts"));
|
|
93
|
+
expect(result).toBeTruthy();
|
|
94
|
+
expect(result).not.toContain("@Dec()");
|
|
95
|
+
});
|
|
96
|
+
it("returns null for a file with '@' only in a comment (no real decorator)", () => {
|
|
97
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
98
|
+
const code = `
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
100
|
+
export function identity(signal) { return signal; }
|
|
101
|
+
`;
|
|
102
|
+
const result = decorators.transform?.(code, "utils.ts");
|
|
103
|
+
expect(result).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
it("returns null for non-JS/TS files", () => {
|
|
106
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
107
|
+
const result = decorators.transform?.("@import 'x.css';", "styles.css");
|
|
108
|
+
expect(result).toBeNull();
|
|
109
|
+
});
|
|
110
|
+
it("lowers a real decorator in a .tsx file, leaving JSX untouched", () => {
|
|
111
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
112
|
+
const code = `
|
|
113
|
+
function Dec() { return function (v, ctx) {}; }
|
|
114
|
+
class Foo {
|
|
115
|
+
@Dec()
|
|
116
|
+
accent = "red";
|
|
117
|
+
render() { return <div>{this.accent}</div>; }
|
|
118
|
+
}
|
|
119
|
+
`;
|
|
120
|
+
const result = transformedCode(decorators.transform?.(code, "component.tsx"));
|
|
121
|
+
expect(result).toBeTruthy();
|
|
122
|
+
expect(result).not.toContain("@Dec()");
|
|
123
|
+
expect(result).toContain("<div>{this.accent}</div>");
|
|
124
|
+
});
|
|
125
|
+
it("lowers a real decorator in a .jsx file, leaving JSX untouched", () => {
|
|
126
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
127
|
+
const code = `
|
|
128
|
+
function Dec() { return function (v, ctx) {}; }
|
|
129
|
+
class Foo {
|
|
130
|
+
@Dec()
|
|
131
|
+
accent = "red";
|
|
132
|
+
render() { return <div>{this.accent}</div>; }
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
const result = transformedCode(decorators.transform?.(code, "component.jsx"));
|
|
136
|
+
expect(result).toBeTruthy();
|
|
137
|
+
expect(result).not.toContain("@Dec()");
|
|
138
|
+
expect(result).toContain("<div>{this.accent}</div>");
|
|
139
|
+
});
|
|
140
|
+
it("lowers a real decorator in a plain .js file", () => {
|
|
141
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
142
|
+
const code = `
|
|
143
|
+
function Dec() { return function (v, ctx) {}; }
|
|
144
|
+
class Foo {
|
|
145
|
+
@Dec()
|
|
146
|
+
accent = "red";
|
|
147
|
+
}
|
|
148
|
+
`;
|
|
149
|
+
const result = transformedCode(decorators.transform?.(code, "component.js"));
|
|
150
|
+
expect(result).toBeTruthy();
|
|
151
|
+
expect(result).not.toContain("@Dec()");
|
|
152
|
+
});
|
|
153
|
+
it("keeps a field decorator's addInitializer running after super() in a derived class", () => {
|
|
154
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
155
|
+
const code = `
|
|
156
|
+
function Dec() {
|
|
157
|
+
return function (value, ctx) {
|
|
158
|
+
ctx.addInitializer(function () { this.order.push("field:" + ctx.name); });
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
class Base {
|
|
162
|
+
constructor(order) { this.order = order; this.order.push("super"); }
|
|
163
|
+
}
|
|
164
|
+
class Comp extends Base {
|
|
165
|
+
@Dec()
|
|
166
|
+
accent = "red";
|
|
167
|
+
constructor(order) {
|
|
168
|
+
super(order);
|
|
169
|
+
order.push("after-super");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
const result = transformedCode(decorators.transform?.(code, "component.ts"));
|
|
174
|
+
expect(result).toBeTruthy();
|
|
175
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
176
|
+
const factory = new Function(`${result}\nreturn Comp;`);
|
|
177
|
+
const Comp = factory();
|
|
178
|
+
const order = [];
|
|
179
|
+
new Comp(order);
|
|
180
|
+
expect(order).toEqual(["super", "field:accent", "after-super"]);
|
|
181
|
+
});
|
|
182
|
+
it("throws on invalid decorator syntax instead of silently emitting broken code", () => {
|
|
183
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
184
|
+
const code = `
|
|
185
|
+
class Foo {
|
|
186
|
+
@ accent = "red";
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
189
|
+
// An absolute id (as Vite always passes) makes TypeScript canonicalize
|
|
190
|
+
// the file name while formatting the diagnostic message.
|
|
191
|
+
expect(() => decorators.transform?.(code, "/src/component.ts")).toThrow();
|
|
192
|
+
});
|
|
193
|
+
it("returns a null map when ts.transpileModule omits sourceMapText", () => {
|
|
194
|
+
const transpileModule = ts.transpileModule;
|
|
195
|
+
transpileModule.mockReturnValueOnce({
|
|
196
|
+
outputText: "class Foo {}",
|
|
197
|
+
diagnostics: [],
|
|
198
|
+
sourceMapText: undefined,
|
|
199
|
+
});
|
|
200
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
201
|
+
const result = decorators.transform?.("class Foo { @Dec() x = 1; }", "component.ts");
|
|
202
|
+
expect(result).toEqual({ code: "class Foo {}", map: null });
|
|
203
|
+
});
|
|
204
|
+
it("does not throw when ts.transpileModule omits diagnostics", () => {
|
|
205
|
+
const transpileModule = ts.transpileModule;
|
|
206
|
+
transpileModule.mockReturnValueOnce({
|
|
207
|
+
outputText: "class Foo {}",
|
|
208
|
+
diagnostics: undefined,
|
|
209
|
+
sourceMapText: undefined,
|
|
210
|
+
});
|
|
211
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
212
|
+
expect(() => decorators.transform?.("class Foo { @Dec() x = 1; }", "component.ts")).not.toThrow();
|
|
213
|
+
});
|
|
28
214
|
});
|
|
29
215
|
describe("praxisjs:core config()", () => {
|
|
30
|
-
it("sets
|
|
31
|
-
const
|
|
32
|
-
const config = core.config();
|
|
33
|
-
expect(config).toEqual({
|
|
216
|
+
it("sets oxc target to es2022", () => {
|
|
217
|
+
const core = findPlugin(praxisjs(), "praxisjs:core");
|
|
218
|
+
const config = core.config?.();
|
|
219
|
+
expect(config).toEqual({ oxc: { target: "es2022" } });
|
|
34
220
|
});
|
|
35
221
|
});
|
|
36
222
|
describe("praxisjs:core transform()", () => {
|
|
37
223
|
it("returns null for .tsx files when autoImport is enabled", () => {
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const result = transform("const x = 1;", "component.tsx");
|
|
224
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
225
|
+
const result = core.transform?.("const x = 1;", "component.tsx");
|
|
41
226
|
expect(result).toBeNull();
|
|
42
227
|
});
|
|
43
228
|
it("returns null for .jsx files when autoImport is enabled", () => {
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const result = transform("const x = 1;", "component.jsx");
|
|
229
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
230
|
+
const result = core.transform?.("const x = 1;", "component.jsx");
|
|
47
231
|
expect(result).toBeNull();
|
|
48
232
|
});
|
|
49
233
|
it("returns undefined (no-op) for non-.tsx/.jsx files", () => {
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const result = transform("const x = 1;", "module.ts");
|
|
234
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
235
|
+
const result = core.transform?.("const x = 1;", "module.ts");
|
|
53
236
|
expect(result).toBeUndefined();
|
|
54
237
|
});
|
|
55
238
|
it("returns undefined when autoImport is false", () => {
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const result = transform("const x = 1;", "component.tsx");
|
|
239
|
+
const core = findPlugin(praxisjs({ autoImport: false }), "praxisjs:core");
|
|
240
|
+
const result = core.transform?.("const x = 1;", "component.tsx");
|
|
59
241
|
expect(result).toBeUndefined();
|
|
60
242
|
});
|
|
61
243
|
it("returns undefined when code already imports @praxisjs/jsx/jsx-runtime", () => {
|
|
62
|
-
const
|
|
63
|
-
const transform = core.transform;
|
|
244
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
64
245
|
const code = 'import "@praxisjs/jsx/jsx-runtime"; const x = 1;';
|
|
65
|
-
const result = transform(code, "component.tsx");
|
|
246
|
+
const result = core.transform?.(code, "component.tsx");
|
|
66
247
|
expect(result).toBeUndefined();
|
|
67
248
|
});
|
|
68
249
|
});
|
|
@@ -75,12 +256,9 @@ describe("praxisjs:hmr handleHotUpdate()", () => {
|
|
|
75
256
|
};
|
|
76
257
|
}
|
|
77
258
|
it("sends custom event for .ts files", () => {
|
|
78
|
-
const
|
|
259
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
79
260
|
const server = makeMockServer();
|
|
80
|
-
hmr.handleHotUpdate({
|
|
81
|
-
file: "src/app.ts",
|
|
82
|
-
server,
|
|
83
|
-
});
|
|
261
|
+
hmr.handleHotUpdate?.({ file: "src/app.ts", server });
|
|
84
262
|
expect(server.ws.send).toHaveBeenCalledWith({
|
|
85
263
|
type: "custom",
|
|
86
264
|
event: "praxisjs:component-update",
|
|
@@ -88,12 +266,9 @@ describe("praxisjs:hmr handleHotUpdate()", () => {
|
|
|
88
266
|
});
|
|
89
267
|
});
|
|
90
268
|
it("sends custom event for .tsx files", () => {
|
|
91
|
-
const
|
|
269
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
92
270
|
const server = makeMockServer();
|
|
93
|
-
hmr.handleHotUpdate({
|
|
94
|
-
file: "src/component.tsx",
|
|
95
|
-
server,
|
|
96
|
-
});
|
|
271
|
+
hmr.handleHotUpdate?.({ file: "src/component.tsx", server });
|
|
97
272
|
expect(server.ws.send).toHaveBeenCalledWith({
|
|
98
273
|
type: "custom",
|
|
99
274
|
event: "praxisjs:component-update",
|
|
@@ -101,21 +276,15 @@ describe("praxisjs:hmr handleHotUpdate()", () => {
|
|
|
101
276
|
});
|
|
102
277
|
});
|
|
103
278
|
it("does not send event for non-.ts/.tsx files", () => {
|
|
104
|
-
const
|
|
279
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
105
280
|
const server = makeMockServer();
|
|
106
|
-
hmr.handleHotUpdate({
|
|
107
|
-
file: "src/style.css",
|
|
108
|
-
server,
|
|
109
|
-
});
|
|
281
|
+
hmr.handleHotUpdate?.({ file: "src/style.css", server });
|
|
110
282
|
expect(server.ws.send).not.toHaveBeenCalled();
|
|
111
283
|
});
|
|
112
284
|
it("does not send event for .js files", () => {
|
|
113
|
-
const
|
|
285
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
114
286
|
const server = makeMockServer();
|
|
115
|
-
hmr.handleHotUpdate({
|
|
116
|
-
file: "src/utils.js",
|
|
117
|
-
server,
|
|
118
|
-
});
|
|
287
|
+
hmr.handleHotUpdate?.({ file: "src/utils.js", server });
|
|
119
288
|
expect(server.ws.send).not.toHaveBeenCalled();
|
|
120
289
|
});
|
|
121
290
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAC;QAC3B,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,QAAQ,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,QAAQ,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAI,IAA6C,CAAC,MAAM,EAAE,CAAC;QACvE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IAGzC,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAI,IAAmC,CAAC,SAAS,CAAC;QACjE,MAAM,MAAM,GAAG,SAAS,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAI,IAAmC,CAAC,SAAS,CAAC;QACjE,MAAM,MAAM,GAAG,SAAS,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAI,IAAmC,CAAC,SAAS,CAAC;QACjE,MAAM,MAAM,GAAG,SAAS,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAI,IAAmC,CAAC,SAAS,CAAC;QACjE,MAAM,MAAM,GAAG,SAAS,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAI,IAAmC,CAAC,SAAS,CAAC;QACjE,MAAM,IAAI,GAAG,kDAAkD,CAAC;QAChE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAG9C,SAAS,cAAc;QACrB,OAAO;YACL,EAAE,EAAE;gBACF,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;aACd;SACF,CAAC;IACJ,CAAC;IAED,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAC/B,GAAuD,CAAC,eAAe,CAAC;YACvE,IAAI,EAAE,YAAY;YAClB,MAAM;SACP,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC;YAC1C,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,2BAA2B;YAClC,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAC/B,GAAuD,CAAC,eAAe,CAAC;YACvE,IAAI,EAAE,mBAAmB;YACzB,MAAM;SACP,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC;YAC1C,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,2BAA2B;YAClC,IAAI,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE;SACpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAC/B,GAAuD,CAAC,eAAe,CAAC;YACvE,IAAI,EAAE,eAAe;YACrB,MAAM;SACP,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAC/B,GAAuD,CAAC,eAAe,CAAC;YACvE,IAAI,EAAE,cAAc;YACpB,MAAM;SACP,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAiEnC,wBAAgB,uBAAuB,IAAI,MAAM,CA+BhD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
const JS_LIKE_FILE = /\.[cm]?[jt]sx?(?:$|\?)/;
|
|
3
|
+
function cleanFileName(id) {
|
|
4
|
+
return id.split("?")[0];
|
|
5
|
+
}
|
|
6
|
+
function scriptKindFor(fileName) {
|
|
7
|
+
if (fileName.endsWith(".tsx"))
|
|
8
|
+
return ts.ScriptKind.TSX;
|
|
9
|
+
if (fileName.endsWith(".jsx"))
|
|
10
|
+
return ts.ScriptKind.JSX;
|
|
11
|
+
if (fileName.endsWith(".ts") || fileName.endsWith(".mts") || fileName.endsWith(".cts")) {
|
|
12
|
+
return ts.ScriptKind.TS;
|
|
13
|
+
}
|
|
14
|
+
return ts.ScriptKind.JS;
|
|
15
|
+
}
|
|
16
|
+
// The `code.includes("@")` pre-filter below also matches "@" in comments
|
|
17
|
+
// (JSDoc, eslint-disable directives), so this walks a real AST to confirm
|
|
18
|
+
// actual decorator syntax is present before reprocessing the file — some
|
|
19
|
+
// framework code (`@praxisjs/concurrent`'s `acceptsSignal`) relies on
|
|
20
|
+
// `fn.toString()` returning untouched source.
|
|
21
|
+
function hasRealDecorator(code, fileName) {
|
|
22
|
+
const source = ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, false, scriptKindFor(fileName));
|
|
23
|
+
let found = false;
|
|
24
|
+
const visit = (node) => {
|
|
25
|
+
if (found)
|
|
26
|
+
return;
|
|
27
|
+
if (ts.canHaveDecorators(node) && (ts.getDecorators(node)?.length ?? 0) > 0) {
|
|
28
|
+
found = true;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
ts.forEachChild(node, visit);
|
|
32
|
+
};
|
|
33
|
+
visit(source);
|
|
34
|
+
return found;
|
|
35
|
+
}
|
|
36
|
+
function formatDiagnostics(diagnostics) {
|
|
37
|
+
return ts.formatDiagnostics(diagnostics, {
|
|
38
|
+
getCanonicalFileName: (fileName) => fileName,
|
|
39
|
+
getCurrentDirectory: () => "",
|
|
40
|
+
getNewLine: () => "\n",
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// oxc doesn't lower TC39 (non-legacy) decorators yet — `@Decorator()`
|
|
44
|
+
// syntax passes through unchanged and no JS runtime executes it directly:
|
|
45
|
+
// https://github.com/oxc-project/oxc/issues/9170
|
|
46
|
+
//
|
|
47
|
+
// TypeScript's compiler lowers them instead (the same lowering `tsc` uses
|
|
48
|
+
// to build every package here). At ES2022 a decorated field stays a real
|
|
49
|
+
// class field rather than being rewritten into a constructor assignment,
|
|
50
|
+
// so its initializer runs after `super()` automatically — no separate
|
|
51
|
+
// ordering fix-up is needed. JSX is left untouched (`jsx: "preserve"`) for
|
|
52
|
+
// oxc's own JSX pipeline to handle.
|
|
53
|
+
export function decoratorLoweringPlugin() {
|
|
54
|
+
return {
|
|
55
|
+
name: "praxisjs:decorators",
|
|
56
|
+
transform(code, id) {
|
|
57
|
+
if (!JS_LIKE_FILE.test(id) || !code.includes("@"))
|
|
58
|
+
return null;
|
|
59
|
+
const fileName = cleanFileName(id);
|
|
60
|
+
if (!hasRealDecorator(code, fileName))
|
|
61
|
+
return null;
|
|
62
|
+
const { outputText, sourceMapText, diagnostics } = ts.transpileModule(code, {
|
|
63
|
+
fileName,
|
|
64
|
+
reportDiagnostics: true,
|
|
65
|
+
compilerOptions: {
|
|
66
|
+
target: ts.ScriptTarget.ES2022,
|
|
67
|
+
module: ts.ModuleKind.ESNext,
|
|
68
|
+
useDefineForClassFields: true,
|
|
69
|
+
jsx: ts.JsxEmit.Preserve,
|
|
70
|
+
sourceMap: true,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
const errors = diagnostics?.filter((d) => d.category === ts.DiagnosticCategory.Error) ?? [];
|
|
74
|
+
if (errors.length > 0) {
|
|
75
|
+
throw new Error(`[praxisjs:decorators] ${fileName}:\n${formatDiagnostics(errors)}`);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
code: outputText,
|
|
79
|
+
map: sourceMapText ? JSON.parse(sourceMapText) : null,
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=decorators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { praxisjsCSS } from "./css.js";
|
|
2
|
-
import
|
|
2
|
+
import { decoratorLoweringPlugin } from "./decorators.js";
|
|
3
|
+
import type { PluginOption } from "vite";
|
|
3
4
|
export { praxisjsCSS };
|
|
5
|
+
export { decoratorLoweringPlugin };
|
|
4
6
|
export interface PraxisJSVitePluginOptions {
|
|
5
7
|
hmr?: boolean;
|
|
6
8
|
autoImport?: boolean;
|
|
7
9
|
}
|
|
8
|
-
export declare function praxisjs(options?: PraxisJSVitePluginOptions):
|
|
10
|
+
export declare function praxisjs(options?: PraxisJSVitePluginOptions): PluginOption[];
|
|
9
11
|
export default praxisjs;
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,MAAM,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAEnC,MAAM,WAAW,yBAAyB;IACxC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,QAAQ,CAAC,OAAO,GAAE,yBAA8B,GAAG,YAAY,EAAE,CA8ChF;AAED,eAAe,QAAQ,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { praxisjsCSS } from "./css.js";
|
|
2
|
+
import { decoratorLoweringPlugin } from "./decorators.js";
|
|
2
3
|
export { praxisjsCSS };
|
|
4
|
+
export { decoratorLoweringPlugin };
|
|
3
5
|
export function praxisjs(options = {}) {
|
|
4
6
|
const { hmr = true, autoImport = true } = options;
|
|
5
7
|
return [
|
|
8
|
+
decoratorLoweringPlugin(),
|
|
6
9
|
{
|
|
7
10
|
name: "praxisjs:core",
|
|
8
11
|
enforce: "pre",
|
|
9
12
|
config() {
|
|
10
13
|
return {
|
|
11
|
-
|
|
14
|
+
oxc: {
|
|
12
15
|
target: "es2022",
|
|
13
16
|
},
|
|
14
17
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAI1D,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAOnC,MAAM,UAAU,QAAQ,CAAC,UAAqC,EAAE;IAC9D,MAAM,EAAE,GAAG,GAAG,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAElD,OAAO;QACL,uBAAuB,EAAE;QACzB;YACE,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,KAAK;YACd,MAAM;gBACJ,OAAO;oBACL,GAAG,EAAE;wBACH,MAAM,EAAE,QAAQ;qBACjB;iBACF,CAAC;YACJ,CAAC;YACD,SAAS,CAAC,IAAI,EAAE,EAAE;gBAChB,IAAI,CAAC,UAAU;oBAAE,OAAO;gBACxB,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,OAAO;gBACzD,IAAI,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC;oBAAE,OAAO;gBACvD,OAAO,IAAI,CAAC;YACd,CAAC;SACF;QACD,GAAG,CAAC,GAAG;YACL,CAAC,CAAC;gBACE;oBACE,IAAI,EAAE,cAAc;oBACpB,OAAO,EAAE,MAAe;oBACxB,eAAe,CAAC,EACd,IAAI,EACJ,MAAM,GAIP;wBACC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;4BAAE,OAAO;wBAE5D,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;4BACb,IAAI,EAAE,QAAQ;4BACd,KAAK,EAAE,2BAA2B;4BAClC,IAAI,EAAE,EAAE,IAAI,EAAE;yBACf,CAAC,CAAC;oBACL,CAAC;iBACF;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED,eAAe,QAAQ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/vite-plugin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,13 +11,16 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
+
"vite": ">=8.0.0",
|
|
14
15
|
"@praxisjs/css": "0.3.0"
|
|
15
16
|
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"esbuild": "^0.28.1",
|
|
19
|
+
"typescript": "^6.0.3"
|
|
20
|
+
},
|
|
16
21
|
"devDependencies": {
|
|
17
22
|
"@types/node": "^25.9.1",
|
|
18
|
-
"
|
|
19
|
-
"typescript": "^5.9.3",
|
|
20
|
-
"vite": "^7.3.1",
|
|
23
|
+
"vite": "^8.1.4",
|
|
21
24
|
"@praxisjs/css": "0.3.0"
|
|
22
25
|
},
|
|
23
26
|
"scripts": {
|
|
@@ -1,90 +1,299 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
1
2
|
import { describe, it, expect, vi } from "vitest";
|
|
2
3
|
|
|
3
|
-
import { praxisjs } from "../index";
|
|
4
|
+
import { praxisjs, decoratorLoweringPlugin } from "../index";
|
|
5
|
+
|
|
6
|
+
// `ts.transpileModule`'s own types mark `diagnostics` and `sourceMapText` as
|
|
7
|
+
// optional regardless of the options passed in — wrapping it lets a couple
|
|
8
|
+
// of tests below simulate that contract even though it never happens with
|
|
9
|
+
// the fixed options `decoratorLoweringPlugin()` always calls it with.
|
|
10
|
+
vi.mock("typescript", async (importOriginal) => {
|
|
11
|
+
const actual = (await importOriginal()) as typeof import("typescript") & {
|
|
12
|
+
default: typeof import("typescript");
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
...actual,
|
|
16
|
+
default: {
|
|
17
|
+
...actual.default,
|
|
18
|
+
transpileModule: vi.fn(actual.default.transpileModule),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
interface TransformResult {
|
|
24
|
+
code: string;
|
|
25
|
+
map?: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface NamedPlugin {
|
|
29
|
+
name?: string;
|
|
30
|
+
enforce?: string;
|
|
31
|
+
config?: () => unknown;
|
|
32
|
+
transform?: (code: string, id: string) => string | TransformResult | null | undefined;
|
|
33
|
+
handleHotUpdate?: (ctx: { file: string; server: unknown }) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function transformedCode(result: string | TransformResult | null | undefined): string | null | undefined {
|
|
37
|
+
if (result == null || typeof result === "string") return result;
|
|
38
|
+
return result.code;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function findPlugin(plugins: ReturnType<typeof praxisjs>, name: string): NamedPlugin {
|
|
42
|
+
const plugin = (plugins as NamedPlugin[]).find((p) => p.name === name);
|
|
43
|
+
if (!plugin) throw new Error(`plugin "${name}" not found`);
|
|
44
|
+
return plugin;
|
|
45
|
+
}
|
|
4
46
|
|
|
5
47
|
describe("praxisjs() plugin factory", () => {
|
|
6
|
-
it("returns
|
|
48
|
+
it("returns three plugins by default (decorators + core + hmr)", () => {
|
|
7
49
|
const plugins = praxisjs();
|
|
8
|
-
expect(plugins).toHaveLength(
|
|
50
|
+
expect(plugins).toHaveLength(3);
|
|
9
51
|
});
|
|
10
52
|
|
|
11
|
-
it("returns
|
|
53
|
+
it("returns two plugins when hmr is disabled", () => {
|
|
12
54
|
const plugins = praxisjs({ hmr: false });
|
|
13
|
-
expect(plugins).toHaveLength(
|
|
55
|
+
expect(plugins).toHaveLength(2);
|
|
14
56
|
});
|
|
15
57
|
|
|
16
58
|
it("core plugin has the correct name", () => {
|
|
17
|
-
const
|
|
59
|
+
const core = findPlugin(praxisjs(), "praxisjs:core");
|
|
18
60
|
expect(core.name).toBe("praxisjs:core");
|
|
19
61
|
});
|
|
20
62
|
|
|
21
63
|
it("core plugin enforces 'pre'", () => {
|
|
22
|
-
const
|
|
64
|
+
const core = findPlugin(praxisjs(), "praxisjs:core");
|
|
23
65
|
expect(core.enforce).toBe("pre");
|
|
24
66
|
});
|
|
25
67
|
|
|
26
68
|
it("hmr plugin has the correct name", () => {
|
|
27
|
-
const
|
|
69
|
+
const hmr = findPlugin(praxisjs(), "praxisjs:hmr");
|
|
28
70
|
expect(hmr.name).toBe("praxisjs:hmr");
|
|
29
71
|
});
|
|
30
72
|
|
|
31
73
|
it("hmr plugin enforces 'post'", () => {
|
|
32
|
-
const
|
|
74
|
+
const hmr = findPlugin(praxisjs(), "praxisjs:hmr");
|
|
33
75
|
expect(hmr.enforce).toBe("post");
|
|
34
76
|
});
|
|
77
|
+
|
|
78
|
+
it("omits the hmr plugin when hmr is disabled", () => {
|
|
79
|
+
const plugins = praxisjs({ hmr: false }) as NamedPlugin[];
|
|
80
|
+
expect(plugins.find((p) => p.name === "praxisjs:hmr")).toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("includes the decorator-lowering plugin", () => {
|
|
84
|
+
const plugins = praxisjs();
|
|
85
|
+
expect(findPlugin(plugins, "praxisjs:decorators")).toBeDefined();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("decoratorLoweringPlugin() standalone export", () => {
|
|
90
|
+
it("is exported so it can be reused outside of praxisjs(), e.g. in vitest.config.ts", () => {
|
|
91
|
+
const plugin = decoratorLoweringPlugin() as NamedPlugin;
|
|
92
|
+
expect(plugin.name).toBe("praxisjs:decorators");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("lowers decorators the same way whether reused standalone or via praxisjs()", () => {
|
|
96
|
+
const code = `
|
|
97
|
+
function Dec() { return function (v, ctx) {}; }
|
|
98
|
+
class Foo {
|
|
99
|
+
@Dec()
|
|
100
|
+
accent = "red";
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
const standalone = decoratorLoweringPlugin() as NamedPlugin;
|
|
104
|
+
const result = transformedCode(standalone.transform?.(code, "component.ts"));
|
|
105
|
+
expect(result).toBeTruthy();
|
|
106
|
+
expect(result).not.toContain("@Dec()");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("praxisjs:decorators transform()", () => {
|
|
111
|
+
it("lowers a real decorator into runtime-executable code", () => {
|
|
112
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
113
|
+
const code = `
|
|
114
|
+
function Dec() { return function (v, ctx) {}; }
|
|
115
|
+
class Foo {
|
|
116
|
+
@Dec()
|
|
117
|
+
accent = "red";
|
|
118
|
+
}
|
|
119
|
+
`;
|
|
120
|
+
const result = transformedCode(decorators.transform?.(code, "component.ts"));
|
|
121
|
+
expect(result).toBeTruthy();
|
|
122
|
+
expect(result).not.toContain("@Dec()");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("returns null for a file with '@' only in a comment (no real decorator)", () => {
|
|
126
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
127
|
+
const code = `
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
+
export function identity(signal) { return signal; }
|
|
130
|
+
`;
|
|
131
|
+
const result = decorators.transform?.(code, "utils.ts");
|
|
132
|
+
expect(result).toBeNull();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("returns null for non-JS/TS files", () => {
|
|
136
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
137
|
+
const result = decorators.transform?.("@import 'x.css';", "styles.css");
|
|
138
|
+
expect(result).toBeNull();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("lowers a real decorator in a .tsx file, leaving JSX untouched", () => {
|
|
142
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
143
|
+
const code = `
|
|
144
|
+
function Dec() { return function (v, ctx) {}; }
|
|
145
|
+
class Foo {
|
|
146
|
+
@Dec()
|
|
147
|
+
accent = "red";
|
|
148
|
+
render() { return <div>{this.accent}</div>; }
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
const result = transformedCode(decorators.transform?.(code, "component.tsx"));
|
|
152
|
+
expect(result).toBeTruthy();
|
|
153
|
+
expect(result).not.toContain("@Dec()");
|
|
154
|
+
expect(result).toContain("<div>{this.accent}</div>");
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("lowers a real decorator in a .jsx file, leaving JSX untouched", () => {
|
|
158
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
159
|
+
const code = `
|
|
160
|
+
function Dec() { return function (v, ctx) {}; }
|
|
161
|
+
class Foo {
|
|
162
|
+
@Dec()
|
|
163
|
+
accent = "red";
|
|
164
|
+
render() { return <div>{this.accent}</div>; }
|
|
165
|
+
}
|
|
166
|
+
`;
|
|
167
|
+
const result = transformedCode(decorators.transform?.(code, "component.jsx"));
|
|
168
|
+
expect(result).toBeTruthy();
|
|
169
|
+
expect(result).not.toContain("@Dec()");
|
|
170
|
+
expect(result).toContain("<div>{this.accent}</div>");
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("lowers a real decorator in a plain .js file", () => {
|
|
174
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
175
|
+
const code = `
|
|
176
|
+
function Dec() { return function (v, ctx) {}; }
|
|
177
|
+
class Foo {
|
|
178
|
+
@Dec()
|
|
179
|
+
accent = "red";
|
|
180
|
+
}
|
|
181
|
+
`;
|
|
182
|
+
const result = transformedCode(decorators.transform?.(code, "component.js"));
|
|
183
|
+
expect(result).toBeTruthy();
|
|
184
|
+
expect(result).not.toContain("@Dec()");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("keeps a field decorator's addInitializer running after super() in a derived class", () => {
|
|
188
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
189
|
+
const code = `
|
|
190
|
+
function Dec() {
|
|
191
|
+
return function (value, ctx) {
|
|
192
|
+
ctx.addInitializer(function () { this.order.push("field:" + ctx.name); });
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
class Base {
|
|
196
|
+
constructor(order) { this.order = order; this.order.push("super"); }
|
|
197
|
+
}
|
|
198
|
+
class Comp extends Base {
|
|
199
|
+
@Dec()
|
|
200
|
+
accent = "red";
|
|
201
|
+
constructor(order) {
|
|
202
|
+
super(order);
|
|
203
|
+
order.push("after-super");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
`;
|
|
207
|
+
const result = transformedCode(decorators.transform?.(code, "component.ts"));
|
|
208
|
+
expect(result).toBeTruthy();
|
|
209
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
210
|
+
const factory = new Function(`${result as string}\nreturn Comp;`);
|
|
211
|
+
const Comp = factory() as new (order: string[]) => unknown;
|
|
212
|
+
const order: string[] = [];
|
|
213
|
+
new Comp(order);
|
|
214
|
+
expect(order).toEqual(["super", "field:accent", "after-super"]);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("throws on invalid decorator syntax instead of silently emitting broken code", () => {
|
|
218
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
219
|
+
const code = `
|
|
220
|
+
class Foo {
|
|
221
|
+
@ accent = "red";
|
|
222
|
+
}
|
|
223
|
+
`;
|
|
224
|
+
// An absolute id (as Vite always passes) makes TypeScript canonicalize
|
|
225
|
+
// the file name while formatting the diagnostic message.
|
|
226
|
+
expect(() => decorators.transform?.(code, "/src/component.ts")).toThrow();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("returns a null map when ts.transpileModule omits sourceMapText", () => {
|
|
230
|
+
const transpileModule = ts.transpileModule as unknown as ReturnType<typeof vi.fn>;
|
|
231
|
+
transpileModule.mockReturnValueOnce({
|
|
232
|
+
outputText: "class Foo {}",
|
|
233
|
+
diagnostics: [],
|
|
234
|
+
sourceMapText: undefined,
|
|
235
|
+
});
|
|
236
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
237
|
+
const result = decorators.transform?.("class Foo { @Dec() x = 1; }", "component.ts");
|
|
238
|
+
expect(result).toEqual({ code: "class Foo {}", map: null });
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("does not throw when ts.transpileModule omits diagnostics", () => {
|
|
242
|
+
const transpileModule = ts.transpileModule as unknown as ReturnType<typeof vi.fn>;
|
|
243
|
+
transpileModule.mockReturnValueOnce({
|
|
244
|
+
outputText: "class Foo {}",
|
|
245
|
+
diagnostics: undefined,
|
|
246
|
+
sourceMapText: undefined,
|
|
247
|
+
});
|
|
248
|
+
const decorators = findPlugin(praxisjs(), "praxisjs:decorators");
|
|
249
|
+
expect(() =>
|
|
250
|
+
decorators.transform?.("class Foo { @Dec() x = 1; }", "component.ts"),
|
|
251
|
+
).not.toThrow();
|
|
252
|
+
});
|
|
35
253
|
});
|
|
36
254
|
|
|
37
255
|
describe("praxisjs:core config()", () => {
|
|
38
|
-
it("sets
|
|
39
|
-
const
|
|
40
|
-
const config =
|
|
41
|
-
expect(config).toEqual({
|
|
256
|
+
it("sets oxc target to es2022", () => {
|
|
257
|
+
const core = findPlugin(praxisjs(), "praxisjs:core");
|
|
258
|
+
const config = core.config?.();
|
|
259
|
+
expect(config).toEqual({ oxc: { target: "es2022" } });
|
|
42
260
|
});
|
|
43
261
|
});
|
|
44
262
|
|
|
45
263
|
describe("praxisjs:core transform()", () => {
|
|
46
|
-
type TransformFn = (code: string, id: string) => null | undefined;
|
|
47
|
-
|
|
48
264
|
it("returns null for .tsx files when autoImport is enabled", () => {
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const result = transform("const x = 1;", "component.tsx");
|
|
265
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
266
|
+
const result = core.transform?.("const x = 1;", "component.tsx");
|
|
52
267
|
expect(result).toBeNull();
|
|
53
268
|
});
|
|
54
269
|
|
|
55
270
|
it("returns null for .jsx files when autoImport is enabled", () => {
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const result = transform("const x = 1;", "component.jsx");
|
|
271
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
272
|
+
const result = core.transform?.("const x = 1;", "component.jsx");
|
|
59
273
|
expect(result).toBeNull();
|
|
60
274
|
});
|
|
61
275
|
|
|
62
276
|
it("returns undefined (no-op) for non-.tsx/.jsx files", () => {
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
const result = transform("const x = 1;", "module.ts");
|
|
277
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
278
|
+
const result = core.transform?.("const x = 1;", "module.ts");
|
|
66
279
|
expect(result).toBeUndefined();
|
|
67
280
|
});
|
|
68
281
|
|
|
69
282
|
it("returns undefined when autoImport is false", () => {
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const result = transform("const x = 1;", "component.tsx");
|
|
283
|
+
const core = findPlugin(praxisjs({ autoImport: false }), "praxisjs:core");
|
|
284
|
+
const result = core.transform?.("const x = 1;", "component.tsx");
|
|
73
285
|
expect(result).toBeUndefined();
|
|
74
286
|
});
|
|
75
287
|
|
|
76
288
|
it("returns undefined when code already imports @praxisjs/jsx/jsx-runtime", () => {
|
|
77
|
-
const
|
|
78
|
-
const transform = (core as { transform: TransformFn }).transform;
|
|
289
|
+
const core = findPlugin(praxisjs({ autoImport: true }), "praxisjs:core");
|
|
79
290
|
const code = 'import "@praxisjs/jsx/jsx-runtime"; const x = 1;';
|
|
80
|
-
const result = transform(code, "component.tsx");
|
|
291
|
+
const result = core.transform?.(code, "component.tsx");
|
|
81
292
|
expect(result).toBeUndefined();
|
|
82
293
|
});
|
|
83
294
|
});
|
|
84
295
|
|
|
85
296
|
describe("praxisjs:hmr handleHotUpdate()", () => {
|
|
86
|
-
type HandleHotUpdate = (ctx: { file: string; server: unknown }) => void;
|
|
87
|
-
|
|
88
297
|
function makeMockServer() {
|
|
89
298
|
return {
|
|
90
299
|
ws: {
|
|
@@ -94,12 +303,9 @@ describe("praxisjs:hmr handleHotUpdate()", () => {
|
|
|
94
303
|
}
|
|
95
304
|
|
|
96
305
|
it("sends custom event for .ts files", () => {
|
|
97
|
-
const
|
|
306
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
98
307
|
const server = makeMockServer();
|
|
99
|
-
(
|
|
100
|
-
file: "src/app.ts",
|
|
101
|
-
server,
|
|
102
|
-
});
|
|
308
|
+
hmr.handleHotUpdate?.({ file: "src/app.ts", server });
|
|
103
309
|
expect(server.ws.send).toHaveBeenCalledWith({
|
|
104
310
|
type: "custom",
|
|
105
311
|
event: "praxisjs:component-update",
|
|
@@ -108,12 +314,9 @@ describe("praxisjs:hmr handleHotUpdate()", () => {
|
|
|
108
314
|
});
|
|
109
315
|
|
|
110
316
|
it("sends custom event for .tsx files", () => {
|
|
111
|
-
const
|
|
317
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
112
318
|
const server = makeMockServer();
|
|
113
|
-
(
|
|
114
|
-
file: "src/component.tsx",
|
|
115
|
-
server,
|
|
116
|
-
});
|
|
319
|
+
hmr.handleHotUpdate?.({ file: "src/component.tsx", server });
|
|
117
320
|
expect(server.ws.send).toHaveBeenCalledWith({
|
|
118
321
|
type: "custom",
|
|
119
322
|
event: "praxisjs:component-update",
|
|
@@ -122,22 +325,16 @@ describe("praxisjs:hmr handleHotUpdate()", () => {
|
|
|
122
325
|
});
|
|
123
326
|
|
|
124
327
|
it("does not send event for non-.ts/.tsx files", () => {
|
|
125
|
-
const
|
|
328
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
126
329
|
const server = makeMockServer();
|
|
127
|
-
(
|
|
128
|
-
file: "src/style.css",
|
|
129
|
-
server,
|
|
130
|
-
});
|
|
330
|
+
hmr.handleHotUpdate?.({ file: "src/style.css", server });
|
|
131
331
|
expect(server.ws.send).not.toHaveBeenCalled();
|
|
132
332
|
});
|
|
133
333
|
|
|
134
334
|
it("does not send event for .js files", () => {
|
|
135
|
-
const
|
|
335
|
+
const hmr = findPlugin(praxisjs({ hmr: true }), "praxisjs:hmr");
|
|
136
336
|
const server = makeMockServer();
|
|
137
|
-
(
|
|
138
|
-
file: "src/utils.js",
|
|
139
|
-
server,
|
|
140
|
-
});
|
|
337
|
+
hmr.handleHotUpdate?.({ file: "src/utils.js", server });
|
|
141
338
|
expect(server.ws.send).not.toHaveBeenCalled();
|
|
142
339
|
});
|
|
143
340
|
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
import type { Plugin } from "vite";
|
|
4
|
+
|
|
5
|
+
const JS_LIKE_FILE = /\.[cm]?[jt]sx?(?:$|\?)/;
|
|
6
|
+
|
|
7
|
+
function cleanFileName(id: string): string {
|
|
8
|
+
return id.split("?")[0];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function scriptKindFor(fileName: string): ts.ScriptKind {
|
|
12
|
+
if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
|
|
13
|
+
if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
|
|
14
|
+
if (fileName.endsWith(".ts") || fileName.endsWith(".mts") || fileName.endsWith(".cts")) {
|
|
15
|
+
return ts.ScriptKind.TS;
|
|
16
|
+
}
|
|
17
|
+
return ts.ScriptKind.JS;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The `code.includes("@")` pre-filter below also matches "@" in comments
|
|
21
|
+
// (JSDoc, eslint-disable directives), so this walks a real AST to confirm
|
|
22
|
+
// actual decorator syntax is present before reprocessing the file — some
|
|
23
|
+
// framework code (`@praxisjs/concurrent`'s `acceptsSignal`) relies on
|
|
24
|
+
// `fn.toString()` returning untouched source.
|
|
25
|
+
function hasRealDecorator(code: string, fileName: string): boolean {
|
|
26
|
+
const source = ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, false, scriptKindFor(fileName));
|
|
27
|
+
let found = false;
|
|
28
|
+
const visit = (node: ts.Node): void => {
|
|
29
|
+
if (found) return;
|
|
30
|
+
if (ts.canHaveDecorators(node) && (ts.getDecorators(node)?.length ?? 0) > 0) {
|
|
31
|
+
found = true;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
ts.forEachChild(node, visit);
|
|
35
|
+
};
|
|
36
|
+
visit(source);
|
|
37
|
+
return found;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface RawSourceMap {
|
|
41
|
+
version: number;
|
|
42
|
+
file?: string;
|
|
43
|
+
sourceRoot?: string;
|
|
44
|
+
sources: string[];
|
|
45
|
+
sourcesContent?: Array<string | null>;
|
|
46
|
+
names: string[];
|
|
47
|
+
mappings: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function formatDiagnostics(diagnostics: readonly ts.Diagnostic[]): string {
|
|
51
|
+
return ts.formatDiagnostics(diagnostics, {
|
|
52
|
+
getCanonicalFileName: (fileName) => fileName,
|
|
53
|
+
getCurrentDirectory: () => "",
|
|
54
|
+
getNewLine: () => "\n",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// oxc doesn't lower TC39 (non-legacy) decorators yet — `@Decorator()`
|
|
59
|
+
// syntax passes through unchanged and no JS runtime executes it directly:
|
|
60
|
+
// https://github.com/oxc-project/oxc/issues/9170
|
|
61
|
+
//
|
|
62
|
+
// TypeScript's compiler lowers them instead (the same lowering `tsc` uses
|
|
63
|
+
// to build every package here). At ES2022 a decorated field stays a real
|
|
64
|
+
// class field rather than being rewritten into a constructor assignment,
|
|
65
|
+
// so its initializer runs after `super()` automatically — no separate
|
|
66
|
+
// ordering fix-up is needed. JSX is left untouched (`jsx: "preserve"`) for
|
|
67
|
+
// oxc's own JSX pipeline to handle.
|
|
68
|
+
export function decoratorLoweringPlugin(): Plugin {
|
|
69
|
+
return {
|
|
70
|
+
name: "praxisjs:decorators",
|
|
71
|
+
transform(code, id) {
|
|
72
|
+
if (!JS_LIKE_FILE.test(id) || !code.includes("@")) return null;
|
|
73
|
+
const fileName = cleanFileName(id);
|
|
74
|
+
if (!hasRealDecorator(code, fileName)) return null;
|
|
75
|
+
|
|
76
|
+
const { outputText, sourceMapText, diagnostics } = ts.transpileModule(code, {
|
|
77
|
+
fileName,
|
|
78
|
+
reportDiagnostics: true,
|
|
79
|
+
compilerOptions: {
|
|
80
|
+
target: ts.ScriptTarget.ES2022,
|
|
81
|
+
module: ts.ModuleKind.ESNext,
|
|
82
|
+
useDefineForClassFields: true,
|
|
83
|
+
jsx: ts.JsxEmit.Preserve,
|
|
84
|
+
sourceMap: true,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const errors = diagnostics?.filter((d) => d.category === ts.DiagnosticCategory.Error) ?? [];
|
|
89
|
+
if (errors.length > 0) {
|
|
90
|
+
throw new Error(`[praxisjs:decorators] ${fileName}:\n${formatDiagnostics(errors)}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
code: outputText,
|
|
95
|
+
map: sourceMapText ? (JSON.parse(sourceMapText) as RawSourceMap) : null,
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import { praxisjsCSS } from "./css.js";
|
|
2
|
+
import { decoratorLoweringPlugin } from "./decorators.js";
|
|
2
3
|
|
|
3
|
-
import type {
|
|
4
|
+
import type { PluginOption, ViteDevServer } from "vite";
|
|
4
5
|
|
|
5
6
|
export { praxisjsCSS };
|
|
7
|
+
export { decoratorLoweringPlugin };
|
|
6
8
|
|
|
7
9
|
export interface PraxisJSVitePluginOptions {
|
|
8
10
|
hmr?: boolean;
|
|
9
11
|
autoImport?: boolean;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export function praxisjs(options: PraxisJSVitePluginOptions = {}):
|
|
14
|
+
export function praxisjs(options: PraxisJSVitePluginOptions = {}): PluginOption[] {
|
|
13
15
|
const { hmr = true, autoImport = true } = options;
|
|
14
16
|
|
|
15
17
|
return [
|
|
18
|
+
decoratorLoweringPlugin(),
|
|
16
19
|
{
|
|
17
20
|
name: "praxisjs:core",
|
|
18
21
|
enforce: "pre",
|
|
19
22
|
config() {
|
|
20
23
|
return {
|
|
21
|
-
|
|
24
|
+
oxc: {
|
|
22
25
|
target: "es2022",
|
|
23
26
|
},
|
|
24
27
|
};
|