@macroforge/vite-plugin 0.1.78 → 0.1.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/index.js +178 -50
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@macroforge/shared": "
|
|
4
|
-
"macroforge": "
|
|
3
|
+
"@macroforge/shared": "file:../shared",
|
|
4
|
+
"macroforge": "file:../../crates/macroforge_ts"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@types/node": "^22.0.0"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|
|
25
|
-
"url": "git+https://github.com/macroforge-ts/
|
|
25
|
+
"url": "git+https://github.com/macroforge-ts/macroforge-ts.git"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "echo 'No build needed'",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
},
|
|
31
31
|
"type": "module",
|
|
32
32
|
"types": "src/index.d.ts",
|
|
33
|
-
"version": "0.1.
|
|
33
|
+
"version": "0.1.79"
|
|
34
34
|
}
|
package/src/index.js
CHANGED
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
import { createRequire } from "node:module";
|
|
43
43
|
import { createHash } from "node:crypto";
|
|
44
44
|
import * as fs from "node:fs";
|
|
45
|
+
import * as os from "node:os";
|
|
45
46
|
import * as path from "node:path";
|
|
46
47
|
import {
|
|
47
48
|
collectExternalDecoratorModules,
|
|
@@ -347,6 +348,48 @@ export async function macroforge() {
|
|
|
347
348
|
try {
|
|
348
349
|
const projectRequire = createRequire(process.cwd() + "/");
|
|
349
350
|
rustTransformer = projectRequire("macroforge");
|
|
351
|
+
|
|
352
|
+
// Register external macro callbacks for WASM builds.
|
|
353
|
+
// The WASM build cannot spawn Node subprocesses to resolve external macros,
|
|
354
|
+
// so we provide JS-side resolve/run callbacks. No-op for NAPI builds.
|
|
355
|
+
if (rustTransformer.setupExternalMacros) {
|
|
356
|
+
const req = createRequire(process.cwd() + "/package.json");
|
|
357
|
+
|
|
358
|
+
const resolveDecoratorNames = function (packagePath) {
|
|
359
|
+
const pkg = req(packagePath);
|
|
360
|
+
const names = [];
|
|
361
|
+
if (pkg.__macroforgeGetManifest) {
|
|
362
|
+
names.push(
|
|
363
|
+
...(pkg.__macroforgeGetManifest().decorators || []).map(
|
|
364
|
+
(d) => d.export,
|
|
365
|
+
),
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
for (const key of Object.keys(pkg)) {
|
|
369
|
+
if (
|
|
370
|
+
key.startsWith("__macroforgeGetManifest_") &&
|
|
371
|
+
typeof pkg[key] === "function"
|
|
372
|
+
) {
|
|
373
|
+
names.push(
|
|
374
|
+
...(pkg[key]().decorators || []).map((d) => d.export),
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (names.length > 0) return [...new Set(names)];
|
|
379
|
+
return [];
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
const runMacro = function (ctxJson) {
|
|
383
|
+
const ctx = JSON.parse(ctxJson);
|
|
384
|
+
const fnName = `__macroforgeRun${ctx.macro_name}`;
|
|
385
|
+
const pkg = req(ctx.module_path);
|
|
386
|
+
const fn_ = pkg?.[fnName] || pkg?.default?.[fnName];
|
|
387
|
+
if (typeof fn_ === "function") return fn_(ctxJson);
|
|
388
|
+
throw new Error(`Macro ${fnName} not found in ${ctx.module_path}`);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
rustTransformer.setupExternalMacros(resolveDecoratorNames, runMacro);
|
|
392
|
+
}
|
|
350
393
|
} catch (error) {
|
|
351
394
|
console.warn(
|
|
352
395
|
"[@macroforge/vite-plugin] Rust binary not found. Please run `npm run build:rust` first.",
|
|
@@ -455,17 +498,84 @@ export async function macroforge() {
|
|
|
455
498
|
* @returns {string}
|
|
456
499
|
*/
|
|
457
500
|
function getMacroforgeVersion() {
|
|
501
|
+
const req = createRequire(process.cwd() + "/");
|
|
458
502
|
try {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
503
|
+
return JSON.parse(
|
|
504
|
+
fs.readFileSync(req.resolve("macroforge/package.json"), "utf-8"),
|
|
505
|
+
).version;
|
|
506
|
+
} catch { /* exports map may block ./package.json */ }
|
|
507
|
+
try {
|
|
508
|
+
return JSON.parse(
|
|
509
|
+
fs.readFileSync(
|
|
510
|
+
path.join(process.cwd(), "node_modules", "macroforge", "package.json"),
|
|
511
|
+
"utf-8",
|
|
512
|
+
),
|
|
513
|
+
).version;
|
|
514
|
+
} catch { /* not in local node_modules */ }
|
|
515
|
+
return "unknown";
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Computes a hash over external macro package binaries (`.node`, `.wasm`)
|
|
520
|
+
* so the cache invalidates when a local macro package is rebuilt.
|
|
521
|
+
* @returns {string}
|
|
522
|
+
*/
|
|
523
|
+
function getExternalMacroHash() {
|
|
524
|
+
const nodeModules = path.join(projectRoot || process.cwd(), "node_modules");
|
|
525
|
+
if (!fs.existsSync(nodeModules)) return "none";
|
|
526
|
+
|
|
527
|
+
// Collect path:size:mtime_seconds parts, sort for deterministic ordering
|
|
528
|
+
// (readdir order varies across Node/Deno/Rust), then hash.
|
|
529
|
+
const parts = [];
|
|
530
|
+
|
|
531
|
+
const checkPackage = (pkgDir) => {
|
|
532
|
+
const indexJs = path.join(pkgDir, "index.js");
|
|
533
|
+
try {
|
|
534
|
+
const content = fs.readFileSync(indexJs, "utf-8");
|
|
535
|
+
if (!content.includes("__macroforgeRun")) return;
|
|
536
|
+
} catch {
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
try {
|
|
540
|
+
for (const entry of fs.readdirSync(pkgDir)) {
|
|
541
|
+
const ext = path.extname(entry);
|
|
542
|
+
if (ext === ".node" || ext === ".wasm" || entry === "index.js") {
|
|
543
|
+
const full = path.join(pkgDir, entry);
|
|
544
|
+
try {
|
|
545
|
+
const stat = fs.statSync(full);
|
|
546
|
+
parts.push(
|
|
547
|
+
`${full}:${stat.size}:${Math.floor(stat.mtimeMs / 1000)}`,
|
|
548
|
+
);
|
|
549
|
+
} catch { /* expected */ }
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
} catch { /* expected */ }
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
try {
|
|
556
|
+
for (const entry of fs.readdirSync(nodeModules)) {
|
|
557
|
+
const full = path.join(nodeModules, entry);
|
|
558
|
+
if (!fs.statSync(full).isDirectory()) continue;
|
|
559
|
+
if (entry.startsWith("@")) {
|
|
560
|
+
try {
|
|
561
|
+
for (const sub of fs.readdirSync(full)) {
|
|
562
|
+
const subFull = path.join(full, sub);
|
|
563
|
+
if (fs.statSync(subFull).isDirectory()) checkPackage(subFull);
|
|
564
|
+
}
|
|
565
|
+
} catch { /* expected */ }
|
|
566
|
+
} else if (!entry.startsWith(".")) {
|
|
567
|
+
checkPackage(full);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
} catch { /* expected */ }
|
|
571
|
+
|
|
572
|
+
if (parts.length === 0) return "none";
|
|
573
|
+
parts.sort();
|
|
574
|
+
const hasher = createHash("sha256");
|
|
575
|
+
for (const part of parts) {
|
|
576
|
+
hasher.update(part);
|
|
468
577
|
}
|
|
578
|
+
return hasher.digest("hex");
|
|
469
579
|
}
|
|
470
580
|
|
|
471
581
|
/**
|
|
@@ -518,6 +628,17 @@ export async function macroforge() {
|
|
|
518
628
|
return null;
|
|
519
629
|
}
|
|
520
630
|
|
|
631
|
+
const currentExternalHash = getExternalMacroHash();
|
|
632
|
+
if (
|
|
633
|
+
manifest.externalMacroHash &&
|
|
634
|
+
manifest.externalMacroHash !== currentExternalHash
|
|
635
|
+
) {
|
|
636
|
+
console.log(
|
|
637
|
+
"[@macroforge/vite-plugin] Cache invalidated: external macro binary changed",
|
|
638
|
+
);
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
|
|
521
642
|
return manifest;
|
|
522
643
|
} catch {
|
|
523
644
|
return null;
|
|
@@ -574,6 +695,7 @@ export async function macroforge() {
|
|
|
574
695
|
cacheManifest = {
|
|
575
696
|
version: macroforgeVersion,
|
|
576
697
|
configHash: getConfigHash(),
|
|
698
|
+
externalMacroHash: getExternalMacroHash(),
|
|
577
699
|
entries: {},
|
|
578
700
|
};
|
|
579
701
|
}
|
|
@@ -727,42 +849,61 @@ export async function macroforge() {
|
|
|
727
849
|
},
|
|
728
850
|
|
|
729
851
|
/**
|
|
730
|
-
*
|
|
852
|
+
* Load the type registry from the CLI cache for compile-time type awareness.
|
|
731
853
|
* The registry is passed to every expandSync call so macros can introspect
|
|
732
|
-
* any type in the project
|
|
854
|
+
* any type in the project.
|
|
733
855
|
*/
|
|
734
856
|
buildStart() {
|
|
735
|
-
|
|
736
|
-
|
|
857
|
+
const localRegistry = path.join(
|
|
858
|
+
projectRoot,
|
|
859
|
+
".macroforge",
|
|
860
|
+
"type-registry.json",
|
|
861
|
+
);
|
|
862
|
+
if (fs.existsSync(localRegistry)) {
|
|
863
|
+
typeRegistryJson = fs.readFileSync(localRegistry, "utf-8");
|
|
864
|
+
try {
|
|
865
|
+
const parsed = JSON.parse(typeRegistryJson);
|
|
866
|
+
const count = Object.keys(parsed.types ?? parsed).length;
|
|
867
|
+
console.log(
|
|
868
|
+
`[@macroforge/vite-plugin] Type registry loaded: ${count} types`,
|
|
869
|
+
);
|
|
870
|
+
} catch {
|
|
871
|
+
// JSON is passed as-is to expandSync, no need to parse here
|
|
872
|
+
}
|
|
873
|
+
} else {
|
|
874
|
+
console.warn(
|
|
875
|
+
`[@macroforge/vite-plugin] No type registry found at .macroforge/type-registry.json. Run \`macroforge watch\` to generate it.`,
|
|
876
|
+
);
|
|
737
877
|
}
|
|
878
|
+
},
|
|
738
879
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
880
|
+
/**
|
|
881
|
+
* Resolve `.svelte` imports to `.svelte.ts` when the `.svelte` file
|
|
882
|
+
* does not exist. Macroforge type files use the `.svelte.ts` extension
|
|
883
|
+
* (Svelte 5 runes modules) but are imported with just `.svelte`.
|
|
884
|
+
*
|
|
885
|
+
* @param {string} source
|
|
886
|
+
* @param {string | undefined} importer
|
|
887
|
+
* @param {object} options
|
|
888
|
+
*/
|
|
889
|
+
async resolveId(source, importer, options) {
|
|
890
|
+
if (!source.endsWith(".svelte") || !importer) return null;
|
|
745
891
|
|
|
746
|
-
|
|
892
|
+
// Let other plugins (SvelteKit, etc.) try to resolve it first
|
|
893
|
+
const resolved = await this.resolve(source, importer, {
|
|
894
|
+
...options,
|
|
895
|
+
skipSelf: true,
|
|
896
|
+
});
|
|
747
897
|
|
|
748
|
-
|
|
749
|
-
`[@macroforge/vite-plugin] Type scan: ${scanResult.typesFound} types from ${scanResult.filesScanned} files (${scanTime}ms)`,
|
|
750
|
-
);
|
|
898
|
+
if (resolved && !resolved.external) return resolved;
|
|
751
899
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
} catch (error) {
|
|
760
|
-
console.warn(
|
|
761
|
-
`[@macroforge/vite-plugin] Type scan failed, macros will run without type awareness:`,
|
|
762
|
-
error.message || error,
|
|
763
|
-
);
|
|
764
|
-
typeRegistryJson = undefined;
|
|
765
|
-
}
|
|
900
|
+
// Fall back: try appending .ts
|
|
901
|
+
const resolvedTs = await this.resolve(source + ".ts", importer, {
|
|
902
|
+
...options,
|
|
903
|
+
skipSelf: true,
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
return resolvedTs || null;
|
|
766
907
|
},
|
|
767
908
|
|
|
768
909
|
/**
|
|
@@ -802,7 +943,6 @@ export async function macroforge() {
|
|
|
802
943
|
if (cached) {
|
|
803
944
|
let cachedCode = cached.code;
|
|
804
945
|
|
|
805
|
-
// Apply same post-processing as the normal path
|
|
806
946
|
cachedCode = cachedCode.replace(
|
|
807
947
|
/\/\*\*\s*import\s+macro[\s\S]*?\*\/\s*/gi,
|
|
808
948
|
"",
|
|
@@ -814,18 +954,6 @@ export async function macroforge() {
|
|
|
814
954
|
);
|
|
815
955
|
}
|
|
816
956
|
|
|
817
|
-
// Generate type definitions from cached expanded code
|
|
818
|
-
if (generateTypes) {
|
|
819
|
-
const emitted = emitDeclarationsFromCode(
|
|
820
|
-
cachedCode,
|
|
821
|
-
id,
|
|
822
|
-
projectRoot,
|
|
823
|
-
);
|
|
824
|
-
if (emitted) {
|
|
825
|
-
writeTypeDefinitions(id, emitted);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
957
|
return {
|
|
830
958
|
code: cachedCode,
|
|
831
959
|
map: null,
|