macroforge 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.
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Svelte-check wrapper — spawned by the CLI's `run_svelte_check_wrapper`.
3
+ *
4
+ * Patches `ts.sys.readFile` to expand macros before svelte-check sees the files.
5
+ * Since svelte-check uses TypeScript as a peer dependency and Node.js caches
6
+ * modules, the patched `ts.sys.readFile` is shared with svelte-check's internal
7
+ * TypeScript language service.
8
+ *
9
+ * Arguments:
10
+ * argv[2..] — forwarded to svelte-check CLI
11
+ *
12
+ * Environment:
13
+ * MACROFORGE_TYPE_REGISTRY_PATH — path to pre-built type registry JSON
14
+ */
15
+ const { createRequire } = require("module");
16
+ const fs = require("fs");
17
+ const path = require("path");
18
+ const cwdRequire = createRequire(process.cwd() + "/package.json");
19
+ let ts;
20
+ let macros;
21
+ try {
22
+ ts = cwdRequire("typescript");
23
+ } catch {
24
+ console.error(
25
+ "[macroforge] error: typescript is not installed in this project",
26
+ );
27
+ process.exit(1);
28
+ }
29
+ try {
30
+ macros = cwdRequire("macroforge");
31
+ } catch {
32
+ console.error(
33
+ "[macroforge] error: macroforge is not installed in this project",
34
+ );
35
+ process.exit(1);
36
+ }
37
+ if (macros.setupExternalMacros) {
38
+ let resolveDecoratorNames = function (packagePath) {
39
+ const candidates = [packagePath];
40
+ for (const id of candidates) {
41
+ try {
42
+ const pkg = req(id);
43
+ const names = [];
44
+ if (pkg.__macroforgeGetManifest) {
45
+ names.push(
46
+ ...(pkg.__macroforgeGetManifest().decorators || []).map(
47
+ (d) => d.export,
48
+ ),
49
+ );
50
+ }
51
+ for (const key of Object.keys(pkg)) {
52
+ if (
53
+ key.startsWith("__macroforgeGetManifest_") &&
54
+ typeof pkg[key] === "function"
55
+ ) {
56
+ names.push(...(pkg[key]().decorators || []).map((d) => d.export));
57
+ }
58
+ }
59
+ if (names.length > 0) return [...new Set(names)];
60
+ } catch {}
61
+ }
62
+ return [];
63
+ },
64
+ runMacro = function (ctxJson) {
65
+ const ctx = JSON.parse(ctxJson);
66
+ const fnName = `__macroforgeRun${ctx.macro_name}`;
67
+ const candidates = [ctx.module_path];
68
+ for (const id of candidates) {
69
+ try {
70
+ const pkg = req(id);
71
+ const fn_ = pkg?.[fnName] || pkg?.default?.[fnName];
72
+ if (typeof fn_ === "function") return fn_(ctxJson);
73
+ } catch {}
74
+ }
75
+ throw new Error(`Macro ${fnName} not found in ${ctx.module_path}`);
76
+ };
77
+ var resolveDecoratorNames2 = resolveDecoratorNames,
78
+ runMacro2 = runMacro;
79
+ const req = createRequire(process.cwd() + "/package.json");
80
+ macros.setupExternalMacros(resolveDecoratorNames, runMacro);
81
+ }
82
+ const CONFIG_FILES = [
83
+ "macroforge.config.ts",
84
+ "macroforge.config.mts",
85
+ "macroforge.config.js",
86
+ "macroforge.config.mjs",
87
+ "macroforge.config.cjs",
88
+ ];
89
+ let macroConfigPath = null;
90
+ let currentDir = process.cwd();
91
+ while (true) {
92
+ for (const filename of CONFIG_FILES) {
93
+ const candidate = path.join(currentDir, filename);
94
+ if (fs.existsSync(candidate)) {
95
+ macroConfigPath = candidate;
96
+ break;
97
+ }
98
+ }
99
+ if (macroConfigPath) break;
100
+ if (fs.existsSync(path.join(currentDir, "package.json"))) break;
101
+ const parent = path.dirname(currentDir);
102
+ if (parent === currentDir) break;
103
+ currentDir = parent;
104
+ }
105
+ if (macroConfigPath) {
106
+ try {
107
+ const configContent = fs.readFileSync(macroConfigPath, "utf8");
108
+ macros.loadConfig(configContent, macroConfigPath);
109
+ } catch {}
110
+ }
111
+ const typeRegistryPath = process.env.MACROFORGE_TYPE_REGISTRY_PATH;
112
+ let typeRegistryJson = void 0;
113
+ if (typeRegistryPath) {
114
+ try {
115
+ typeRegistryJson = fs.readFileSync(typeRegistryPath, "utf8");
116
+ } catch {}
117
+ }
118
+ const plugin = new macros.NativePlugin();
119
+ const expandOpts = {};
120
+ if (macroConfigPath) expandOpts.configPath = macroConfigPath;
121
+ if (typeRegistryJson) expandOpts.typeRegistryJson = typeRegistryJson;
122
+ const tsSys = ts.sys;
123
+ const origReadFile = tsSys.readFile.bind(tsSys);
124
+ tsSys.readFile = (filePath, encoding) => {
125
+ const content = origReadFile(filePath, encoding);
126
+ if (content == null) return content;
127
+ try {
128
+ if (
129
+ (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) &&
130
+ !filePath.endsWith(".d.ts") &&
131
+ content.includes("@derive")
132
+ ) {
133
+ const result = plugin.processFile(filePath, content, expandOpts);
134
+ return result.code || content;
135
+ }
136
+ } catch {}
137
+ return content;
138
+ };
139
+ const args = ["svelte-check"];
140
+ for (let i = 2; i < process.argv.length; i++) {
141
+ args.push(process.argv[i]);
142
+ }
143
+ process.argv = [process.argv[0], ...args];
144
+ try {
145
+ cwdRequire("svelte-check");
146
+ } catch (e) {
147
+ if (e.code === "MODULE_NOT_FOUND") {
148
+ console.error(
149
+ "[macroforge] error: svelte-check is not installed in this project",
150
+ );
151
+ console.error(
152
+ "[macroforge] install it with: npm install --save-dev svelte-check",
153
+ );
154
+ process.exit(1);
155
+ }
156
+ throw e;
157
+ }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * TSC wrapper — spawned by the CLI's `run_tsc_wrapper`.
3
+ *
4
+ * Wraps `tsc --noEmit` with macro expansion baked into file reads.
5
+ * Files containing `@derive` are expanded before being passed to the
6
+ * TypeScript compiler.
7
+ *
8
+ * Arguments:
9
+ * argv[2] — tsconfig path (default: "tsconfig.json")
10
+ *
11
+ * Environment:
12
+ * MACROFORGE_TYPE_REGISTRY_PATH — path to pre-built type registry JSON
13
+ */
14
+ const { createRequire } = require("module");
15
+ const fs = require("fs");
16
+ const path = require("path");
17
+ const cwdRequire = createRequire(process.cwd() + "/package.json");
18
+ const ts = cwdRequire("typescript");
19
+ const macros = cwdRequire("macroforge");
20
+ if (macros.setupExternalMacros) {
21
+ let resolveDecoratorNames = function (packagePath) {
22
+ const candidates = [packagePath];
23
+ for (const id of candidates) {
24
+ try {
25
+ const pkg = req(id);
26
+ const names = [];
27
+ if (pkg.__macroforgeGetManifest) {
28
+ names.push(
29
+ ...(pkg.__macroforgeGetManifest().decorators || []).map(
30
+ (d) => d.export,
31
+ ),
32
+ );
33
+ }
34
+ for (const key of Object.keys(pkg)) {
35
+ if (
36
+ key.startsWith("__macroforgeGetManifest_") &&
37
+ typeof pkg[key] === "function"
38
+ ) {
39
+ names.push(...(pkg[key]().decorators || []).map((d) => d.export));
40
+ }
41
+ }
42
+ if (names.length > 0) return [...new Set(names)];
43
+ } catch {}
44
+ }
45
+ return [];
46
+ },
47
+ runMacro = function (ctxJson) {
48
+ const ctx = JSON.parse(ctxJson);
49
+ const fnName = `__macroforgeRun${ctx.macro_name}`;
50
+ const candidates = [ctx.module_path];
51
+ for (const id of candidates) {
52
+ try {
53
+ const pkg = req(id);
54
+ const fn_ = pkg?.[fnName] || pkg?.default?.[fnName];
55
+ if (typeof fn_ === "function") return fn_(ctxJson);
56
+ } catch {}
57
+ }
58
+ throw new Error(`Macro ${fnName} not found in ${ctx.module_path}`);
59
+ };
60
+ var resolveDecoratorNames2 = resolveDecoratorNames,
61
+ runMacro2 = runMacro;
62
+ const req = createRequire(process.cwd() + "/package.json");
63
+ macros.setupExternalMacros(resolveDecoratorNames, runMacro);
64
+ }
65
+ const projectArg = process.argv[2] || "tsconfig.json";
66
+ const configPath = ts.findConfigFile(
67
+ process.cwd(),
68
+ ts.sys.fileExists,
69
+ projectArg,
70
+ );
71
+ if (!configPath) {
72
+ console.error(`[macroforge] tsconfig not found: ${projectArg}`);
73
+ process.exit(1);
74
+ }
75
+ const CONFIG_FILES = [
76
+ "macroforge.config.ts",
77
+ "macroforge.config.mts",
78
+ "macroforge.config.js",
79
+ "macroforge.config.mjs",
80
+ "macroforge.config.cjs",
81
+ ];
82
+ let macroConfigPath = null;
83
+ let currentDir = process.cwd();
84
+ while (true) {
85
+ for (const filename of CONFIG_FILES) {
86
+ const candidate = path.join(currentDir, filename);
87
+ if (fs.existsSync(candidate)) {
88
+ macroConfigPath = candidate;
89
+ break;
90
+ }
91
+ }
92
+ if (macroConfigPath) break;
93
+ if (fs.existsSync(path.join(currentDir, "package.json"))) break;
94
+ const parent = path.dirname(currentDir);
95
+ if (parent === currentDir) break;
96
+ currentDir = parent;
97
+ }
98
+ if (macroConfigPath) {
99
+ try {
100
+ const configContent = fs.readFileSync(macroConfigPath, "utf8");
101
+ macros.loadConfig(configContent, macroConfigPath);
102
+ } catch {}
103
+ }
104
+ const typeRegistryPath = process.env.MACROFORGE_TYPE_REGISTRY_PATH;
105
+ let typeRegistryJson = void 0;
106
+ if (typeRegistryPath) {
107
+ try {
108
+ typeRegistryJson = fs.readFileSync(typeRegistryPath, "utf8");
109
+ } catch {}
110
+ }
111
+ const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
112
+ if (configFile.error) {
113
+ console.error(
114
+ ts.formatDiagnostic(configFile.error, {
115
+ getCanonicalFileName: (f) => f,
116
+ getCurrentDirectory: ts.sys.getCurrentDirectory,
117
+ getNewLine: () => ts.sys.newLine,
118
+ }),
119
+ );
120
+ process.exit(1);
121
+ }
122
+ const parsed = ts.parseJsonConfigFileContent(
123
+ configFile.config,
124
+ ts.sys,
125
+ path.dirname(configPath),
126
+ );
127
+ const options = { ...parsed.options, noEmit: true };
128
+ const formatHost = {
129
+ getCanonicalFileName: (f) => f,
130
+ getCurrentDirectory: ts.sys.getCurrentDirectory,
131
+ getNewLine: () => ts.sys.newLine,
132
+ };
133
+ const plugin = new macros.NativePlugin();
134
+ const tscExpandOpts = {};
135
+ if (macroConfigPath) tscExpandOpts.configPath = macroConfigPath;
136
+ if (typeRegistryJson) tscExpandOpts.typeRegistryJson = typeRegistryJson;
137
+ const host = ts.createCompilerHost(options);
138
+ const origGetSourceFile = host.getSourceFile.bind(host);
139
+ host.getSourceFile = (fileName, languageVersion, ...rest) => {
140
+ try {
141
+ if (
142
+ (fileName.endsWith(".ts") || fileName.endsWith(".tsx")) &&
143
+ !fileName.endsWith(".d.ts")
144
+ ) {
145
+ const sourceText = ts.sys.readFile(fileName);
146
+ if (sourceText && sourceText.includes("@derive")) {
147
+ const result = plugin.processFile(fileName, sourceText, tscExpandOpts);
148
+ const text = result.code || sourceText;
149
+ return ts.createSourceFile(fileName, text, languageVersion, true);
150
+ }
151
+ }
152
+ } catch {}
153
+ return origGetSourceFile(fileName, languageVersion, ...rest);
154
+ };
155
+ const program = ts.createProgram(parsed.fileNames, options, host);
156
+ const diagnostics = ts.getPreEmitDiagnostics(program);
157
+ if (diagnostics.length) {
158
+ diagnostics.forEach((d) => {
159
+ const msg = ts.formatDiagnostic(d, formatHost);
160
+ console.error(msg.trimEnd());
161
+ });
162
+ }
163
+ const hasError = diagnostics.some(
164
+ (d) => d.category === ts.DiagnosticCategory.Error,
165
+ );
166
+ process.exit(hasError ? 1 : 0);
package/package.json CHANGED
@@ -1,92 +1,67 @@
1
1
  {
2
2
  "author": "macroforge contributors",
3
3
  "bugs": {
4
- "url": "https://github.com/macroforge-ts/core/issues"
5
- },
6
- "dependencies": {
7
- "@napi-rs/cli": "^3.5.1"
8
- },
9
- "description": "TypeScript macro expansion engine powered by Rust and SWC",
10
- "engines": {
11
- "node": ">= 24"
4
+ "url": "https://github.com/macroforge-ts/macroforge-ts/issues"
12
5
  },
6
+ "description": "TypeScript macro expansion engine powered by Rust, Oxc, and WebAssembly",
13
7
  "exports": {
14
8
  ".": {
15
- "default": "./index.js",
16
- "require": "./index.js",
17
- "types": "./index.d.ts"
9
+ "types": "./pkg/macroforge_ts.d.ts",
10
+ "require": "./pkg/macroforge_ts.js",
11
+ "default": "./pkg/macroforge_ts.js"
18
12
  },
19
13
  "./reexports": {
20
- "default": "./js/reexports/index.mjs",
14
+ "types": "./js/reexports/index.d.ts",
21
15
  "import": "./js/reexports/index.mjs",
22
- "types": "./js/reexports/index.d.ts"
16
+ "default": "./js/reexports/index.mjs"
23
17
  },
24
18
  "./reexports/effect": {
25
- "default": "./js/reexports/effect.mjs",
19
+ "types": "./js/reexports/effect.d.ts",
26
20
  "import": "./js/reexports/effect.mjs",
27
- "types": "./js/reexports/effect.d.ts"
21
+ "default": "./js/reexports/effect.mjs"
28
22
  },
29
23
  "./serde": {
30
- "default": "./js/serde/index.mjs",
24
+ "types": "./js/serde/index.d.ts",
31
25
  "import": "./js/serde/index.mjs",
32
- "types": "./js/serde/index.d.ts"
26
+ "default": "./js/serde/index.mjs"
33
27
  },
34
28
  "./traits": {
35
- "default": "./js/traits/index.mjs",
29
+ "types": "./js/traits/index.d.ts",
36
30
  "import": "./js/traits/index.mjs",
37
- "types": "./js/traits/index.d.ts"
31
+ "default": "./js/traits/index.mjs"
38
32
  }
39
33
  },
40
34
  "files": [
41
- "index.d.ts",
42
- "index.js",
43
- "js"
35
+ "js",
36
+ "pkg"
44
37
  ],
45
- "homepage": "https://github.com/macroforge-ts/core#readme",
38
+ "homepage": "https://github.com/macroforge-ts/macroforge-ts#readme",
46
39
  "keywords": [
47
40
  "typescript",
48
41
  "macros",
49
42
  "derive",
50
43
  "codegen",
51
- "swc"
44
+ "oxc",
45
+ "wasm",
46
+ "webassembly"
52
47
  ],
53
48
  "license": "MIT",
54
- "main": "index.js",
49
+ "main": "./pkg/macroforge_ts.js",
55
50
  "name": "macroforge",
56
- "napi": {
57
- "binaryName": "macroforge",
58
- "packageName": "@macroforge/bin",
59
- "targets": [
60
- "x86_64-apple-darwin",
61
- "aarch64-apple-darwin",
62
- "x86_64-unknown-linux-gnu",
63
- "aarch64-unknown-linux-gnu",
64
- "x86_64-pc-windows-msvc",
65
- "aarch64-pc-windows-msvc"
66
- ]
67
- },
68
- "optionalDependencies": {
69
- "@macroforge/bin-darwin-arm64": "0.1.78",
70
- "@macroforge/bin-darwin-x64": "0.1.78",
71
- "@macroforge/bin-linux-arm64-gnu": "0.1.78",
72
- "@macroforge/bin-linux-x64-gnu": "0.1.78",
73
- "@macroforge/bin-win32-arm64-msvc": "0.1.78",
74
- "@macroforge/bin-win32-x64-msvc": "0.1.78"
75
- },
76
51
  "repository": {
77
52
  "type": "git",
78
- "url": "git+https://github.com/macroforge-ts/core.git"
53
+ "url": "git+https://github.com/macroforge-ts/macroforge-ts.git"
79
54
  },
80
55
  "scripts": {
81
- "artifacts": "napi artifacts --npm-dir npm",
82
- "build": "deno install --node-modules-dir && deno task build:js && deno run -A npm:@napi-rs/cli/napi build --platform --release && cargo install --path . --force",
56
+ "build": "deno task build:wasm",
83
57
  "build:js": "deno task build:serde && deno task build:traits",
84
58
  "build:serde": "deno run -A npm:esbuild js/serde/index.ts --bundle --outfile=js/serde/index.mjs --format=esm && deno run -A npm:typescript/tsc js/serde/index.ts --declaration --emitDeclarationOnly --outDir js/serde --lib ES2024 --skipLibCheck",
85
59
  "build:traits": "deno run -A npm:esbuild js/traits/index.ts --bundle --outfile=js/traits/index.mjs --format=esm && deno run -A npm:typescript/tsc js/traits/index.ts --declaration --emitDeclarationOnly --outDir js/traits --lib ES2024 --skipLibCheck",
86
- "clean": "rm -f macroforge.*.node || true; rm -f pkg/*.node || true; rm -rf node_modules",
60
+ "build:wasm": "deno install --node-modules-dir && deno task build:js && cargo build --release --target wasm32-unknown-unknown && deno run -A ../../tooling/scripts/bench.mjs --wasm-bindgen target/wasm32-unknown-unknown/release/macroforge_ts.wasm pkg",
61
+ "clean": "rm -rf pkg node_modules",
87
62
  "cleanbuild": "deno task clean && deno task build"
88
63
  },
89
64
  "type": "commonjs",
90
- "types": "index.d.ts",
91
- "version": "0.1.78"
65
+ "types": "./pkg/macroforge_ts.d.ts",
66
+ "version": "0.1.79"
92
67
  }
@@ -0,0 +1,97 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ export function Derive(): void;
5
+
6
+ export class NativeMapper {
7
+ private constructor();
8
+ free(): void;
9
+ [Symbol.dispose](): void;
10
+ expandedToOriginal(pos: number): number | undefined;
11
+ generatedBy(pos: number): string | undefined;
12
+ isEmpty(): boolean;
13
+ isInGenerated(pos: number): boolean;
14
+ mapSpanToExpanded(start: number, length: number): any;
15
+ mapSpanToOriginal(start: number, length: number): any;
16
+ originalToExpanded(pos: number): number;
17
+ }
18
+
19
+ export class NativePlugin {
20
+ free(): void;
21
+ [Symbol.dispose](): void;
22
+ expandSync(code: string, filepath: string, options: any): any;
23
+ getMapper(filepath: string): NativeMapper | undefined;
24
+ log(_message: string): void;
25
+ mapDiagnostics(filepath: string, diags: any): any;
26
+ constructor();
27
+ processFile(filepath: string, code: string, options: any): any;
28
+ transformSync(code: string, filepath: string): any;
29
+ }
30
+
31
+ export class NativePositionMapper {
32
+ free(): void;
33
+ [Symbol.dispose](): void;
34
+ mapToExpanded(_line: number, _column: number): any;
35
+ mapToOriginal(_line: number, _column: number): any;
36
+ constructor(_mapping: any);
37
+ }
38
+
39
+ export function __macroforgeDebugDescriptors(): any;
40
+
41
+ export function __macroforgeDebugGetModules(): any;
42
+
43
+ export function __macroforgeDebugLookup(module: string, name: string): string;
44
+
45
+ export function __macroforgeGetMacroNames(): any;
46
+
47
+ export function __macroforgeGetManifest(): any;
48
+
49
+ export function __macroforgeIsMacroPackage(): boolean;
50
+
51
+ export function __macroforgeRunClone(context_json: string): string;
52
+
53
+ export function __macroforgeRunDebug(context_json: string): string;
54
+
55
+ export function __macroforgeRunDefault(context_json: string): string;
56
+
57
+ export function __macroforgeRunDeserialize(context_json: string): string;
58
+
59
+ export function __macroforgeRunHash(context_json: string): string;
60
+
61
+ export function __macroforgeRunOrd(context_json: string): string;
62
+
63
+ export function __macroforgeRunPartialEq(context_json: string): string;
64
+
65
+ export function __macroforgeRunPartialOrd(context_json: string): string;
66
+
67
+ export function __macroforgeRunSerialize(context_json: string): string;
68
+
69
+ export function checkSyntax(code: string, filepath: string): any;
70
+
71
+ export function clearConfigCache(): void;
72
+
73
+ export function expandSync(code: string, filepath: string, options: any): any;
74
+
75
+ export function loadConfig(content: string, filepath: string): any;
76
+
77
+ export function parseImportSources(code: string, filepath: string): any;
78
+
79
+ export function scanProjectSync(root_dir: string, options: any): any;
80
+
81
+ /**
82
+ * Register JS callbacks for resolving and running external (user-defined) macros.
83
+ *
84
+ * Required for WASM builds. The native (NAPI) build resolves external macros
85
+ * by spawning a Node subprocess, but WASM cannot spawn processes. Instead, the
86
+ * host JS environment must provide two callbacks:
87
+ *
88
+ * resolve: Given a package path, return an array of decorator names exported by that package.
89
+ *
90
+ * run: Given a JSON-serialized MacroContextIR, execute the external macro and return a JSON-serialized MacroResult.
91
+ *
92
+ * Must be called before expandSync if the source uses import macro comments.
93
+ * Does not exist on NAPI builds, so guard the call.
94
+ */
95
+ export function setupExternalMacros(resolve: Function, run: Function): void;
96
+
97
+ export function transformSync(code: string, filepath: string): any;