@macroforge/vite-plugin 0.1.47 → 0.1.72

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.
Files changed (3) hide show
  1. package/README.md +42 -30
  2. package/package.json +4 -3
  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 build pipeline,
12
- enabling compile-time code generation through `@derive` decorators. It processes TypeScript
13
- files during the build, expands macros, generates type definitions, and emits metadata.
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 'vite';
18
- import macroforgePlugin from '@macroforge/vite-plugin';
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: '.macroforge/types',
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 code after macro expansion.
42
- - **`napiMacrosPlugin`** - Creates a Vite plugin for Macroforge compile-time macro expansion.
43
- - **`ensureDir`** - Ensures a directory exists, creating it recursively if necessary.
44
- - **`writeTypeDefinitions`** - Writes generated TypeScript declaration files to the configured output directory.
45
- - **`writeMetadata`** - Writes macro intermediate representation (IR) metadata to JSON files.
46
- - **`formatTransformError`** - Formats transformation errors into user-friendly messages.
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 plugin.
51
- - **`MacroConfig`** - Glob patterns, regular expressions, or arrays of either to specify which files
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 'vite';
57
- import macroforgePlugin from '@macroforge/vite-plugin';
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: '.macroforge/types',
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 [full documentation](https://macroforge.dev/docs/api/reference/typescript/vite-plugin) on the Macroforge website.
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.65",
4
- "macroforge": "^0.1.65"
3
+ "@macroforge/shared": "^0.1.72",
4
+ "macroforge": "^0.1.72"
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.47"
33
+ "version": "0.1.72"
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 { collectExternalDecoratorModules, loadMacroConfig } from "@macroforge/shared";
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 = /** @type {NodeJS.Require} */ (createRequire(process.cwd() + "/"));
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(configPath, tsModule.sys.readFile);
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(requestedFileName, text, languageVersion, true)
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 = (/** @type {string} */ outputName, /** @type {string} */ text) => {
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 ${path.relative(
248
- projectRoot,
249
- fileName
250
- )}\n${formatted}`
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(process.cwd(), rustTransformer?.loadConfig);
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} -> ${path.relative(projectRoot, targetPath)}`
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} -> ${path.relative(projectRoot, targetPath)}`
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
- error.stack && error.stack.includes(error.message)
439
- ? error.stack
440
- : `${error.message}\n${error.stack ?? ""}`;
441
- return `[@macroforge/vite-plugin] Failed to transform ${relative}\n${details}`.trim();
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}: ${String(error)}`;
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
- await ensureRequire();
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
- moduleRequire
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 ?? "?"}-${diag.end ?? "?"}: ${diag.message}`;
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);