macroforge 0.1.32 → 0.1.34
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 +72 -339
- package/index.d.ts +955 -21
- package/index.js +52 -52
- package/js/serde/index.d.ts +242 -16
- package/js/serde/index.mjs +12 -4
- package/js/serde/index.ts +264 -21
- package/js/traits/index.d.ts +227 -2
- package/js/traits/index.ts +229 -11
- package/js/utils/index.d.ts +41 -0
- package/js/utils/index.ts +42 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,368 +1,101 @@
|
|
|
1
|
-
#
|
|
1
|
+
# macroforge_ts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TypeScript macro expansion engine - write compile-time macros in Rust
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://crates.io/crates/macroforge_ts)
|
|
6
|
+
[](https://docs.rs/macroforge_ts)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Installation
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install macroforge
|
|
15
|
-
```
|
|
8
|
+
This crate provides a TypeScript macro expansion engine that brings Rust-like derive macros
|
|
9
|
+
to TypeScript. It is designed to be used via NAPI bindings from Node.js, enabling compile-time
|
|
10
|
+
code generation for TypeScript projects.
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
- macOS (x64, arm64)
|
|
19
|
-
- Linux (x64, arm64)
|
|
20
|
-
- Windows (x64, arm64)
|
|
21
|
-
|
|
22
|
-
## Quick Start
|
|
23
|
-
|
|
24
|
-
### Using Built-in Macros
|
|
12
|
+
## Overview
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
Macroforge processes TypeScript source files containing `@derive` decorators and expands them
|
|
15
|
+
into concrete implementations. For example, a class decorated with `@derive(Debug, Clone)`
|
|
16
|
+
will have `toString()` and `clone()` methods automatically generated.
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
class User {
|
|
31
|
-
name: string;
|
|
32
|
-
age: number;
|
|
18
|
+
## Architecture
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
this.name = name;
|
|
36
|
-
this.age = age;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
20
|
+
The crate is organized into several key components:
|
|
39
21
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
22
|
+
- **NAPI Bindings** (`NativePlugin`, `expand_sync`, `transform_sync`): Entry points for Node.js
|
|
23
|
+
- **Position Mapping** (`NativePositionMapper`, `NativeMapper`): Bidirectional source mapping
|
|
24
|
+
for IDE integration
|
|
25
|
+
- **Macro Host** (`host` module): Core expansion engine with registry and dispatcher
|
|
26
|
+
- **Built-in Macros** (`builtin` module): Standard derive macros (Debug, Clone, Serialize, etc.)
|
|
45
27
|
|
|
46
|
-
|
|
28
|
+
## Performance Considerations
|
|
47
29
|
|
|
48
|
-
|
|
49
|
-
|
|
30
|
+
- Uses a 32MB thread stack to prevent stack overflow during deep SWC AST recursion
|
|
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
|
|
50
34
|
|
|
51
|
-
|
|
52
|
-
const result = expandSync(sourceCode, "file.ts", {
|
|
53
|
-
keepDecorators: false
|
|
54
|
-
});
|
|
35
|
+
## Usage from Node.js
|
|
55
36
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
console.log(result.metadata); // Macro IR metadata (JSON)
|
|
37
|
+
```javascript
|
|
38
|
+
const { NativePlugin, expand_sync } = require('macroforge-ts');
|
|
59
39
|
|
|
60
|
-
//
|
|
40
|
+
// Create a plugin instance with caching
|
|
61
41
|
const plugin = new NativePlugin();
|
|
62
|
-
const cached = plugin.processFile("file.ts", sourceCode, {
|
|
63
|
-
version: "1.0.0" // Cache key
|
|
64
|
-
});
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## API Reference
|
|
68
|
-
|
|
69
|
-
### Core Functions
|
|
70
|
-
|
|
71
|
-
#### `expandSync(code, filepath, options?)`
|
|
72
|
-
|
|
73
|
-
Expands macros in TypeScript code synchronously.
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
function expandSync(
|
|
77
|
-
code: string,
|
|
78
|
-
filepath: string,
|
|
79
|
-
options?: ExpandOptions
|
|
80
|
-
): ExpandResult;
|
|
81
|
-
|
|
82
|
-
interface ExpandOptions {
|
|
83
|
-
keepDecorators?: boolean; // Keep @derive decorators in output (default: false)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
interface ExpandResult {
|
|
87
|
-
code: string; // Transformed TypeScript
|
|
88
|
-
types?: string; // Generated .d.ts content
|
|
89
|
-
metadata?: string; // Macro IR as JSON
|
|
90
|
-
diagnostics: MacroDiagnostic[]; // Warnings and errors
|
|
91
|
-
sourceMapping?: SourceMappingResult; // Position mapping data
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
#### `transformSync(code, filepath)`
|
|
96
|
-
|
|
97
|
-
Lower-level transform that returns additional metadata.
|
|
98
42
|
|
|
99
|
-
|
|
100
|
-
|
|
43
|
+
// Process a file (uses cache if version matches)
|
|
44
|
+
const result = plugin.process_file(filepath, code, { version: '1.0' });
|
|
101
45
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
map?: string; // Source map (not yet implemented)
|
|
105
|
-
types?: string; // Generated declarations
|
|
106
|
-
metadata?: string;
|
|
107
|
-
}
|
|
46
|
+
// Or use the sync function directly
|
|
47
|
+
const result = expand_sync(code, filepath, { keep_decorators: false });
|
|
108
48
|
```
|
|
109
49
|
|
|
110
|
-
|
|
50
|
+
## Re-exports for Macro Authors
|
|
111
51
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
interface SyntaxCheckResult {
|
|
118
|
-
ok: boolean;
|
|
119
|
-
error?: string;
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
#### `parseImportSources(code, filepath)`
|
|
124
|
-
|
|
125
|
-
Extracts import information from TypeScript code.
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
function parseImportSources(code: string, filepath: string): ImportSourceResult[];
|
|
129
|
-
|
|
130
|
-
interface ImportSourceResult {
|
|
131
|
-
local: string; // Local identifier name
|
|
132
|
-
module: string; // Module specifier
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### Classes
|
|
137
|
-
|
|
138
|
-
#### `NativePlugin`
|
|
139
|
-
|
|
140
|
-
Stateful plugin with caching for language server integration.
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
class NativePlugin {
|
|
144
|
-
constructor();
|
|
145
|
-
|
|
146
|
-
// Process file with version-based caching
|
|
147
|
-
processFile(
|
|
148
|
-
filepath: string,
|
|
149
|
-
code: string,
|
|
150
|
-
options?: ProcessFileOptions
|
|
151
|
-
): ExpandResult;
|
|
152
|
-
|
|
153
|
-
// Get position mapper for a cached file
|
|
154
|
-
getMapper(filepath: string): NativeMapper | null;
|
|
155
|
-
|
|
156
|
-
// Map diagnostics from expanded to original positions
|
|
157
|
-
mapDiagnostics(filepath: string, diags: JsDiagnostic[]): JsDiagnostic[];
|
|
158
|
-
|
|
159
|
-
// Logging utilities
|
|
160
|
-
log(message: string): void;
|
|
161
|
-
setLogFile(path: string): void;
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
#### `NativeMapper` / `PositionMapper`
|
|
166
|
-
|
|
167
|
-
Maps positions between original and expanded code.
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
class NativeMapper {
|
|
171
|
-
constructor(mapping: SourceMappingResult);
|
|
172
|
-
|
|
173
|
-
isEmpty(): boolean;
|
|
174
|
-
originalToExpanded(pos: number): number;
|
|
175
|
-
expandedToOriginal(pos: number): number | null;
|
|
176
|
-
generatedBy(pos: number): string | null;
|
|
177
|
-
mapSpanToOriginal(start: number, length: number): SpanResult | null;
|
|
178
|
-
mapSpanToExpanded(start: number, length: number): SpanResult;
|
|
179
|
-
isInGenerated(pos: number): boolean;
|
|
180
|
-
}
|
|
181
|
-
```
|
|
52
|
+
This crate re-exports several dependencies for convenience when writing custom macros:
|
|
53
|
+
- `ts_syn`: TypeScript syntax types for AST manipulation
|
|
54
|
+
- `macros`: Macro attributes and quote templates
|
|
55
|
+
- `swc_core`, `swc_common`, `swc_ecma_ast`: SWC compiler infrastructure
|
|
182
56
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
| Decorator | Description |
|
|
186
|
-
|-----------|-------------|
|
|
187
|
-
| `@Derive(...features)` | Class decorator that triggers macro expansion |
|
|
188
|
-
| `@Debug` | Generates `toString(): string` method |
|
|
189
|
-
| `@Clone` | Generates `clone(): T` method |
|
|
190
|
-
| `@Eq` | Generates `equals(other: T): boolean` method |
|
|
191
|
-
|
|
192
|
-
## Writing Custom Macros
|
|
193
|
-
|
|
194
|
-
Custom macros are written in Rust and compiled to native Node.js addons. See the [playground/macro](../../playground/macro) directory for examples.
|
|
57
|
+
## Installation
|
|
195
58
|
|
|
196
|
-
|
|
59
|
+
Add this to your `Cargo.toml`:
|
|
197
60
|
|
|
198
|
-
**Cargo.toml:**
|
|
199
61
|
```toml
|
|
200
|
-
[package]
|
|
201
|
-
name = "my-macros"
|
|
202
|
-
version = "0.1.0"
|
|
203
|
-
edition = "2024"
|
|
204
|
-
|
|
205
|
-
[lib]
|
|
206
|
-
crate-type = ["cdylib"]
|
|
207
|
-
|
|
208
62
|
[dependencies]
|
|
209
|
-
macroforge_ts = "0.1.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
})
|
|
242
|
-
}
|
|
243
|
-
_ => Err(MacroforgeError::new(
|
|
244
|
-
input.decorator_span(),
|
|
245
|
-
"@derive(JSON) only works on classes",
|
|
246
|
-
)),
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### Template Syntax
|
|
252
|
-
|
|
253
|
-
The `ts_template!` and `body!` macros support:
|
|
254
|
-
|
|
255
|
-
| Syntax | Description |
|
|
256
|
-
|--------|-------------|
|
|
257
|
-
| `@{expr}` | Interpolate Rust expression as identifier/code |
|
|
258
|
-
| `{#for x in iter}...{/for}` | Loop over iterables |
|
|
259
|
-
| `{$let name = expr}` | Local variable binding |
|
|
260
|
-
| `{#if cond}...{/if}` | Conditional blocks |
|
|
261
|
-
|
|
262
|
-
### Re-exported Crates
|
|
263
|
-
|
|
264
|
-
`macroforge_ts` re-exports everything needed for macro development:
|
|
265
|
-
|
|
266
|
-
```rust
|
|
267
|
-
// TypeScript syntax types
|
|
268
|
-
use macroforge_ts::ts_syn::*;
|
|
269
|
-
|
|
270
|
-
// Macro attributes and quote templates
|
|
271
|
-
use macroforge_ts::macros::{ts_macro_derive, body, ts_template, above, below};
|
|
272
|
-
|
|
273
|
-
// SWC modules (for advanced use)
|
|
274
|
-
use macroforge_ts::swc_core;
|
|
275
|
-
use macroforge_ts::swc_common;
|
|
276
|
-
use macroforge_ts::swc_ecma_ast;
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
## Integration
|
|
63
|
+
macroforge_ts = "0.1.33"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Key Exports
|
|
67
|
+
|
|
68
|
+
### Structs
|
|
69
|
+
|
|
70
|
+
- **`TransformResult`** - Result of transforming TypeScript code through the macro system.
|
|
71
|
+
- **`MacroDiagnostic`** - A diagnostic message produced during macro expansion.
|
|
72
|
+
- **`MappingSegmentResult`** - A segment mapping a range in the original source to a range in the expanded source.
|
|
73
|
+
- **`GeneratedRegionResult`** - A region in the expanded source that was generated by a macro.
|
|
74
|
+
- **`SourceMappingResult`** - Complete source mapping information for a macro expansion.
|
|
75
|
+
- **`ExpandResult`** - Result of expanding macros in TypeScript source code.
|
|
76
|
+
- **`ImportSourceResult`** - Information about an imported identifier from a TypeScript module.
|
|
77
|
+
- **`SyntaxCheckResult`** - Result of checking TypeScript syntax validity.
|
|
78
|
+
- **`SpanResult`** - A span (range) in source code, represented as start position and length.
|
|
79
|
+
- **`JsDiagnostic`** - A diagnostic from the TypeScript/JavaScript compiler or IDE.
|
|
80
|
+
- ... and 8 more
|
|
81
|
+
|
|
82
|
+
### Functions
|
|
83
|
+
|
|
84
|
+
- **`unchanged`** - Creates a no-op result with the original code unchanged.
|
|
85
|
+
- **`new`** - Creates a new position mapper from source mapping data.
|
|
86
|
+
- **`is_empty`** - Checks if this mapper has no mapping data.
|
|
87
|
+
- **`original_to_expanded`** - Converts a position in the original source to the corresponding position in expanded source.
|
|
88
|
+
- **`expanded_to_original`** - Converts a position in the expanded source back to the original source position.
|
|
89
|
+
- **`generated_by`** - Returns the name of the macro that generated code at the given position.
|
|
90
|
+
- **`map_span_to_original`** - Maps a span (start + length) from expanded source to original source.
|
|
91
|
+
- **`map_span_to_expanded`** - Maps a span (start + length) from original source to expanded source.
|
|
92
|
+
- **`is_in_generated`** - Checks if a position is inside macro-generated code.
|
|
93
|
+
- **`new`** - Creates a new mapper wrapping the given source mapping.
|
|
94
|
+
- ... and 23 more
|
|
280
95
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
// vite.config.ts
|
|
285
|
-
import macroforge from "@macroforge/vite-plugin";
|
|
286
|
-
|
|
287
|
-
export default defineConfig({
|
|
288
|
-
plugins: [
|
|
289
|
-
macroforge({
|
|
290
|
-
typesOutputDir: ".macroforge/types",
|
|
291
|
-
metadataOutputDir: ".macroforge/meta",
|
|
292
|
-
generateTypes: true,
|
|
293
|
-
emitMetadata: true,
|
|
294
|
-
}),
|
|
295
|
-
],
|
|
296
|
-
});
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### TypeScript Plugin
|
|
300
|
-
|
|
301
|
-
Add to `tsconfig.json` for IDE support:
|
|
302
|
-
|
|
303
|
-
```json
|
|
304
|
-
{
|
|
305
|
-
"compilerOptions": {
|
|
306
|
-
"plugins": [
|
|
307
|
-
{
|
|
308
|
-
"name": "@macroforge/typescript-plugin"
|
|
309
|
-
}
|
|
310
|
-
]
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
## Debug API
|
|
316
|
-
|
|
317
|
-
For debugging macro registration:
|
|
318
|
-
|
|
319
|
-
```typescript
|
|
320
|
-
import {
|
|
321
|
-
__macroforgeGetManifest,
|
|
322
|
-
__macroforgeGetMacroNames,
|
|
323
|
-
__macroforgeIsMacroPackage,
|
|
324
|
-
__macroforgeDebugDescriptors,
|
|
325
|
-
__macroforgeDebugLookup,
|
|
326
|
-
} from "macroforge";
|
|
327
|
-
|
|
328
|
-
// Get all registered macros
|
|
329
|
-
const manifest = __macroforgeGetManifest();
|
|
330
|
-
console.log(manifest.macros);
|
|
331
|
-
|
|
332
|
-
// Check if current package exports macros
|
|
333
|
-
console.log(__macroforgeIsMacroPackage());
|
|
334
|
-
|
|
335
|
-
// List macro names
|
|
336
|
-
console.log(__macroforgeGetMacroNames());
|
|
337
|
-
|
|
338
|
-
// Debug lookup
|
|
339
|
-
console.log(__macroforgeDebugLookup("@my/macros", "JSON"));
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
## Architecture
|
|
343
|
-
|
|
344
|
-
```
|
|
345
|
-
┌─────────────────────────────────────────────────────────┐
|
|
346
|
-
│ Node.js / Vite │
|
|
347
|
-
├─────────────────────────────────────────────────────────┤
|
|
348
|
-
│ NAPI-RS Bindings │
|
|
349
|
-
├─────────────────────────────────────────────────────────┤
|
|
350
|
-
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
|
351
|
-
│ │ ts_syn │ │ ts_quote │ │ts_macro_derive│ │
|
|
352
|
-
│ │ (parsing) │ │ (templating) │ │ (proc-macro) │ │
|
|
353
|
-
│ └─────────────┘ └──────────────┘ └───────────────┘ │
|
|
354
|
-
├─────────────────────────────────────────────────────────┤
|
|
355
|
-
│ SWC Core │
|
|
356
|
-
│ (TypeScript parsing & codegen) │
|
|
357
|
-
└─────────────────────────────────────────────────────────┘
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
## Performance
|
|
96
|
+
## API Reference
|
|
361
97
|
|
|
362
|
-
|
|
363
|
-
- **Caching**: `NativePlugin` caches expansion results by file version
|
|
364
|
-
- **Binary search**: Position mapping uses O(log n) lookups
|
|
365
|
-
- **Zero-copy parsing**: SWC's arena allocator minimizes allocations
|
|
98
|
+
See the [full API documentation](https://macroforge.dev/docs/api/reference/rust/macroforge_ts) on the Macroforge website.
|
|
366
99
|
|
|
367
100
|
## License
|
|
368
101
|
|