@macroforge/vite-plugin 0.1.45 → 0.1.48
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 +42 -30
- package/package.json +4 -3
- package/src/index.js +71 -42
package/README.md
CHANGED
|
@@ -8,23 +8,25 @@
|
|
|
8
8
|
|
|
9
9
|
Vite plugin for Macroforge compile-time TypeScript macro expansion.
|
|
10
10
|
|
|
11
|
-
This plugin integrates Macroforge's Rust-based macro expander into the Vite
|
|
12
|
-
enabling compile-time code generation through `@derive`
|
|
13
|
-
files during the build, expands macros,
|
|
11
|
+
This plugin integrates Macroforge's Rust-based macro expander into the Vite
|
|
12
|
+
build pipeline, enabling compile-time code generation through `@derive`
|
|
13
|
+
decorators. It processes TypeScript files during the build, expands macros,
|
|
14
|
+
generates type definitions, and emits metadata.
|
|
14
15
|
|
|
15
16
|
@example
|
|
17
|
+
|
|
16
18
|
```typescript
|
|
17
|
-
import { defineConfig } from
|
|
18
|
-
import macroforgePlugin from
|
|
19
|
+
import { defineConfig } from "vite";
|
|
20
|
+
import macroforgePlugin from "@macroforge/vite-plugin";
|
|
19
21
|
|
|
20
22
|
export default defineConfig({
|
|
21
|
-
plugins: [
|
|
22
|
-
macroforgePlugin({
|
|
23
|
-
generateTypes: true,
|
|
24
|
-
typesOutputDir:
|
|
25
|
-
emitMetadata: true,
|
|
26
|
-
}),
|
|
27
|
-
],
|
|
23
|
+
plugins: [
|
|
24
|
+
macroforgePlugin({
|
|
25
|
+
generateTypes: true,
|
|
26
|
+
typesOutputDir: ".macroforge/types",
|
|
27
|
+
emitMetadata: true,
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
28
30
|
});
|
|
29
31
|
```
|
|
30
32
|
|
|
@@ -38,37 +40,47 @@ npm install @macroforge/vite-plugin
|
|
|
38
40
|
|
|
39
41
|
### Functions
|
|
40
42
|
|
|
41
|
-
- **`loadMacroConfig`** - Whether to preserve `@derive` decorators in the output
|
|
42
|
-
|
|
43
|
-
- **`
|
|
44
|
-
|
|
45
|
-
- **`
|
|
46
|
-
|
|
43
|
+
- **`loadMacroConfig`** - Whether to preserve `@derive` decorators in the output
|
|
44
|
+
code after macro expansion.
|
|
45
|
+
- **`napiMacrosPlugin`** - Creates a Vite plugin for Macroforge compile-time
|
|
46
|
+
macro expansion.
|
|
47
|
+
- **`ensureDir`** - Ensures a directory exists, creating it recursively if
|
|
48
|
+
necessary.
|
|
49
|
+
- **`writeTypeDefinitions`** - Writes generated TypeScript declaration files to
|
|
50
|
+
the configured output directory.
|
|
51
|
+
- **`writeMetadata`** - Writes macro intermediate representation (IR) metadata
|
|
52
|
+
to JSON files.
|
|
53
|
+
- **`formatTransformError`** - Formats transformation errors into user-friendly
|
|
54
|
+
messages.
|
|
47
55
|
|
|
48
56
|
### Types
|
|
49
57
|
|
|
50
|
-
- **`NapiMacrosPluginOptions`** - Configuration options for the Macroforge Vite
|
|
51
|
-
|
|
58
|
+
- **`NapiMacrosPluginOptions`** - Configuration options for the Macroforge Vite
|
|
59
|
+
plugin.
|
|
60
|
+
- **`MacroConfig`** - Glob patterns, regular expressions, or arrays of either to
|
|
61
|
+
specify which files
|
|
52
62
|
|
|
53
63
|
## Examples
|
|
54
64
|
|
|
55
65
|
```typescript
|
|
56
|
-
import { defineConfig } from
|
|
57
|
-
import macroforgePlugin from
|
|
66
|
+
import { defineConfig } from "vite";
|
|
67
|
+
import macroforgePlugin from "@macroforge/vite-plugin";
|
|
58
68
|
export default defineConfig({
|
|
59
|
-
plugins: [
|
|
60
|
-
macroforgePlugin({
|
|
61
|
-
generateTypes: true,
|
|
62
|
-
typesOutputDir:
|
|
63
|
-
emitMetadata: true,
|
|
64
|
-
}),
|
|
65
|
-
],
|
|
69
|
+
plugins: [
|
|
70
|
+
macroforgePlugin({
|
|
71
|
+
generateTypes: true,
|
|
72
|
+
typesOutputDir: ".macroforge/types",
|
|
73
|
+
emitMetadata: true,
|
|
74
|
+
}),
|
|
75
|
+
],
|
|
66
76
|
});
|
|
67
77
|
```
|
|
68
78
|
|
|
69
79
|
## Documentation
|
|
70
80
|
|
|
71
|
-
See the
|
|
81
|
+
See the
|
|
82
|
+
[full documentation](https://macroforge.dev/docs/api/reference/typescript/vite-plugin)
|
|
83
|
+
on the Macroforge website.
|
|
72
84
|
|
|
73
85
|
## License
|
|
74
86
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@macroforge/shared": "^0.1.
|
|
4
|
-
"macroforge": "^0.1.
|
|
3
|
+
"@macroforge/shared": "^0.1.66",
|
|
4
|
+
"macroforge": "^0.1.66"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@types/node": "^22.0.0"
|
|
@@ -25,9 +25,10 @@
|
|
|
25
25
|
"url": "git+https://github.com/macroforge-ts/vite-plugin.git"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
+
"build": "echo 'No build needed'",
|
|
28
29
|
"test": "node --test tests/**/*.test.js"
|
|
29
30
|
},
|
|
30
31
|
"type": "module",
|
|
31
32
|
"types": "src/index.d.ts",
|
|
32
|
-
"version": "0.1.
|
|
33
|
+
"version": "0.1.48"
|
|
33
34
|
}
|
package/src/index.js
CHANGED
|
@@ -38,11 +38,13 @@
|
|
|
38
38
|
* @packageDocumentation
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
import { createRequire } from "module";
|
|
42
|
-
import * as fs from "fs";
|
|
43
|
-
import * as path from "path";
|
|
44
|
-
import {
|
|
45
|
-
|
|
41
|
+
import { createRequire } from "node:module";
|
|
42
|
+
import * as fs from "node:fs";
|
|
43
|
+
import * as path from "node:path";
|
|
44
|
+
import {
|
|
45
|
+
collectExternalDecoratorModules,
|
|
46
|
+
loadMacroConfig,
|
|
47
|
+
} from "@macroforge/shared";
|
|
46
48
|
|
|
47
49
|
const moduleRequire = createRequire(import.meta.url);
|
|
48
50
|
|
|
@@ -53,7 +55,7 @@ try {
|
|
|
53
55
|
} catch (error) {
|
|
54
56
|
tsModule = undefined;
|
|
55
57
|
console.warn(
|
|
56
|
-
"[@macroforge/vite-plugin] TypeScript not found. Generated .d.ts files will be skipped."
|
|
58
|
+
"[@macroforge/vite-plugin] TypeScript not found. Generated .d.ts files will be skipped.",
|
|
57
59
|
);
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -74,8 +76,9 @@ async function ensureRequire() {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
if (!cachedRequire) {
|
|
77
|
-
const { createRequire } = await import("module");
|
|
78
|
-
cachedRequire =
|
|
79
|
+
const { createRequire } = await import("node:module");
|
|
80
|
+
cachedRequire =
|
|
81
|
+
/** @type {NodeJS.Require} */ (createRequire(process.cwd() + "/"));
|
|
79
82
|
// @ts-ignore - Expose on globalThis so native runtime loaders can use it
|
|
80
83
|
globalThis.require = cachedRequire;
|
|
81
84
|
}
|
|
@@ -104,7 +107,7 @@ function getCompilerOptions(projectRoot) {
|
|
|
104
107
|
configPath = tsModule.findConfigFile(
|
|
105
108
|
projectRoot,
|
|
106
109
|
tsModule.sys.fileExists,
|
|
107
|
-
"tsconfig.json"
|
|
110
|
+
"tsconfig.json",
|
|
108
111
|
);
|
|
109
112
|
} catch {
|
|
110
113
|
configPath = undefined;
|
|
@@ -113,7 +116,10 @@ function getCompilerOptions(projectRoot) {
|
|
|
113
116
|
/** @type {import('typescript').CompilerOptions} */
|
|
114
117
|
let options;
|
|
115
118
|
if (configPath) {
|
|
116
|
-
const configFile = tsModule.readConfigFile(
|
|
119
|
+
const configFile = tsModule.readConfigFile(
|
|
120
|
+
configPath,
|
|
121
|
+
tsModule.sys.readFile,
|
|
122
|
+
);
|
|
117
123
|
if (configFile.error) {
|
|
118
124
|
const formatted = tsModule.formatDiagnosticsWithColorAndContext(
|
|
119
125
|
[configFile.error],
|
|
@@ -121,17 +127,17 @@ function getCompilerOptions(projectRoot) {
|
|
|
121
127
|
getCurrentDirectory: () => projectRoot,
|
|
122
128
|
getCanonicalFileName: (fileName) => fileName,
|
|
123
129
|
getNewLine: () => tsModule.sys.newLine,
|
|
124
|
-
}
|
|
130
|
+
},
|
|
125
131
|
);
|
|
126
132
|
console.warn(
|
|
127
|
-
`[@macroforge/vite-plugin] Failed to read tsconfig at ${configPath}\n${formatted}
|
|
133
|
+
`[@macroforge/vite-plugin] Failed to read tsconfig at ${configPath}\n${formatted}`,
|
|
128
134
|
);
|
|
129
135
|
options = {};
|
|
130
136
|
} else {
|
|
131
137
|
const parsed = tsModule.parseJsonConfigFileContent(
|
|
132
138
|
configFile.config,
|
|
133
139
|
tsModule.sys,
|
|
134
|
-
path.dirname(configPath)
|
|
140
|
+
path.dirname(configPath),
|
|
135
141
|
);
|
|
136
142
|
options = parsed.options;
|
|
137
143
|
}
|
|
@@ -193,12 +199,17 @@ function emitDeclarationsFromCode(code, fileName, projectRoot) {
|
|
|
193
199
|
requestedFileName,
|
|
194
200
|
sourceText,
|
|
195
201
|
languageVersion,
|
|
196
|
-
true
|
|
202
|
+
true,
|
|
197
203
|
);
|
|
198
204
|
}
|
|
199
205
|
const text = tsModule.sys.readFile(requestedFileName);
|
|
200
206
|
return text !== undefined
|
|
201
|
-
? tsModule.createSourceFile(
|
|
207
|
+
? tsModule.createSourceFile(
|
|
208
|
+
requestedFileName,
|
|
209
|
+
text,
|
|
210
|
+
languageVersion,
|
|
211
|
+
true,
|
|
212
|
+
)
|
|
202
213
|
: undefined;
|
|
203
214
|
};
|
|
204
215
|
|
|
@@ -220,7 +231,10 @@ function emitDeclarationsFromCode(code, fileName, projectRoot) {
|
|
|
220
231
|
// Capture emitted declaration content
|
|
221
232
|
/** @type {string | undefined} */
|
|
222
233
|
let output;
|
|
223
|
-
const writeFile = (
|
|
234
|
+
const writeFile = (
|
|
235
|
+
/** @type {string} */ outputName,
|
|
236
|
+
/** @type {string} */ text,
|
|
237
|
+
) => {
|
|
224
238
|
if (outputName.endsWith(".d.ts")) {
|
|
225
239
|
output = text;
|
|
226
240
|
}
|
|
@@ -229,7 +243,7 @@ function emitDeclarationsFromCode(code, fileName, projectRoot) {
|
|
|
229
243
|
const program = tsModule.createProgram(
|
|
230
244
|
[normalizedFileName],
|
|
231
245
|
compilerOptions,
|
|
232
|
-
compilerHost
|
|
246
|
+
compilerHost,
|
|
233
247
|
);
|
|
234
248
|
const emitResult = program.emit(undefined, writeFile, undefined, true);
|
|
235
249
|
|
|
@@ -241,13 +255,15 @@ function emitDeclarationsFromCode(code, fileName, projectRoot) {
|
|
|
241
255
|
getCurrentDirectory: () => projectRoot,
|
|
242
256
|
getCanonicalFileName: (fileName) => fileName,
|
|
243
257
|
getNewLine: () => tsModule.sys.newLine,
|
|
244
|
-
}
|
|
258
|
+
},
|
|
245
259
|
);
|
|
246
260
|
console.warn(
|
|
247
|
-
`[@macroforge/vite-plugin] Declaration emit failed for ${
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
`[@macroforge/vite-plugin] Declaration emit failed for ${
|
|
262
|
+
path.relative(
|
|
263
|
+
projectRoot,
|
|
264
|
+
fileName,
|
|
265
|
+
)
|
|
266
|
+
}\n${formatted}`,
|
|
251
267
|
);
|
|
252
268
|
return undefined;
|
|
253
269
|
}
|
|
@@ -299,18 +315,21 @@ export async function macroforge() {
|
|
|
299
315
|
rustTransformer = moduleRequire("macroforge");
|
|
300
316
|
} catch (error) {
|
|
301
317
|
console.warn(
|
|
302
|
-
"[@macroforge/vite-plugin] Rust binary not found. Please run `npm run build:rust` first."
|
|
318
|
+
"[@macroforge/vite-plugin] Rust binary not found. Please run `npm run build:rust` first.",
|
|
303
319
|
);
|
|
304
320
|
console.warn(error);
|
|
305
321
|
}
|
|
306
322
|
|
|
307
323
|
// Load config upfront (passing Rust transformer for foreign type parsing)
|
|
308
|
-
const macroConfig = loadMacroConfig(
|
|
324
|
+
const macroConfig = loadMacroConfig(
|
|
325
|
+
process.cwd(),
|
|
326
|
+
rustTransformer?.loadConfig,
|
|
327
|
+
);
|
|
309
328
|
|
|
310
329
|
if (macroConfig.hasForeignTypes) {
|
|
311
330
|
console.log(
|
|
312
331
|
"[@macroforge/vite-plugin] Loaded config with foreign types from:",
|
|
313
|
-
macroConfig.configPath
|
|
332
|
+
macroConfig.configPath,
|
|
314
333
|
);
|
|
315
334
|
}
|
|
316
335
|
|
|
@@ -347,7 +366,7 @@ export async function macroforge() {
|
|
|
347
366
|
}
|
|
348
367
|
} catch (error) {
|
|
349
368
|
throw new Error(
|
|
350
|
-
`[@macroforge/vite-plugin] Failed to load config from ${macroConfig.configPath}: ${error.message}
|
|
369
|
+
`[@macroforge/vite-plugin] Failed to load config from ${macroConfig.configPath}: ${error.message}`,
|
|
351
370
|
);
|
|
352
371
|
}
|
|
353
372
|
}
|
|
@@ -384,13 +403,15 @@ export async function macroforge() {
|
|
|
384
403
|
if (existing !== types) {
|
|
385
404
|
fs.writeFileSync(targetPath, types, "utf-8");
|
|
386
405
|
console.log(
|
|
387
|
-
`[@macroforge/vite-plugin] Wrote types for ${relativePath} -> ${
|
|
406
|
+
`[@macroforge/vite-plugin] Wrote types for ${relativePath} -> ${
|
|
407
|
+
path.relative(projectRoot, targetPath)
|
|
408
|
+
}`,
|
|
388
409
|
);
|
|
389
410
|
}
|
|
390
411
|
} catch (error) {
|
|
391
412
|
console.error(
|
|
392
413
|
`[@macroforge/vite-plugin] Failed to write type definitions for ${id}:`,
|
|
393
|
-
error
|
|
414
|
+
error,
|
|
394
415
|
);
|
|
395
416
|
}
|
|
396
417
|
}
|
|
@@ -414,13 +435,15 @@ export async function macroforge() {
|
|
|
414
435
|
if (existing !== metadata) {
|
|
415
436
|
fs.writeFileSync(targetPath, metadata, "utf-8");
|
|
416
437
|
console.log(
|
|
417
|
-
`[@macroforge/vite-plugin] Wrote metadata for ${relativePath} -> ${
|
|
438
|
+
`[@macroforge/vite-plugin] Wrote metadata for ${relativePath} -> ${
|
|
439
|
+
path.relative(projectRoot, targetPath)
|
|
440
|
+
}`,
|
|
418
441
|
);
|
|
419
442
|
}
|
|
420
443
|
} catch (error) {
|
|
421
444
|
console.error(
|
|
422
445
|
`[@macroforge/vite-plugin] Failed to write metadata for ${id}:`,
|
|
423
|
-
error
|
|
446
|
+
error,
|
|
424
447
|
);
|
|
425
448
|
}
|
|
426
449
|
}
|
|
@@ -434,13 +457,15 @@ export async function macroforge() {
|
|
|
434
457
|
function formatTransformError(error, id) {
|
|
435
458
|
const relative = projectRoot ? path.relative(projectRoot, id) || id : id;
|
|
436
459
|
if (error instanceof Error) {
|
|
437
|
-
const details =
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
460
|
+
const details = error.stack && error.stack.includes(error.message)
|
|
461
|
+
? error.stack
|
|
462
|
+
: `${error.message}\n${error.stack ?? ""}`;
|
|
463
|
+
return `[@macroforge/vite-plugin] Failed to transform ${relative}\n${details}`
|
|
464
|
+
.trim();
|
|
442
465
|
}
|
|
443
|
-
return `[@macroforge/vite-plugin] Failed to transform ${relative}: ${
|
|
466
|
+
return `[@macroforge/vite-plugin] Failed to transform ${relative}: ${
|
|
467
|
+
String(error)
|
|
468
|
+
}`;
|
|
444
469
|
}
|
|
445
470
|
|
|
446
471
|
/** @type {import('vite').Plugin} */
|
|
@@ -461,7 +486,8 @@ export async function macroforge() {
|
|
|
461
486
|
*/
|
|
462
487
|
async transform(code, id) {
|
|
463
488
|
// Ensure require() is available for native module loading
|
|
464
|
-
|
|
489
|
+
// Use the project's CWD-based require for resolving external macro packages
|
|
490
|
+
const projectRequire = await ensureRequire();
|
|
465
491
|
|
|
466
492
|
// Only transform TypeScript files
|
|
467
493
|
if (!id.endsWith(".ts") && !id.endsWith(".tsx")) {
|
|
@@ -485,9 +511,10 @@ export async function macroforge() {
|
|
|
485
511
|
|
|
486
512
|
try {
|
|
487
513
|
// Collect external decorator modules from macro imports
|
|
514
|
+
// Use projectRequire to resolve packages from the project's CWD, not the plugin's location
|
|
488
515
|
const externalDecoratorModules = collectExternalDecoratorModules(
|
|
489
516
|
code,
|
|
490
|
-
|
|
517
|
+
projectRequire,
|
|
491
518
|
);
|
|
492
519
|
|
|
493
520
|
// Perform macro expansion via the Rust binary
|
|
@@ -500,11 +527,13 @@ export async function macroforge() {
|
|
|
500
527
|
// Report diagnostics from macro expansion
|
|
501
528
|
for (const diag of result.diagnostics) {
|
|
502
529
|
if (diag.level === "error") {
|
|
503
|
-
const message = `Macro error at ${id}:${diag.start ?? "?"}-${
|
|
530
|
+
const message = `Macro error at ${id}:${diag.start ?? "?"}-${
|
|
531
|
+
diag.end ?? "?"
|
|
532
|
+
}: ${diag.message}`;
|
|
504
533
|
/** @type {any} */ (this).error(message);
|
|
505
534
|
} else {
|
|
506
535
|
console.warn(
|
|
507
|
-
`[@macroforge/vite-plugin] ${diag.level}: ${diag.message}
|
|
536
|
+
`[@macroforge/vite-plugin] ${diag.level}: ${diag.message}`,
|
|
508
537
|
);
|
|
509
538
|
}
|
|
510
539
|
}
|
|
@@ -513,7 +542,7 @@ export async function macroforge() {
|
|
|
513
542
|
// Remove macro-only imports so SSR output doesn't load native bindings
|
|
514
543
|
result.code = result.code.replace(
|
|
515
544
|
/\/\*\*\s*import\s+macro[\s\S]*?\*\/\s*/gi,
|
|
516
|
-
""
|
|
545
|
+
"",
|
|
517
546
|
);
|
|
518
547
|
|
|
519
548
|
// Generate type definitions if enabled
|
|
@@ -521,7 +550,7 @@ export async function macroforge() {
|
|
|
521
550
|
const emitted = emitDeclarationsFromCode(
|
|
522
551
|
result.code,
|
|
523
552
|
id,
|
|
524
|
-
projectRoot
|
|
553
|
+
projectRoot,
|
|
525
554
|
);
|
|
526
555
|
if (emitted) {
|
|
527
556
|
writeTypeDefinitions(id, emitted);
|