macroforge 0.1.79 → 0.1.80
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 +28 -51
- package/js/buildtime/index.d.ts +107 -0
- package/js/buildtime/index.mjs +65 -0
- package/js/buildtime/index.ts +176 -0
- package/js/cli/svelte-check-wrapper.js +21 -1
- package/js/cli/tsc-wrapper.js +34 -2
- package/js/rules/index.d.ts +94 -0
- package/js/rules/index.mjs +9 -0
- package/js/rules/index.ts +109 -0
- package/package.json +73 -61
- package/pkg/macroforge_ts.d.ts +35 -0
- package/pkg/macroforge_ts.js +114 -0
- package/pkg/macroforge_ts_bg.wasm +0 -0
- package/pkg/macroforge_ts_bg.wasm.d.ts +20 -8
package/README.md
CHANGED
|
@@ -5,9 +5,13 @@ TypeScript macro expansion engine - write compile-time macros in Rust
|
|
|
5
5
|
[](https://crates.io/crates/macroforge_ts)
|
|
6
6
|
[](https://docs.rs/macroforge_ts)
|
|
7
7
|
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
8
10
|
This crate provides a TypeScript macro expansion engine that brings Rust-like derive macros to
|
|
9
|
-
TypeScript. It
|
|
10
|
-
|
|
11
|
+
TypeScript. It supports multiple output targets via feature flags:
|
|
12
|
+
|
|
13
|
+
- `wasm`: (Default) Universal WebAssembly module via wasm-bindgen for browser and edge environments.
|
|
14
|
+
- `node`: Optional native Node.js bindings via NAPI-RS.
|
|
11
15
|
|
|
12
16
|
## Overview
|
|
13
17
|
|
|
@@ -19,31 +23,30 @@ concrete implementations. For example, a class decorated with `@derive(Debug, Cl
|
|
|
19
23
|
|
|
20
24
|
The crate is organized into several key components:
|
|
21
25
|
|
|
22
|
-
- **
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
- **Unified API** (`api` module): An output-agnostic trait-based interface (`MacroforgeApi`) that
|
|
27
|
+
defines all macro operations.
|
|
28
|
+
- **Target Bindings**:
|
|
29
|
+
- `bindings_napi`: Node.js specific entry points using NAPI-RS.
|
|
30
|
+
- `bindings_wasm`: Universal entry points using `wasm-bindgen`.
|
|
31
|
+
- **Position Mapping** (`api_types::SourceMappingResult`): Bidirectional source mapping for IDE
|
|
32
|
+
integration.
|
|
33
|
+
- **Macro Host** (`host` module): Core expansion engine with registry and dispatcher.
|
|
34
|
+
- **Built-in Macros** (`builtin` module): Standard derive macros (Debug, Clone, Serialize, etc.).
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
- Implements early bailout for files without `@derive` decorators
|
|
32
|
-
- Caches expansion results keyed by filepath and version
|
|
33
|
-
- Uses binary search for O(log n) position mapping lookups
|
|
36
|
+
## Usage
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
### From Node.js
|
|
36
39
|
|
|
37
40
|
```javascript
|
|
38
|
-
const {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const plugin = new NativePlugin();
|
|
41
|
+
const { expandSync } = require('macroforge');
|
|
42
|
+
const result = expandSync(code, filepath, { keep_decorators: false });
|
|
43
|
+
```
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
const result = plugin.process_file(filepath, code, { version: '1.0' });
|
|
45
|
+
### From WASM
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
```javascript
|
|
48
|
+
import init, { expand_sync } from './pkg/macroforge_ts.js';
|
|
49
|
+
await init();
|
|
47
50
|
const result = expand_sync(code, filepath, { keep_decorators: false });
|
|
48
51
|
```
|
|
49
52
|
|
|
@@ -53,7 +56,7 @@ This crate re-exports several dependencies for convenience when writing custom m
|
|
|
53
56
|
|
|
54
57
|
- `ts_syn`: TypeScript syntax types for AST manipulation
|
|
55
58
|
- `macros`: Macro attributes and quote templates
|
|
56
|
-
- `swc_core`, `swc_common`, `swc_ecma_ast`: SWC
|
|
59
|
+
- `swc_core`, `swc_common`, `swc_ecma_ast`: SWC compatibility infrastructure
|
|
57
60
|
|
|
58
61
|
## Installation
|
|
59
62
|
|
|
@@ -61,41 +64,15 @@ Add this to your `Cargo.toml`:
|
|
|
61
64
|
|
|
62
65
|
```toml
|
|
63
66
|
[dependencies]
|
|
64
|
-
macroforge_ts = "0.1.
|
|
67
|
+
macroforge_ts = "0.1.79"
|
|
65
68
|
```
|
|
66
69
|
|
|
67
70
|
## Key Exports
|
|
68
71
|
|
|
69
|
-
### Structs
|
|
70
|
-
|
|
71
|
-
- **`TransformResult`** - Result of transforming TypeScript code through the macro system.
|
|
72
|
-
- **`MacroDiagnostic`** - A diagnostic message produced during macro expansion.
|
|
73
|
-
- **`MappingSegmentResult`** - A segment mapping a range in the original source to a range in the
|
|
74
|
-
expanded source.
|
|
75
|
-
- **`GeneratedRegionResult`** - A region in the expanded source that was generated by a macro.
|
|
76
|
-
- **`SourceMappingResult`** - Complete source mapping information for a macro expansion.
|
|
77
|
-
- **`ExpandResult`** - Result of expanding macros in TypeScript source code.
|
|
78
|
-
- **`ImportSourceResult`** - Information about an imported identifier from a TypeScript module.
|
|
79
|
-
- **`SyntaxCheckResult`** - Result of checking TypeScript syntax validity.
|
|
80
|
-
- **`SpanResult`** - A span (range) in source code, represented as start position and length.
|
|
81
|
-
- **`JsDiagnostic`** - A diagnostic from the TypeScript/JavaScript compiler or IDE.
|
|
82
|
-
- ... and 8 more
|
|
83
|
-
|
|
84
72
|
### Functions
|
|
85
73
|
|
|
86
|
-
- **`
|
|
87
|
-
- **`
|
|
88
|
-
- **`is_empty`** - Checks if this mapper has no mapping data.
|
|
89
|
-
- **`original_to_expanded`** - Converts a position in the original source to the corresponding
|
|
90
|
-
position in expanded source.
|
|
91
|
-
- **`expanded_to_original`** - Converts a position in the expanded source back to the original
|
|
92
|
-
source position.
|
|
93
|
-
- **`generated_by`** - Returns the name of the macro that generated code at the given position.
|
|
94
|
-
- **`map_span_to_original`** - Maps a span (start + length) from expanded source to original source.
|
|
95
|
-
- **`map_span_to_expanded`** - Maps a span (start + length) from original source to expanded source.
|
|
96
|
-
- **`is_in_generated`** - Checks if a position is inside macro-generated code.
|
|
97
|
-
- **`new`** - Creates a new mapper wrapping the given source mapping.
|
|
98
|
-
- ... and 23 more
|
|
74
|
+
- **`__macroforge_ffi_free`** - Free a buffer allocated by an FFI function.
|
|
75
|
+
- **`__macroforge_ffi_get_manifest`** - Returns the full MacroManifest as JSON via FFI.
|
|
99
76
|
|
|
100
77
|
## API Reference
|
|
101
78
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Macroforge Buildtime Module
|
|
3
|
+
*
|
|
4
|
+
* Compile-time JavaScript evaluation — the Zig-comptime primitive for
|
|
5
|
+
* TypeScript. Annotate a top-level `const` or `function` declaration with
|
|
6
|
+
* `/** @buildtime *\/` and the macroforge build pass evaluates it in a
|
|
7
|
+
* sandboxed JS context, serializes the result, and splices a plain TS
|
|
8
|
+
* literal back into the module.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* /** @buildtime *\/
|
|
12
|
+
* const BUILT_AT = buildtime.time.iso();
|
|
13
|
+
*
|
|
14
|
+
* /** @buildtime *\/
|
|
15
|
+
* const SCHEMA = buildtime.fs.readJson("./schema.json");
|
|
16
|
+
*
|
|
17
|
+
* /** @buildtime *\/
|
|
18
|
+
* function generateValidators() {
|
|
19
|
+
* const schema = buildtime.fs.readJson("./schema.json");
|
|
20
|
+
* return schema.fields.map(f =>
|
|
21
|
+
* `export function is_${f.name}(v: unknown): v is ${f.type} {
|
|
22
|
+
* return typeof v === "${f.jsType}";
|
|
23
|
+
* }`
|
|
24
|
+
* ).join("\n");
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* ## Runtime behavior
|
|
29
|
+
*
|
|
30
|
+
* Every export from this module is a sentinel. Calling any of them at
|
|
31
|
+
* runtime throws — they should have been resolved by the macroforge
|
|
32
|
+
* build pass and no longer exist in the output. If you see the runtime
|
|
33
|
+
* error, the build pass is not running on this file.
|
|
34
|
+
*
|
|
35
|
+
* @module macroforge/buildtime
|
|
36
|
+
*/
|
|
37
|
+
export interface BuildtimeFs {
|
|
38
|
+
/** Read a file as UTF-8 text. Path is resolved relative to the file the
|
|
39
|
+
* @buildtime declaration lives in. Throws if the path is not in the
|
|
40
|
+
* `buildtime.capabilities.filesystem.read` allowlist. */
|
|
41
|
+
readText(path: string): string;
|
|
42
|
+
/** Read a file and parse its content as JSON. Same capability rules
|
|
43
|
+
* as `readText`. */
|
|
44
|
+
readJson(path: string): unknown;
|
|
45
|
+
/** Return whether the path exists on disk. Counts as a read for
|
|
46
|
+
* dependency tracking — if the file appears later, the cache
|
|
47
|
+
* invalidates. */
|
|
48
|
+
exists(path: string): boolean;
|
|
49
|
+
/** Return the names of the entries in a directory, sorted. Counts as
|
|
50
|
+
* a read. */
|
|
51
|
+
listDir(path: string): string[];
|
|
52
|
+
}
|
|
53
|
+
export interface BuildtimeCrypto {
|
|
54
|
+
/** SHA-256 of the input, lowercase hex. Pure — always allowed. */
|
|
55
|
+
sha256(input: string): string;
|
|
56
|
+
/** SHA-512 of the input, lowercase hex. Pure — always allowed. */
|
|
57
|
+
sha512(input: string): string;
|
|
58
|
+
}
|
|
59
|
+
export interface BuildtimeTime {
|
|
60
|
+
/** Current wall-clock time as an ISO 8601 string. Makes builds
|
|
61
|
+
* non-deterministic — prefer recording a fixed timestamp if
|
|
62
|
+
* determinism matters. */
|
|
63
|
+
now(): string;
|
|
64
|
+
/** Current wall-clock time in unix seconds. */
|
|
65
|
+
unix(): number;
|
|
66
|
+
/** Alias for {@link BuildtimeTime.now}. */
|
|
67
|
+
iso(): string;
|
|
68
|
+
}
|
|
69
|
+
export interface BuildtimeFlags {
|
|
70
|
+
/** True if the named flag was passed to the build (e.g. from a
|
|
71
|
+
* `--define` argument or from `config.buildtime.flags`). */
|
|
72
|
+
has(flag: string): boolean;
|
|
73
|
+
/** Value of the named flag, or undefined if not set. */
|
|
74
|
+
get(flag: string): string | undefined;
|
|
75
|
+
}
|
|
76
|
+
export interface BuildtimeLocation {
|
|
77
|
+
/** Absolute path of the source file the @buildtime declaration
|
|
78
|
+
* lives in. */
|
|
79
|
+
readonly file: string;
|
|
80
|
+
/** 1-based line number of the `/** @buildtime *\/` annotation. */
|
|
81
|
+
readonly line: number;
|
|
82
|
+
/** 1-based column number of the annotation. */
|
|
83
|
+
readonly column: number;
|
|
84
|
+
}
|
|
85
|
+
export interface Buildtime {
|
|
86
|
+
readonly fs: BuildtimeFs;
|
|
87
|
+
readonly crypto: BuildtimeCrypto;
|
|
88
|
+
readonly time: BuildtimeTime;
|
|
89
|
+
/** Environment variables the build was allowed to read. Populated
|
|
90
|
+
* from `buildtime.capabilities.env` in macroforge.config.js. Reads
|
|
91
|
+
* of variables not in the allowlist return `undefined`. */
|
|
92
|
+
readonly env: Record<string, string | undefined>;
|
|
93
|
+
readonly flags: BuildtimeFlags;
|
|
94
|
+
readonly location: BuildtimeLocation;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The compile-time API. Inside a `@buildtime` declaration, calls
|
|
98
|
+
* against this object are routed to native implementations. At
|
|
99
|
+
* runtime, every access throws — see module docs for why.
|
|
100
|
+
*/
|
|
101
|
+
export declare const buildtime: Buildtime;
|
|
102
|
+
/**
|
|
103
|
+
* Re-export with the name `$buildtime` for users who prefer the macroforge
|
|
104
|
+
* convention of prefixing compile-time identifiers with `$`. Points at the
|
|
105
|
+
* same object.
|
|
106
|
+
*/
|
|
107
|
+
export declare const $buildtime: Buildtime;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// js/buildtime/index.ts
|
|
2
|
+
var runtimeError = (method) => new Error(
|
|
3
|
+
`macroforge/buildtime.${method}: @buildtime APIs are only available inside @buildtime declarations evaluated by macroforge. If you're seeing this at runtime, the macroforge plugin is not installed or not running on this file.`
|
|
4
|
+
);
|
|
5
|
+
var buildtime = {
|
|
6
|
+
fs: {
|
|
7
|
+
readText(_path) {
|
|
8
|
+
throw runtimeError("fs.readText");
|
|
9
|
+
},
|
|
10
|
+
readJson(_path) {
|
|
11
|
+
throw runtimeError("fs.readJson");
|
|
12
|
+
},
|
|
13
|
+
exists(_path) {
|
|
14
|
+
throw runtimeError("fs.exists");
|
|
15
|
+
},
|
|
16
|
+
listDir(_path) {
|
|
17
|
+
throw runtimeError("fs.listDir");
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
crypto: {
|
|
21
|
+
sha256(_input) {
|
|
22
|
+
throw runtimeError("crypto.sha256");
|
|
23
|
+
},
|
|
24
|
+
sha512(_input) {
|
|
25
|
+
throw runtimeError("crypto.sha512");
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
time: {
|
|
29
|
+
now() {
|
|
30
|
+
throw runtimeError("time.now");
|
|
31
|
+
},
|
|
32
|
+
unix() {
|
|
33
|
+
throw runtimeError("time.unix");
|
|
34
|
+
},
|
|
35
|
+
iso() {
|
|
36
|
+
throw runtimeError("time.iso");
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
env: new Proxy(
|
|
40
|
+
{},
|
|
41
|
+
{
|
|
42
|
+
get(_target, _prop) {
|
|
43
|
+
throw runtimeError("env");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
),
|
|
47
|
+
flags: {
|
|
48
|
+
has(_flag) {
|
|
49
|
+
throw runtimeError("flags.has");
|
|
50
|
+
},
|
|
51
|
+
get(_flag) {
|
|
52
|
+
throw runtimeError("flags.get");
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
location: new Proxy({}, {
|
|
56
|
+
get(_target, _prop) {
|
|
57
|
+
throw runtimeError("location");
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
var $buildtime = buildtime;
|
|
62
|
+
export {
|
|
63
|
+
$buildtime,
|
|
64
|
+
buildtime
|
|
65
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Macroforge Buildtime Module
|
|
3
|
+
*
|
|
4
|
+
* Compile-time JavaScript evaluation — the Zig-comptime primitive for
|
|
5
|
+
* TypeScript. Annotate a top-level `const` or `function` declaration with
|
|
6
|
+
* `/** @buildtime *\/` and the macroforge build pass evaluates it in a
|
|
7
|
+
* sandboxed JS context, serializes the result, and splices a plain TS
|
|
8
|
+
* literal back into the module.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* /** @buildtime *\/
|
|
12
|
+
* const BUILT_AT = buildtime.time.iso();
|
|
13
|
+
*
|
|
14
|
+
* /** @buildtime *\/
|
|
15
|
+
* const SCHEMA = buildtime.fs.readJson("./schema.json");
|
|
16
|
+
*
|
|
17
|
+
* /** @buildtime *\/
|
|
18
|
+
* function generateValidators() {
|
|
19
|
+
* const schema = buildtime.fs.readJson("./schema.json");
|
|
20
|
+
* return schema.fields.map(f =>
|
|
21
|
+
* `export function is_${f.name}(v: unknown): v is ${f.type} {
|
|
22
|
+
* return typeof v === "${f.jsType}";
|
|
23
|
+
* }`
|
|
24
|
+
* ).join("\n");
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* ## Runtime behavior
|
|
29
|
+
*
|
|
30
|
+
* Every export from this module is a sentinel. Calling any of them at
|
|
31
|
+
* runtime throws — they should have been resolved by the macroforge
|
|
32
|
+
* build pass and no longer exist in the output. If you see the runtime
|
|
33
|
+
* error, the build pass is not running on this file.
|
|
34
|
+
*
|
|
35
|
+
* @module macroforge/buildtime
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
const runtimeError = (method: string) =>
|
|
39
|
+
new Error(
|
|
40
|
+
`macroforge/buildtime.${method}: @buildtime APIs are only available inside @buildtime declarations evaluated by macroforge. ` +
|
|
41
|
+
`If you're seeing this at runtime, the macroforge plugin is not installed or not running on this file.`,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export interface BuildtimeFs {
|
|
45
|
+
/** Read a file as UTF-8 text. Path is resolved relative to the file the
|
|
46
|
+
* @buildtime declaration lives in. Throws if the path is not in the
|
|
47
|
+
* `buildtime.capabilities.filesystem.read` allowlist. */
|
|
48
|
+
readText(path: string): string;
|
|
49
|
+
/** Read a file and parse its content as JSON. Same capability rules
|
|
50
|
+
* as `readText`. */
|
|
51
|
+
readJson(path: string): unknown;
|
|
52
|
+
/** Return whether the path exists on disk. Counts as a read for
|
|
53
|
+
* dependency tracking — if the file appears later, the cache
|
|
54
|
+
* invalidates. */
|
|
55
|
+
exists(path: string): boolean;
|
|
56
|
+
/** Return the names of the entries in a directory, sorted. Counts as
|
|
57
|
+
* a read. */
|
|
58
|
+
listDir(path: string): string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface BuildtimeCrypto {
|
|
62
|
+
/** SHA-256 of the input, lowercase hex. Pure — always allowed. */
|
|
63
|
+
sha256(input: string): string;
|
|
64
|
+
/** SHA-512 of the input, lowercase hex. Pure — always allowed. */
|
|
65
|
+
sha512(input: string): string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface BuildtimeTime {
|
|
69
|
+
/** Current wall-clock time as an ISO 8601 string. Makes builds
|
|
70
|
+
* non-deterministic — prefer recording a fixed timestamp if
|
|
71
|
+
* determinism matters. */
|
|
72
|
+
now(): string;
|
|
73
|
+
/** Current wall-clock time in unix seconds. */
|
|
74
|
+
unix(): number;
|
|
75
|
+
/** Alias for {@link BuildtimeTime.now}. */
|
|
76
|
+
iso(): string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface BuildtimeFlags {
|
|
80
|
+
/** True if the named flag was passed to the build (e.g. from a
|
|
81
|
+
* `--define` argument or from `config.buildtime.flags`). */
|
|
82
|
+
has(flag: string): boolean;
|
|
83
|
+
/** Value of the named flag, or undefined if not set. */
|
|
84
|
+
get(flag: string): string | undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface BuildtimeLocation {
|
|
88
|
+
/** Absolute path of the source file the @buildtime declaration
|
|
89
|
+
* lives in. */
|
|
90
|
+
readonly file: string;
|
|
91
|
+
/** 1-based line number of the `/** @buildtime *\/` annotation. */
|
|
92
|
+
readonly line: number;
|
|
93
|
+
/** 1-based column number of the annotation. */
|
|
94
|
+
readonly column: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface Buildtime {
|
|
98
|
+
readonly fs: BuildtimeFs;
|
|
99
|
+
readonly crypto: BuildtimeCrypto;
|
|
100
|
+
readonly time: BuildtimeTime;
|
|
101
|
+
/** Environment variables the build was allowed to read. Populated
|
|
102
|
+
* from `buildtime.capabilities.env` in macroforge.config.js. Reads
|
|
103
|
+
* of variables not in the allowlist return `undefined`. */
|
|
104
|
+
readonly env: Record<string, string | undefined>;
|
|
105
|
+
readonly flags: BuildtimeFlags;
|
|
106
|
+
readonly location: BuildtimeLocation;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The compile-time API. Inside a `@buildtime` declaration, calls
|
|
111
|
+
* against this object are routed to native implementations. At
|
|
112
|
+
* runtime, every access throws — see module docs for why.
|
|
113
|
+
*/
|
|
114
|
+
export const buildtime: Buildtime = {
|
|
115
|
+
fs: {
|
|
116
|
+
readText(_path: string): string {
|
|
117
|
+
throw runtimeError("fs.readText");
|
|
118
|
+
},
|
|
119
|
+
readJson(_path: string): unknown {
|
|
120
|
+
throw runtimeError("fs.readJson");
|
|
121
|
+
},
|
|
122
|
+
exists(_path: string): boolean {
|
|
123
|
+
throw runtimeError("fs.exists");
|
|
124
|
+
},
|
|
125
|
+
listDir(_path: string): string[] {
|
|
126
|
+
throw runtimeError("fs.listDir");
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
crypto: {
|
|
130
|
+
sha256(_input: string): string {
|
|
131
|
+
throw runtimeError("crypto.sha256");
|
|
132
|
+
},
|
|
133
|
+
sha512(_input: string): string {
|
|
134
|
+
throw runtimeError("crypto.sha512");
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
time: {
|
|
138
|
+
now(): string {
|
|
139
|
+
throw runtimeError("time.now");
|
|
140
|
+
},
|
|
141
|
+
unix(): number {
|
|
142
|
+
throw runtimeError("time.unix");
|
|
143
|
+
},
|
|
144
|
+
iso(): string {
|
|
145
|
+
throw runtimeError("time.iso");
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
env: new Proxy(
|
|
149
|
+
{},
|
|
150
|
+
{
|
|
151
|
+
get(_target, _prop): never {
|
|
152
|
+
throw runtimeError("env");
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
),
|
|
156
|
+
flags: {
|
|
157
|
+
has(_flag: string): boolean {
|
|
158
|
+
throw runtimeError("flags.has");
|
|
159
|
+
},
|
|
160
|
+
get(_flag: string): string | undefined {
|
|
161
|
+
throw runtimeError("flags.get");
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
location: new Proxy({} as BuildtimeLocation, {
|
|
165
|
+
get(_target, _prop): never {
|
|
166
|
+
throw runtimeError("location");
|
|
167
|
+
},
|
|
168
|
+
}),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Re-export with the name `$buildtime` for users who prefer the macroforge
|
|
173
|
+
* convention of prefixing compile-time identifiers with `$`. Points at the
|
|
174
|
+
* same object.
|
|
175
|
+
*/
|
|
176
|
+
export const $buildtime = buildtime;
|
|
@@ -115,12 +115,32 @@ if (typeRegistryPath) {
|
|
|
115
115
|
typeRegistryJson = fs.readFileSync(typeRegistryPath, "utf8");
|
|
116
116
|
} catch {}
|
|
117
117
|
}
|
|
118
|
+
const declarativeRegistryPath =
|
|
119
|
+
process.env.MACROFORGE_DECLARATIVE_REGISTRY_PATH;
|
|
120
|
+
let declarativeRegistryJson = void 0;
|
|
121
|
+
if (declarativeRegistryPath) {
|
|
122
|
+
try {
|
|
123
|
+
declarativeRegistryJson = fs.readFileSync(declarativeRegistryPath, "utf8");
|
|
124
|
+
} catch {}
|
|
125
|
+
}
|
|
118
126
|
const plugin = new macros.NativePlugin();
|
|
119
127
|
const expandOpts = {};
|
|
120
128
|
if (macroConfigPath) expandOpts.configPath = macroConfigPath;
|
|
121
129
|
if (typeRegistryJson) expandOpts.typeRegistryJson = typeRegistryJson;
|
|
130
|
+
if (declarativeRegistryJson) {
|
|
131
|
+
expandOpts.declarativeRegistryJson = declarativeRegistryJson;
|
|
132
|
+
}
|
|
122
133
|
const tsSys = ts.sys;
|
|
123
134
|
const origReadFile = tsSys.readFile.bind(tsSys);
|
|
135
|
+
// Text-level fast path matching the tsc wrapper — covers derive macros
|
|
136
|
+
// plus both sides of the declarative macro system (defining and consuming).
|
|
137
|
+
function hasMacroMarkers(sourceText) {
|
|
138
|
+
if (!sourceText) return false;
|
|
139
|
+
if (sourceText.includes("@derive")) return true;
|
|
140
|
+
if (sourceText.includes("macroforge/rules")) return true;
|
|
141
|
+
if (sourceText.includes("import macro")) return true;
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
124
144
|
tsSys.readFile = (filePath, encoding) => {
|
|
125
145
|
const content = origReadFile(filePath, encoding);
|
|
126
146
|
if (content == null) return content;
|
|
@@ -128,7 +148,7 @@ tsSys.readFile = (filePath, encoding) => {
|
|
|
128
148
|
if (
|
|
129
149
|
(filePath.endsWith(".ts") || filePath.endsWith(".tsx")) &&
|
|
130
150
|
!filePath.endsWith(".d.ts") &&
|
|
131
|
-
content
|
|
151
|
+
hasMacroMarkers(content)
|
|
132
152
|
) {
|
|
133
153
|
const result = plugin.processFile(filePath, content, expandOpts);
|
|
134
154
|
return result.code || content;
|
package/js/cli/tsc-wrapper.js
CHANGED
|
@@ -108,6 +108,14 @@ if (typeRegistryPath) {
|
|
|
108
108
|
typeRegistryJson = fs.readFileSync(typeRegistryPath, "utf8");
|
|
109
109
|
} catch {}
|
|
110
110
|
}
|
|
111
|
+
const declarativeRegistryPath =
|
|
112
|
+
process.env.MACROFORGE_DECLARATIVE_REGISTRY_PATH;
|
|
113
|
+
let declarativeRegistryJson = void 0;
|
|
114
|
+
if (declarativeRegistryPath) {
|
|
115
|
+
try {
|
|
116
|
+
declarativeRegistryJson = fs.readFileSync(declarativeRegistryPath, "utf8");
|
|
117
|
+
} catch {}
|
|
118
|
+
}
|
|
111
119
|
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
112
120
|
if (configFile.error) {
|
|
113
121
|
console.error(
|
|
@@ -134,8 +142,25 @@ const plugin = new macros.NativePlugin();
|
|
|
134
142
|
const tscExpandOpts = {};
|
|
135
143
|
if (macroConfigPath) tscExpandOpts.configPath = macroConfigPath;
|
|
136
144
|
if (typeRegistryJson) tscExpandOpts.typeRegistryJson = typeRegistryJson;
|
|
145
|
+
if (declarativeRegistryJson) {
|
|
146
|
+
tscExpandOpts.declarativeRegistryJson = declarativeRegistryJson;
|
|
147
|
+
}
|
|
137
148
|
const host = ts.createCompilerHost(options);
|
|
138
149
|
const origGetSourceFile = host.getSourceFile.bind(host);
|
|
150
|
+
// Text-level fast path: skip files that don't contain any macro markers.
|
|
151
|
+
// Matches:
|
|
152
|
+
// - `@derive` (derive macros)
|
|
153
|
+
// - `macroforge/rules` (declarative-macro-defining files that
|
|
154
|
+
// `import { macroRules } from "macroforge/rules"`)
|
|
155
|
+
// - `import macro` inside a JSDoc comment (declarative-macro-consuming
|
|
156
|
+
// files that use `/** import macro { $name } from "./file" */`)
|
|
157
|
+
function hasMacroMarkers(sourceText) {
|
|
158
|
+
if (!sourceText) return false;
|
|
159
|
+
if (sourceText.includes("@derive")) return true;
|
|
160
|
+
if (sourceText.includes("macroforge/rules")) return true;
|
|
161
|
+
if (sourceText.includes("import macro")) return true;
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
139
164
|
host.getSourceFile = (fileName, languageVersion, ...rest) => {
|
|
140
165
|
try {
|
|
141
166
|
if (
|
|
@@ -143,13 +168,20 @@ host.getSourceFile = (fileName, languageVersion, ...rest) => {
|
|
|
143
168
|
!fileName.endsWith(".d.ts")
|
|
144
169
|
) {
|
|
145
170
|
const sourceText = ts.sys.readFile(fileName);
|
|
146
|
-
if (sourceText
|
|
171
|
+
if (hasMacroMarkers(sourceText)) {
|
|
147
172
|
const result = plugin.processFile(fileName, sourceText, tscExpandOpts);
|
|
148
173
|
const text = result.code || sourceText;
|
|
149
174
|
return ts.createSourceFile(fileName, text, languageVersion, true);
|
|
150
175
|
}
|
|
151
176
|
}
|
|
152
|
-
} catch {
|
|
177
|
+
} catch (e) {
|
|
178
|
+
if (process.env.MACROFORGE_DEBUG_WRAPPER) {
|
|
179
|
+
console.error(
|
|
180
|
+
`[macroforge tsc wrapper] expand failed for ${fileName}:`,
|
|
181
|
+
e,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
153
185
|
return origGetSourceFile(fileName, languageVersion, ...rest);
|
|
154
186
|
};
|
|
155
187
|
const program = ts.createProgram(parsed.fileNames, options, host);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Macroforge Rules Module
|
|
3
|
+
*
|
|
4
|
+
* Declarative pattern-matching macros for TypeScript. Define macros with
|
|
5
|
+
* `` const $name = macroRules`...` ``, invoke them as `$name(args)`, and the
|
|
6
|
+
* macroforge build pass rewrites call sites at compile time.
|
|
7
|
+
*
|
|
8
|
+
* Example:
|
|
9
|
+
*
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { macroRules } from "macroforge/rules";
|
|
12
|
+
*
|
|
13
|
+
* const $vec = macroRules`
|
|
14
|
+
* () => []
|
|
15
|
+
*
|
|
16
|
+
* ($($x:Expr),+ $(,)?) => {
|
|
17
|
+
* const __v = [];
|
|
18
|
+
* $( __v.push($x); )+
|
|
19
|
+
* __v
|
|
20
|
+
* }
|
|
21
|
+
* `;
|
|
22
|
+
*
|
|
23
|
+
* const empty = $vec();
|
|
24
|
+
* const xs = $vec(1, 2, 3);
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* ## Runtime behavior
|
|
28
|
+
*
|
|
29
|
+
* `macroRules` is a sentinel tag function. It throws at runtime if the
|
|
30
|
+
* macroforge build pass is not installed — if you see the runtime error,
|
|
31
|
+
* your build toolchain is not running macroforge on this file.
|
|
32
|
+
*
|
|
33
|
+
* @module macroforge/rules
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* A macro invocation — a function that takes any arguments and may produce
|
|
37
|
+
* any value. The exact return type depends on the macro body; for accurate
|
|
38
|
+
* types, the macroforge build pass is responsible for erasing the macro
|
|
39
|
+
* definition and inlining the expansion at each call site. Only this
|
|
40
|
+
* placeholder shape is visible to the TypeScript type checker.
|
|
41
|
+
*/
|
|
42
|
+
export type MacroInvocation = (...args: any[]) => any;
|
|
43
|
+
/**
|
|
44
|
+
* The macro definition tag function.
|
|
45
|
+
*
|
|
46
|
+
* At build time, `` const $name = macroRules`...` `` is recognized by
|
|
47
|
+
* macroforge, the template body is parsed as a macro definition, and the
|
|
48
|
+
* declaration is erased from the output. Call sites of `$name(...)` are
|
|
49
|
+
* rewritten in place with the matching arm's body.
|
|
50
|
+
*
|
|
51
|
+
* The return type is a generic callable, so TypeScript lets users invoke
|
|
52
|
+
* `$name(...)` without complaint. At runtime (if the build pass did not
|
|
53
|
+
* run) the tag itself throws — any caller would already have seen the
|
|
54
|
+
* compile-time rewrite.
|
|
55
|
+
*/
|
|
56
|
+
export declare function macroRules(_strings: TemplateStringsArray, ..._values: unknown[]): MacroInvocation;
|
|
57
|
+
/**
|
|
58
|
+
* Configuration for a macro's reverse-monomorphization behavior.
|
|
59
|
+
*
|
|
60
|
+
* Currently a type-only declaration — the object form
|
|
61
|
+
* `macroRules({ expand, runtime, call, mode })` is part of the reverse-mono
|
|
62
|
+
* follow-up and is not yet wired through the build pass. The type is
|
|
63
|
+
* exported now so consumer code can start using the shape.
|
|
64
|
+
*/
|
|
65
|
+
export interface MacroConfig {
|
|
66
|
+
/**
|
|
67
|
+
* Controls how the macro emits in dev vs. prod builds.
|
|
68
|
+
*
|
|
69
|
+
* - `"auto"` (default): dev expands inline, prod shares runtime when safe.
|
|
70
|
+
* - `"expand-only"`: always expand inline at every call site.
|
|
71
|
+
* - `"share-only"`: always emit calls to a shared runtime helper.
|
|
72
|
+
* - `"share-anyway"`: share even past the megamorphism threshold.
|
|
73
|
+
*/
|
|
74
|
+
readonly mode?: "auto" | "expand-only" | "share-only" | "share-anyway";
|
|
75
|
+
/**
|
|
76
|
+
* The expand-form macro template (used for dev + `expand-only` + type-check).
|
|
77
|
+
*/
|
|
78
|
+
readonly expand?: unknown;
|
|
79
|
+
/**
|
|
80
|
+
* The shared runtime body, emitted once per module when the macro
|
|
81
|
+
* is in a sharing mode.
|
|
82
|
+
*/
|
|
83
|
+
readonly runtime?: string;
|
|
84
|
+
/**
|
|
85
|
+
* The call-form template that replaces call sites when the macro
|
|
86
|
+
* is in a sharing mode.
|
|
87
|
+
*/
|
|
88
|
+
readonly call?: unknown;
|
|
89
|
+
/**
|
|
90
|
+
* Above this count of distinct types calling the shared runtime,
|
|
91
|
+
* the megamorphism analyzer emits a warning. Default: 4.
|
|
92
|
+
*/
|
|
93
|
+
readonly megamorphismThreshold?: number;
|
|
94
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// js/rules/index.ts
|
|
2
|
+
function macroRules(_strings, ..._values) {
|
|
3
|
+
throw new Error(
|
|
4
|
+
"macroforge/rules: macros are compile-time only \u2014 they should have been erased by the macroforge build pass. If you're seeing this at runtime, the macroforge plugin is not installed or not running on this file."
|
|
5
|
+
);
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
macroRules
|
|
9
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Macroforge Rules Module
|
|
3
|
+
*
|
|
4
|
+
* Declarative pattern-matching macros for TypeScript. Define macros with
|
|
5
|
+
* `` const $name = macroRules`...` ``, invoke them as `$name(args)`, and the
|
|
6
|
+
* macroforge build pass rewrites call sites at compile time.
|
|
7
|
+
*
|
|
8
|
+
* Example:
|
|
9
|
+
*
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { macroRules } from "macroforge/rules";
|
|
12
|
+
*
|
|
13
|
+
* const $vec = macroRules`
|
|
14
|
+
* () => []
|
|
15
|
+
*
|
|
16
|
+
* ($($x:Expr),+ $(,)?) => {
|
|
17
|
+
* const __v = [];
|
|
18
|
+
* $( __v.push($x); )+
|
|
19
|
+
* __v
|
|
20
|
+
* }
|
|
21
|
+
* `;
|
|
22
|
+
*
|
|
23
|
+
* const empty = $vec();
|
|
24
|
+
* const xs = $vec(1, 2, 3);
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* ## Runtime behavior
|
|
28
|
+
*
|
|
29
|
+
* `macroRules` is a sentinel tag function. It throws at runtime if the
|
|
30
|
+
* macroforge build pass is not installed — if you see the runtime error,
|
|
31
|
+
* your build toolchain is not running macroforge on this file.
|
|
32
|
+
*
|
|
33
|
+
* @module macroforge/rules
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A macro invocation — a function that takes any arguments and may produce
|
|
38
|
+
* any value. The exact return type depends on the macro body; for accurate
|
|
39
|
+
* types, the macroforge build pass is responsible for erasing the macro
|
|
40
|
+
* definition and inlining the expansion at each call site. Only this
|
|
41
|
+
* placeholder shape is visible to the TypeScript type checker.
|
|
42
|
+
*/
|
|
43
|
+
export type MacroInvocation = (...args: any[]) => any;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The macro definition tag function.
|
|
47
|
+
*
|
|
48
|
+
* At build time, `` const $name = macroRules`...` `` is recognized by
|
|
49
|
+
* macroforge, the template body is parsed as a macro definition, and the
|
|
50
|
+
* declaration is erased from the output. Call sites of `$name(...)` are
|
|
51
|
+
* rewritten in place with the matching arm's body.
|
|
52
|
+
*
|
|
53
|
+
* The return type is a generic callable, so TypeScript lets users invoke
|
|
54
|
+
* `$name(...)` without complaint. At runtime (if the build pass did not
|
|
55
|
+
* run) the tag itself throws — any caller would already have seen the
|
|
56
|
+
* compile-time rewrite.
|
|
57
|
+
*/
|
|
58
|
+
export function macroRules(
|
|
59
|
+
_strings: TemplateStringsArray,
|
|
60
|
+
..._values: unknown[]
|
|
61
|
+
): MacroInvocation {
|
|
62
|
+
throw new Error(
|
|
63
|
+
"macroforge/rules: macros are compile-time only — they should have been erased by the macroforge build pass. " +
|
|
64
|
+
"If you're seeing this at runtime, the macroforge plugin is not installed or not running on this file.",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Configuration for a macro's reverse-monomorphization behavior.
|
|
70
|
+
*
|
|
71
|
+
* Currently a type-only declaration — the object form
|
|
72
|
+
* `macroRules({ expand, runtime, call, mode })` is part of the reverse-mono
|
|
73
|
+
* follow-up and is not yet wired through the build pass. The type is
|
|
74
|
+
* exported now so consumer code can start using the shape.
|
|
75
|
+
*/
|
|
76
|
+
export interface MacroConfig {
|
|
77
|
+
/**
|
|
78
|
+
* Controls how the macro emits in dev vs. prod builds.
|
|
79
|
+
*
|
|
80
|
+
* - `"auto"` (default): dev expands inline, prod shares runtime when safe.
|
|
81
|
+
* - `"expand-only"`: always expand inline at every call site.
|
|
82
|
+
* - `"share-only"`: always emit calls to a shared runtime helper.
|
|
83
|
+
* - `"share-anyway"`: share even past the megamorphism threshold.
|
|
84
|
+
*/
|
|
85
|
+
readonly mode?: "auto" | "expand-only" | "share-only" | "share-anyway";
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The expand-form macro template (used for dev + `expand-only` + type-check).
|
|
89
|
+
*/
|
|
90
|
+
readonly expand?: unknown;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The shared runtime body, emitted once per module when the macro
|
|
94
|
+
* is in a sharing mode.
|
|
95
|
+
*/
|
|
96
|
+
readonly runtime?: string;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The call-form template that replaces call sites when the macro
|
|
100
|
+
* is in a sharing mode.
|
|
101
|
+
*/
|
|
102
|
+
readonly call?: unknown;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Above this count of distinct types calling the shared runtime,
|
|
106
|
+
* the megamorphism analyzer emits a warning. Default: 4.
|
|
107
|
+
*/
|
|
108
|
+
readonly megamorphismThreshold?: number;
|
|
109
|
+
}
|
package/package.json
CHANGED
|
@@ -1,67 +1,79 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
},
|
|
6
|
-
"description": "TypeScript macro expansion engine powered by Rust, Oxc, and WebAssembly",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"types": "./pkg/macroforge_ts.d.ts",
|
|
10
|
-
"require": "./pkg/macroforge_ts.js",
|
|
11
|
-
"default": "./pkg/macroforge_ts.js"
|
|
2
|
+
"author": "macroforge contributors",
|
|
3
|
+
"bugs": {
|
|
4
|
+
"url": "https://github.com/macroforge-ts/macroforge-ts/issues"
|
|
12
5
|
},
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
"description": "TypeScript macro expansion engine powered by Rust, Oxc, and WebAssembly",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./pkg/macroforge_ts.js",
|
|
10
|
+
"types": "./pkg/macroforge_ts.d.ts",
|
|
11
|
+
"default": "./pkg/macroforge_ts.js"
|
|
12
|
+
},
|
|
13
|
+
"./buildtime": {
|
|
14
|
+
"import": "./js/buildtime/index.mjs",
|
|
15
|
+
"types": "./js/buildtime/index.d.ts",
|
|
16
|
+
"default": "./js/buildtime/index.mjs"
|
|
17
|
+
},
|
|
18
|
+
"./reexports": {
|
|
19
|
+
"import": "./js/reexports/index.mjs",
|
|
20
|
+
"types": "./js/reexports/index.d.ts",
|
|
21
|
+
"default": "./js/reexports/index.mjs"
|
|
22
|
+
},
|
|
23
|
+
"./reexports/effect": {
|
|
24
|
+
"import": "./js/reexports/effect.mjs",
|
|
25
|
+
"types": "./js/reexports/effect.d.ts",
|
|
26
|
+
"default": "./js/reexports/effect.mjs"
|
|
27
|
+
},
|
|
28
|
+
"./rules": {
|
|
29
|
+
"import": "./js/rules/index.mjs",
|
|
30
|
+
"types": "./js/rules/index.d.ts",
|
|
31
|
+
"default": "./js/rules/index.mjs"
|
|
32
|
+
},
|
|
33
|
+
"./serde": {
|
|
34
|
+
"import": "./js/serde/index.mjs",
|
|
35
|
+
"types": "./js/serde/index.d.ts",
|
|
36
|
+
"default": "./js/serde/index.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./traits": {
|
|
39
|
+
"import": "./js/traits/index.mjs",
|
|
40
|
+
"types": "./js/traits/index.d.ts",
|
|
41
|
+
"default": "./js/traits/index.mjs"
|
|
42
|
+
}
|
|
17
43
|
},
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
"files": [
|
|
45
|
+
"js",
|
|
46
|
+
"pkg"
|
|
47
|
+
],
|
|
48
|
+
"homepage": "https://github.com/macroforge-ts/macroforge-ts#readme",
|
|
49
|
+
"keywords": [
|
|
50
|
+
"typescript",
|
|
51
|
+
"macros",
|
|
52
|
+
"derive",
|
|
53
|
+
"codegen",
|
|
54
|
+
"oxc",
|
|
55
|
+
"wasm",
|
|
56
|
+
"webassembly"
|
|
57
|
+
],
|
|
58
|
+
"license": "MIT",
|
|
59
|
+
"main": "./pkg/macroforge_ts.js",
|
|
60
|
+
"name": "macroforge",
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "git+https://github.com/macroforge-ts/macroforge-ts.git"
|
|
22
64
|
},
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
65
|
+
"scripts": {
|
|
66
|
+
"build": "deno task build:wasm",
|
|
67
|
+
"build:buildtime": "deno run -A npm:esbuild js/buildtime/index.ts --bundle --outfile=js/buildtime/index.mjs --format=esm && deno run -A npm:typescript/tsc js/buildtime/index.ts --declaration --emitDeclarationOnly --outDir js/buildtime --lib ES2024 --skipLibCheck",
|
|
68
|
+
"build:js": "deno task build:serde && deno task build:traits && deno task build:rules && deno task build:buildtime",
|
|
69
|
+
"build:rules": "deno run -A npm:esbuild js/rules/index.ts --bundle --outfile=js/rules/index.mjs --format=esm && deno run -A npm:typescript/tsc js/rules/index.ts --declaration --emitDeclarationOnly --outDir js/rules --lib ES2024 --skipLibCheck",
|
|
70
|
+
"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",
|
|
71
|
+
"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",
|
|
72
|
+
"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",
|
|
73
|
+
"clean": "rm -rf pkg node_modules",
|
|
74
|
+
"cleanbuild": "deno task clean && deno task build"
|
|
27
75
|
},
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"default": "./js/traits/index.mjs"
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"files": [
|
|
35
|
-
"js",
|
|
36
|
-
"pkg"
|
|
37
|
-
],
|
|
38
|
-
"homepage": "https://github.com/macroforge-ts/macroforge-ts#readme",
|
|
39
|
-
"keywords": [
|
|
40
|
-
"typescript",
|
|
41
|
-
"macros",
|
|
42
|
-
"derive",
|
|
43
|
-
"codegen",
|
|
44
|
-
"oxc",
|
|
45
|
-
"wasm",
|
|
46
|
-
"webassembly"
|
|
47
|
-
],
|
|
48
|
-
"license": "MIT",
|
|
49
|
-
"main": "./pkg/macroforge_ts.js",
|
|
50
|
-
"name": "macroforge",
|
|
51
|
-
"repository": {
|
|
52
|
-
"type": "git",
|
|
53
|
-
"url": "git+https://github.com/macroforge-ts/macroforge-ts.git"
|
|
54
|
-
},
|
|
55
|
-
"scripts": {
|
|
56
|
-
"build": "deno task build:wasm",
|
|
57
|
-
"build:js": "deno task build:serde && deno task build:traits",
|
|
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",
|
|
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",
|
|
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",
|
|
62
|
-
"cleanbuild": "deno task clean && deno task build"
|
|
63
|
-
},
|
|
64
|
-
"type": "commonjs",
|
|
65
|
-
"types": "./pkg/macroforge_ts.d.ts",
|
|
66
|
-
"version": "0.1.79"
|
|
76
|
+
"type": "commonjs",
|
|
77
|
+
"types": "./pkg/macroforge_ts.d.ts",
|
|
78
|
+
"version": "0.1.80"
|
|
67
79
|
}
|
package/pkg/macroforge_ts.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
|
|
4
|
+
export function Clone(): void;
|
|
5
|
+
|
|
6
|
+
export function Debug(): void;
|
|
7
|
+
|
|
8
|
+
export function Default(): void;
|
|
9
|
+
|
|
4
10
|
export function Derive(): void;
|
|
5
11
|
|
|
12
|
+
export function Deserialize(): void;
|
|
13
|
+
|
|
14
|
+
export function Hash(): void;
|
|
15
|
+
|
|
6
16
|
export class NativeMapper {
|
|
7
17
|
private constructor();
|
|
8
18
|
free(): void;
|
|
@@ -36,6 +46,14 @@ export class NativePositionMapper {
|
|
|
36
46
|
constructor(_mapping: any);
|
|
37
47
|
}
|
|
38
48
|
|
|
49
|
+
export function Ord(): void;
|
|
50
|
+
|
|
51
|
+
export function PartialEq(): void;
|
|
52
|
+
|
|
53
|
+
export function PartialOrd(): void;
|
|
54
|
+
|
|
55
|
+
export function Serialize(): void;
|
|
56
|
+
|
|
39
57
|
export function __macroforgeDebugDescriptors(): any;
|
|
40
58
|
|
|
41
59
|
export function __macroforgeDebugGetModules(): any;
|
|
@@ -70,14 +88,31 @@ export function checkSyntax(code: string, filepath: string): any;
|
|
|
70
88
|
|
|
71
89
|
export function clearConfigCache(): void;
|
|
72
90
|
|
|
91
|
+
export function clearScanCache(): void;
|
|
92
|
+
|
|
73
93
|
export function expandSync(code: string, filepath: string, options: any): any;
|
|
74
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Phase 17 — scan cache invalidation. WASM cannot access the
|
|
97
|
+
* filesystem, so there is no scan cache to invalidate on that
|
|
98
|
+
* target. These shims are here so the JS side of the plugin can
|
|
99
|
+
* call them uniformly across NAPI and WASM backends.
|
|
100
|
+
*/
|
|
101
|
+
export function invalidateScanCacheEntry(path: string): boolean;
|
|
102
|
+
|
|
75
103
|
export function loadConfig(content: string, filepath: string): any;
|
|
76
104
|
|
|
77
105
|
export function parseImportSources(code: string, filepath: string): any;
|
|
78
106
|
|
|
79
107
|
export function scanProjectSync(root_dir: string, options: any): any;
|
|
80
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Register JS callbacks that bridge `buildtime.fs.*` to the host
|
|
111
|
+
* filesystem. Called once at startup by the Vite plugin (and any
|
|
112
|
+
* other JS host). Subsequent calls are ignored.
|
|
113
|
+
*/
|
|
114
|
+
export function setupBuildtimeFs(read_text: Function, exists: Function, list_dir: Function): void;
|
|
115
|
+
|
|
81
116
|
/**
|
|
82
117
|
* Register JS callbacks for resolving and running external (user-defined) macros.
|
|
83
118
|
*
|
package/pkg/macroforge_ts.js
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
/* @ts-self-types="./macroforge_ts.d.ts" */
|
|
2
2
|
|
|
3
|
+
function Clone() {
|
|
4
|
+
wasm.Clone();
|
|
5
|
+
}
|
|
6
|
+
exports.Clone = Clone;
|
|
7
|
+
|
|
8
|
+
function Debug() {
|
|
9
|
+
wasm.Debug();
|
|
10
|
+
}
|
|
11
|
+
exports.Debug = Debug;
|
|
12
|
+
|
|
13
|
+
function Default() {
|
|
14
|
+
wasm.Default();
|
|
15
|
+
}
|
|
16
|
+
exports.Default = Default;
|
|
17
|
+
|
|
3
18
|
function Derive() {
|
|
4
19
|
wasm.Derive();
|
|
5
20
|
}
|
|
6
21
|
exports.Derive = Derive;
|
|
7
22
|
|
|
23
|
+
function Deserialize() {
|
|
24
|
+
wasm.Deserialize();
|
|
25
|
+
}
|
|
26
|
+
exports.Deserialize = Deserialize;
|
|
27
|
+
|
|
28
|
+
function Hash() {
|
|
29
|
+
wasm.Hash();
|
|
30
|
+
}
|
|
31
|
+
exports.Hash = Hash;
|
|
32
|
+
|
|
8
33
|
class NativeMapper {
|
|
9
34
|
static __wrap(ptr) {
|
|
10
35
|
ptr = ptr >>> 0;
|
|
@@ -234,6 +259,26 @@ class NativePositionMapper {
|
|
|
234
259
|
if (Symbol.dispose) NativePositionMapper.prototype[Symbol.dispose] = NativePositionMapper.prototype.free;
|
|
235
260
|
exports.NativePositionMapper = NativePositionMapper;
|
|
236
261
|
|
|
262
|
+
function Ord() {
|
|
263
|
+
wasm.Ord();
|
|
264
|
+
}
|
|
265
|
+
exports.Ord = Ord;
|
|
266
|
+
|
|
267
|
+
function PartialEq() {
|
|
268
|
+
wasm.PartialEq();
|
|
269
|
+
}
|
|
270
|
+
exports.PartialEq = PartialEq;
|
|
271
|
+
|
|
272
|
+
function PartialOrd() {
|
|
273
|
+
wasm.PartialOrd();
|
|
274
|
+
}
|
|
275
|
+
exports.PartialOrd = PartialOrd;
|
|
276
|
+
|
|
277
|
+
function Serialize() {
|
|
278
|
+
wasm.Serialize();
|
|
279
|
+
}
|
|
280
|
+
exports.Serialize = Serialize;
|
|
281
|
+
|
|
237
282
|
/**
|
|
238
283
|
* @returns {any}
|
|
239
284
|
*/
|
|
@@ -571,6 +616,11 @@ function clearConfigCache() {
|
|
|
571
616
|
}
|
|
572
617
|
exports.clearConfigCache = clearConfigCache;
|
|
573
618
|
|
|
619
|
+
function clearScanCache() {
|
|
620
|
+
wasm.clearScanCache();
|
|
621
|
+
}
|
|
622
|
+
exports.clearScanCache = clearScanCache;
|
|
623
|
+
|
|
574
624
|
/**
|
|
575
625
|
* @param {string} code
|
|
576
626
|
* @param {string} filepath
|
|
@@ -590,6 +640,22 @@ function expandSync(code, filepath, options) {
|
|
|
590
640
|
}
|
|
591
641
|
exports.expandSync = expandSync;
|
|
592
642
|
|
|
643
|
+
/**
|
|
644
|
+
* Phase 17 — scan cache invalidation. WASM cannot access the
|
|
645
|
+
* filesystem, so there is no scan cache to invalidate on that
|
|
646
|
+
* target. These shims are here so the JS side of the plugin can
|
|
647
|
+
* call them uniformly across NAPI and WASM backends.
|
|
648
|
+
* @param {string} path
|
|
649
|
+
* @returns {boolean}
|
|
650
|
+
*/
|
|
651
|
+
function invalidateScanCacheEntry(path) {
|
|
652
|
+
const ptr0 = passStringToWasm0(path, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
|
|
653
|
+
const len0 = WASM_VECTOR_LEN;
|
|
654
|
+
const ret = wasm.invalidateScanCacheEntry(ptr0, len0);
|
|
655
|
+
return ret !== 0;
|
|
656
|
+
}
|
|
657
|
+
exports.invalidateScanCacheEntry = invalidateScanCacheEntry;
|
|
658
|
+
|
|
593
659
|
/**
|
|
594
660
|
* @param {string} content
|
|
595
661
|
* @param {string} filepath
|
|
@@ -642,6 +708,19 @@ function scanProjectSync(root_dir, options) {
|
|
|
642
708
|
}
|
|
643
709
|
exports.scanProjectSync = scanProjectSync;
|
|
644
710
|
|
|
711
|
+
/**
|
|
712
|
+
* Register JS callbacks that bridge `buildtime.fs.*` to the host
|
|
713
|
+
* filesystem. Called once at startup by the Vite plugin (and any
|
|
714
|
+
* other JS host). Subsequent calls are ignored.
|
|
715
|
+
* @param {Function} read_text
|
|
716
|
+
* @param {Function} exists
|
|
717
|
+
* @param {Function} list_dir
|
|
718
|
+
*/
|
|
719
|
+
function setupBuildtimeFs(read_text, exists, list_dir) {
|
|
720
|
+
wasm.setupBuildtimeFs(read_text, exists, list_dir);
|
|
721
|
+
}
|
|
722
|
+
exports.setupBuildtimeFs = setupBuildtimeFs;
|
|
723
|
+
|
|
645
724
|
/**
|
|
646
725
|
* Register JS callbacks for resolving and running external (user-defined) macros.
|
|
647
726
|
*
|
|
@@ -773,6 +852,13 @@ function __wbg_get_imports() {
|
|
|
773
852
|
const ret = Object.entries(arg0);
|
|
774
853
|
return ret;
|
|
775
854
|
},
|
|
855
|
+
__wbg_from_741da0f916ab74aa: function(arg0) {
|
|
856
|
+
const ret = Array.from(arg0);
|
|
857
|
+
return ret;
|
|
858
|
+
},
|
|
859
|
+
__wbg_getRandomValues_3f44b700395062e5: function() { return handleError(function (arg0, arg1) {
|
|
860
|
+
globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
|
|
861
|
+
}, arguments); },
|
|
776
862
|
__wbg_get_4848e350b40afc16: function(arg0, arg1) {
|
|
777
863
|
const ret = arg0[arg1 >>> 0];
|
|
778
864
|
return ret;
|
|
@@ -849,6 +935,18 @@ function __wbg_get_imports() {
|
|
|
849
935
|
const ret = arg0.next();
|
|
850
936
|
return ret;
|
|
851
937
|
}, arguments); },
|
|
938
|
+
__wbg_now_88621c9c9a4f3ffc: function() {
|
|
939
|
+
const ret = Date.now();
|
|
940
|
+
return ret;
|
|
941
|
+
},
|
|
942
|
+
__wbg_now_e7c6795a7f81e10f: function(arg0) {
|
|
943
|
+
const ret = arg0.now();
|
|
944
|
+
return ret;
|
|
945
|
+
},
|
|
946
|
+
__wbg_performance_3fcf6e32a7e1ed0a: function(arg0) {
|
|
947
|
+
const ret = arg0.performance;
|
|
948
|
+
return ret;
|
|
949
|
+
},
|
|
852
950
|
__wbg_prototypesetcall_3e05eb9545565046: function(arg0, arg1, arg2) {
|
|
853
951
|
Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
|
|
854
952
|
},
|
|
@@ -862,6 +960,22 @@ function __wbg_get_imports() {
|
|
|
862
960
|
const ret = Reflect.set(arg0, arg1, arg2);
|
|
863
961
|
return ret;
|
|
864
962
|
}, arguments); },
|
|
963
|
+
__wbg_static_accessor_GLOBAL_THIS_a1248013d790bf5f: function() {
|
|
964
|
+
const ret = typeof globalThis === 'undefined' ? null : globalThis;
|
|
965
|
+
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
|
966
|
+
},
|
|
967
|
+
__wbg_static_accessor_GLOBAL_f2e0f995a21329ff: function() {
|
|
968
|
+
const ret = typeof global === 'undefined' ? null : global;
|
|
969
|
+
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
|
970
|
+
},
|
|
971
|
+
__wbg_static_accessor_SELF_24f78b6d23f286ea: function() {
|
|
972
|
+
const ret = typeof self === 'undefined' ? null : self;
|
|
973
|
+
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
|
974
|
+
},
|
|
975
|
+
__wbg_static_accessor_WINDOW_59fd959c540fe405: function() {
|
|
976
|
+
const ret = typeof window === 'undefined' ? null : window;
|
|
977
|
+
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
|
978
|
+
},
|
|
865
979
|
__wbg_value_7f6052747ccf940f: function(arg0) {
|
|
866
980
|
const ret = arg0.value;
|
|
867
981
|
return ret;
|
|
Binary file
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const Default: () => void;
|
|
5
|
+
export const __macroforgeRunDefault: (a: number, b: number) => [number, number, number, number];
|
|
4
6
|
export const Derive: () => void;
|
|
5
7
|
export const __macroforgeDebugDescriptors: () => [number, number, number];
|
|
6
8
|
export const __macroforgeDebugGetModules: () => [number, number, number];
|
|
@@ -8,12 +10,12 @@ export const __macroforgeDebugLookup: (a: number, b: number, c: number, d: numbe
|
|
|
8
10
|
export const __macroforgeGetMacroNames: () => [number, number, number];
|
|
9
11
|
export const __macroforgeGetManifest: () => [number, number, number];
|
|
10
12
|
export const __macroforgeIsMacroPackage: () => number;
|
|
11
|
-
export const __macroforgeRunDeserialize: (a: number, b: number) => [number, number, number, number];
|
|
12
13
|
export const __wbg_nativemapper_free: (a: number, b: number) => void;
|
|
13
14
|
export const __wbg_nativeplugin_free: (a: number, b: number) => void;
|
|
14
15
|
export const __wbg_nativepositionmapper_free: (a: number, b: number) => void;
|
|
15
16
|
export const checkSyntax: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
16
17
|
export const expandSync: (a: number, b: number, c: number, d: number, e: any) => [number, number, number];
|
|
18
|
+
export const invalidateScanCacheEntry: (a: number, b: number) => number;
|
|
17
19
|
export const loadConfig: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
18
20
|
export const nativemapper_expandedToOriginal: (a: number, b: number) => number;
|
|
19
21
|
export const nativemapper_generatedBy: (a: number, b: number) => [number, number];
|
|
@@ -34,19 +36,29 @@ export const nativepositionmapper_new: (a: any) => number;
|
|
|
34
36
|
export const parseImportSources: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
35
37
|
export const scanProjectSync: (a: number, b: number, c: any) => [number, number, number];
|
|
36
38
|
export const transformSync: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
39
|
+
export const clearScanCache: () => void;
|
|
37
40
|
export const clearConfigCache: () => void;
|
|
38
41
|
export const nativepositionmapper_mapToOriginal: (a: number, b: number, c: number) => any;
|
|
39
|
-
export const
|
|
40
|
-
export const __macroforgeRunOrd: (a: number, b: number) => [number, number, number, number];
|
|
41
|
-
export const setupExternalMacros: (a: any, b: any) => void;
|
|
42
|
-
export const __macroforgeRunPartialEq: (a: number, b: number) => [number, number, number, number];
|
|
42
|
+
export const PartialOrd: () => void;
|
|
43
43
|
export const __macroforgeRunPartialOrd: (a: number, b: number) => [number, number, number, number];
|
|
44
|
+
export const Deserialize: () => void;
|
|
45
|
+
export const __macroforgeRunDeserialize: (a: number, b: number) => [number, number, number, number];
|
|
44
46
|
export const __macroforgeRunSerialize: (a: number, b: number) => [number, number, number, number];
|
|
45
|
-
export const __macroforgeRunDebug: (a: number, b: number) => [number, number, number, number];
|
|
46
|
-
export const __macroforgeRunDefault: (a: number, b: number) => [number, number, number, number];
|
|
47
|
-
export const __macroforgeRunHash: (a: number, b: number) => [number, number, number, number];
|
|
48
47
|
export const __macroforge_ffi_free: (a: number, b: number) => void;
|
|
49
48
|
export const __macroforge_ffi_get_manifest: (a: number, b: number) => number;
|
|
49
|
+
export const Serialize: () => void;
|
|
50
|
+
export const Hash: () => void;
|
|
51
|
+
export const __macroforgeRunHash: (a: number, b: number) => [number, number, number, number];
|
|
52
|
+
export const Debug: () => void;
|
|
53
|
+
export const __macroforgeRunDebug: (a: number, b: number) => [number, number, number, number];
|
|
54
|
+
export const __macroforgeRunOrd: (a: number, b: number) => [number, number, number, number];
|
|
55
|
+
export const setupBuildtimeFs: (a: any, b: any, c: any) => void;
|
|
56
|
+
export const setupExternalMacros: (a: any, b: any) => void;
|
|
57
|
+
export const Ord: () => void;
|
|
58
|
+
export const Clone: () => void;
|
|
59
|
+
export const __macroforgeRunClone: (a: number, b: number) => [number, number, number, number];
|
|
60
|
+
export const __macroforgeRunPartialEq: (a: number, b: number) => [number, number, number, number];
|
|
61
|
+
export const PartialEq: () => void;
|
|
50
62
|
export const __wbindgen_malloc_command_export: (a: number, b: number) => number;
|
|
51
63
|
export const __wbindgen_realloc_command_export: (a: number, b: number, c: number, d: number) => number;
|
|
52
64
|
export const __wbindgen_exn_store_command_export: (a: number) => void;
|