@macroforge/vite-plugin 0.1.77 → 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 +181 -52
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,9 +42,11 @@
|
|
|
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,
|
|
49
|
+
hasMacroAnnotations,
|
|
48
50
|
loadMacroConfig,
|
|
49
51
|
} from "@macroforge/shared";
|
|
50
52
|
|
|
@@ -346,6 +348,48 @@ export async function macroforge() {
|
|
|
346
348
|
try {
|
|
347
349
|
const projectRequire = createRequire(process.cwd() + "/");
|
|
348
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
|
+
}
|
|
349
393
|
} catch (error) {
|
|
350
394
|
console.warn(
|
|
351
395
|
"[@macroforge/vite-plugin] Rust binary not found. Please run `npm run build:rust` first.",
|
|
@@ -454,17 +498,84 @@ export async function macroforge() {
|
|
|
454
498
|
* @returns {string}
|
|
455
499
|
*/
|
|
456
500
|
function getMacroforgeVersion() {
|
|
501
|
+
const req = createRequire(process.cwd() + "/");
|
|
457
502
|
try {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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);
|
|
467
577
|
}
|
|
578
|
+
return hasher.digest("hex");
|
|
468
579
|
}
|
|
469
580
|
|
|
470
581
|
/**
|
|
@@ -517,6 +628,17 @@ export async function macroforge() {
|
|
|
517
628
|
return null;
|
|
518
629
|
}
|
|
519
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
|
+
|
|
520
642
|
return manifest;
|
|
521
643
|
} catch {
|
|
522
644
|
return null;
|
|
@@ -573,6 +695,7 @@ export async function macroforge() {
|
|
|
573
695
|
cacheManifest = {
|
|
574
696
|
version: macroforgeVersion,
|
|
575
697
|
configHash: getConfigHash(),
|
|
698
|
+
externalMacroHash: getExternalMacroHash(),
|
|
576
699
|
entries: {},
|
|
577
700
|
};
|
|
578
701
|
}
|
|
@@ -726,42 +849,61 @@ export async function macroforge() {
|
|
|
726
849
|
},
|
|
727
850
|
|
|
728
851
|
/**
|
|
729
|
-
*
|
|
852
|
+
* Load the type registry from the CLI cache for compile-time type awareness.
|
|
730
853
|
* The registry is passed to every expandSync call so macros can introspect
|
|
731
|
-
* any type in the project
|
|
854
|
+
* any type in the project.
|
|
732
855
|
*/
|
|
733
856
|
buildStart() {
|
|
734
|
-
|
|
735
|
-
|
|
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
|
+
);
|
|
736
877
|
}
|
|
878
|
+
},
|
|
737
879
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
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;
|
|
744
891
|
|
|
745
|
-
|
|
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
|
+
});
|
|
746
897
|
|
|
747
|
-
|
|
748
|
-
`[@macroforge/vite-plugin] Type scan: ${scanResult.typesFound} types from ${scanResult.filesScanned} files (${scanTime}ms)`,
|
|
749
|
-
);
|
|
898
|
+
if (resolved && !resolved.external) return resolved;
|
|
750
899
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
} catch (error) {
|
|
759
|
-
console.warn(
|
|
760
|
-
`[@macroforge/vite-plugin] Type scan failed, macros will run without type awareness:`,
|
|
761
|
-
error.message || error,
|
|
762
|
-
);
|
|
763
|
-
typeRegistryJson = undefined;
|
|
764
|
-
}
|
|
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;
|
|
765
907
|
},
|
|
766
908
|
|
|
767
909
|
/**
|
|
@@ -789,8 +931,8 @@ export async function macroforge() {
|
|
|
789
931
|
return null;
|
|
790
932
|
}
|
|
791
933
|
|
|
792
|
-
// Quick check: files without @derive
|
|
793
|
-
if (!code
|
|
934
|
+
// Quick check: skip files without a real @derive directive
|
|
935
|
+
if (!hasMacroAnnotations(code)) {
|
|
794
936
|
return null;
|
|
795
937
|
}
|
|
796
938
|
|
|
@@ -801,7 +943,6 @@ export async function macroforge() {
|
|
|
801
943
|
if (cached) {
|
|
802
944
|
let cachedCode = cached.code;
|
|
803
945
|
|
|
804
|
-
// Apply same post-processing as the normal path
|
|
805
946
|
cachedCode = cachedCode.replace(
|
|
806
947
|
/\/\*\*\s*import\s+macro[\s\S]*?\*\/\s*/gi,
|
|
807
948
|
"",
|
|
@@ -813,18 +954,6 @@ export async function macroforge() {
|
|
|
813
954
|
);
|
|
814
955
|
}
|
|
815
956
|
|
|
816
|
-
// Generate type definitions from cached expanded code
|
|
817
|
-
if (generateTypes) {
|
|
818
|
-
const emitted = emitDeclarationsFromCode(
|
|
819
|
-
cachedCode,
|
|
820
|
-
id,
|
|
821
|
-
projectRoot,
|
|
822
|
-
);
|
|
823
|
-
if (emitted) {
|
|
824
|
-
writeTypeDefinitions(id, emitted);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
957
|
return {
|
|
829
958
|
code: cachedCode,
|
|
830
959
|
map: null,
|