macroforge 0.1.33 → 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 CHANGED
@@ -1,368 +1,101 @@
1
- # macroforge
1
+ # macroforge_ts
2
2
 
3
- > **Warning:** This is a work in progress and probably won't work for you. Use at your own risk!
3
+ TypeScript macro expansion engine - write compile-time macros in Rust
4
4
 
5
- TypeScript macro expansion engine powered by Rust and SWC.
5
+ [![Crates.io](https://img.shields.io/crates/v/macroforge_ts.svg)](https://crates.io/crates/macroforge_ts)
6
+ [![Documentation](https://docs.rs/macroforge_ts/badge.svg)](https://docs.rs/macroforge_ts)
6
7
 
7
- ## Overview
8
-
9
- `macroforge` is a native Node.js module that enables compile-time code generation for TypeScript through a Rust-like derive macro system. It parses TypeScript using SWC, expands macros written in Rust, and outputs transformed TypeScript code with full source mapping support.
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
- The package includes pre-built binaries for:
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
- ```typescript
27
- import { Derive, Debug, Clone, Eq } from "macroforge";
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
- /** @derive(Debug, Clone, Eq) */
30
- class User {
31
- name: string;
32
- age: number;
18
+ ## Architecture
33
19
 
34
- constructor(name: string, age: number) {
35
- this.name = name;
36
- this.age = age;
37
- }
38
- }
20
+ The crate is organized into several key components:
39
21
 
40
- // After macro expansion, the class gains:
41
- // - toString(): string (from Debug)
42
- // - clone(): User (from Clone)
43
- // - equals(other: User): boolean (from Eq)
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
- ### Programmatic API
28
+ ## Performance Considerations
47
29
 
48
- ```typescript
49
- import { expandSync, NativePlugin } from "macroforge";
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
- // One-shot expansion
52
- const result = expandSync(sourceCode, "file.ts", {
53
- keepDecorators: false
54
- });
35
+ ## Usage from Node.js
55
36
 
56
- console.log(result.code); // Transformed TypeScript
57
- console.log(result.diagnostics); // Any warnings/errors
58
- console.log(result.metadata); // Macro IR metadata (JSON)
37
+ ```javascript
38
+ const { NativePlugin, expand_sync } = require('macroforge-ts');
59
39
 
60
- // Cached expansion (for language servers)
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
- ```typescript
100
- function transformSync(code: string, filepath: string): TransformResult;
43
+ // Process a file (uses cache if version matches)
44
+ const result = plugin.process_file(filepath, code, { version: '1.0' });
101
45
 
102
- interface TransformResult {
103
- code: string;
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
- #### `checkSyntax(code, filepath)`
50
+ ## Re-exports for Macro Authors
111
51
 
112
- Validates TypeScript syntax without macro expansion.
113
-
114
- ```typescript
115
- function checkSyntax(code: string, filepath: string): SyntaxCheckResult;
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
- ### Built-in Decorators
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
- ### Minimal Macro Crate
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.0"
210
- napi = { version = "3.5.2", features = ["napi8", "compat-mode"] }
211
- napi-derive = "3.3.3"
212
-
213
- [build-dependencies]
214
- napi-build = "2.3.1"
215
- ```
216
-
217
- **src/lib.rs:**
218
- ```rust
219
- use macroforge_ts::macros::{ts_macro_derive, body};
220
- use macroforge_ts::ts_syn::{
221
- Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input,
222
- };
223
-
224
- #[ts_macro_derive(
225
- JSON,
226
- description = "Generates toJSON() returning a plain object"
227
- )]
228
- pub fn derive_json(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
229
- let input = parse_ts_macro_input!(input as DeriveInput);
230
-
231
- match &input.data {
232
- Data::Class(class) => {
233
- Ok(body! {
234
- toJSON(): Record<string, unknown> {
235
- return {
236
- {#for field in class.field_names()}
237
- @{field}: this.@{field},
238
- {/for}
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
- ### Vite Plugin
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
- - **Thread-safe expansion**: Each expansion runs in an isolated thread with a 32MB stack to handle deep AST recursion
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