@macroforge/svelte-preprocessor 0.1.80 → 0.1.84
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 +6 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -43
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -16,13 +16,13 @@ npm install @macroforge/svelte-preprocessor
|
|
|
16
16
|
|
|
17
17
|
### Functions
|
|
18
18
|
|
|
19
|
-
- **`macroforgePreprocess`** - Creates a Svelte preprocessor that expands
|
|
20
|
-
|
|
19
|
+
- **`macroforgePreprocess`** - Creates a Svelte preprocessor that expands Macroforge macros in
|
|
20
|
+
`<script>` blocks.
|
|
21
21
|
|
|
22
22
|
### Interfaces
|
|
23
23
|
|
|
24
|
-
- **`MacroforgePreprocessorOptions`** - Configuration options for the Macroforge
|
|
25
|
-
|
|
24
|
+
- **`MacroforgePreprocessorOptions`** - Configuration options for the Macroforge Svelte
|
|
25
|
+
preprocessor.
|
|
26
26
|
|
|
27
27
|
### Constants
|
|
28
28
|
|
|
@@ -31,8 +31,8 @@ npm install @macroforge/svelte-preprocessor
|
|
|
31
31
|
## Documentation
|
|
32
32
|
|
|
33
33
|
See the
|
|
34
|
-
[full documentation](https://macroforge.dev/docs/api/reference/typescript/svelte-preprocessor)
|
|
35
|
-
|
|
34
|
+
[full documentation](https://macroforge.dev/docs/api/reference/typescript/svelte-preprocessor) on
|
|
35
|
+
the Macroforge website.
|
|
36
36
|
|
|
37
37
|
## License
|
|
38
38
|
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*
|
|
26
26
|
* @packageDocumentation
|
|
27
27
|
*/
|
|
28
|
-
import type { PreprocessorGroup } from
|
|
28
|
+
import type { PreprocessorGroup } from 'svelte/compiler';
|
|
29
29
|
/**
|
|
30
30
|
* Configuration options for the Macroforge Svelte preprocessor.
|
|
31
31
|
*
|
|
@@ -92,15 +92,18 @@ export interface MacroforgePreprocessorOptions {
|
|
|
92
92
|
* The preprocessor performs these steps for each script block:
|
|
93
93
|
*
|
|
94
94
|
* 1. **Language Check** - Verifies the script is TypeScript (or JavaScript if enabled)
|
|
95
|
-
* 2. **
|
|
96
|
-
* 3. **
|
|
97
|
-
* 4. **
|
|
98
|
-
*
|
|
95
|
+
* 2. **Expansion** - Calls the native engine to expand macros
|
|
96
|
+
* 3. **Diagnostics** - Logs any errors or warnings from expansion
|
|
97
|
+
* 4. **Return** - Returns transformed code or `undefined` if unchanged
|
|
98
|
+
*
|
|
99
|
+
* Every matching script block is passed to the engine; there is no
|
|
100
|
+
* pre-scan for `@derive`, so unchanged blocks simply come back identical.
|
|
99
101
|
*
|
|
100
102
|
* ## Error Handling
|
|
101
103
|
*
|
|
102
104
|
* The preprocessor is designed to be resilient:
|
|
103
|
-
* - If native bindings fail to load, it
|
|
105
|
+
* - If native bindings fail to load, it logs a warning, skips the block, and
|
|
106
|
+
* retries the import on the next block (so a warning is emitted per attempt)
|
|
104
107
|
* - If macro expansion throws, it logs a warning and continues
|
|
105
108
|
* - Svelte compilation proceeds even if preprocessing fails
|
|
106
109
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AA+OvE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,6BAA6B;IAC1C;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,wBAAgB,oBAAoB,CAChC,OAAO,GAAE,6BAAkC,GAC5C,iBAAiB,CA+InB;AAED;;;;;;;GAOG;AACH,eAAe,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
// ============================================================================
|
|
29
29
|
// Source Map Generation
|
|
30
30
|
// ============================================================================
|
|
31
|
-
const VLQ_CHARS =
|
|
31
|
+
const VLQ_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
32
32
|
function vlqEncode(value) {
|
|
33
33
|
let vlq = value < 0 ? (-value << 1) | 1 : value << 1;
|
|
34
|
-
let encoded =
|
|
34
|
+
let encoded = '';
|
|
35
35
|
do {
|
|
36
36
|
let digit = vlq & 0x1f;
|
|
37
37
|
vlq >>>= 5;
|
|
@@ -45,7 +45,7 @@ function vlqEncode(value) {
|
|
|
45
45
|
function buildLineOffsets(text) {
|
|
46
46
|
const offsets = [0];
|
|
47
47
|
for (let i = 0; i < text.length; i++) {
|
|
48
|
-
if (text[i] ===
|
|
48
|
+
if (text[i] === '\n')
|
|
49
49
|
offsets.push(i + 1);
|
|
50
50
|
}
|
|
51
51
|
return offsets;
|
|
@@ -79,7 +79,7 @@ function buildSourceMap(original, expanded, mapping, filename) {
|
|
|
79
79
|
lineSegments.get(exp.line).push({
|
|
80
80
|
expCol: exp.column,
|
|
81
81
|
origLine: orig.line,
|
|
82
|
-
origCol: orig.column
|
|
82
|
+
origCol: orig.column
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
// Encode VLQ mappings
|
|
@@ -89,7 +89,7 @@ function buildSourceMap(original, expanded, mapping, filename) {
|
|
|
89
89
|
for (let line = 0; line < totalLines; line++) {
|
|
90
90
|
const segs = lineSegments.get(line);
|
|
91
91
|
if (!segs || segs.length === 0) {
|
|
92
|
-
mappingsArr.push(
|
|
92
|
+
mappingsArr.push('');
|
|
93
93
|
continue;
|
|
94
94
|
}
|
|
95
95
|
segs.sort((a, b) => a.expCol - b.expCol);
|
|
@@ -104,14 +104,14 @@ function buildSourceMap(original, expanded, mapping, filename) {
|
|
|
104
104
|
prevOrigLine = seg.origLine;
|
|
105
105
|
prevOrigCol = seg.origCol;
|
|
106
106
|
}
|
|
107
|
-
mappingsArr.push(parts.join(
|
|
107
|
+
mappingsArr.push(parts.join(','));
|
|
108
108
|
}
|
|
109
109
|
return {
|
|
110
110
|
version: 3,
|
|
111
111
|
sources: [filename],
|
|
112
112
|
sourcesContent: [original],
|
|
113
113
|
names: [],
|
|
114
|
-
mappings: mappingsArr.join(
|
|
114
|
+
mappings: mappingsArr.join(';')
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
@@ -120,7 +120,7 @@ function buildSourceMap(original, expanded, mapping, filename) {
|
|
|
120
120
|
* This variable implements a lazy-loading pattern:
|
|
121
121
|
* - Initially `null`, indicating the binding hasn't been loaded yet
|
|
122
122
|
* - Set to the actual function after first successful load
|
|
123
|
-
* - Remains `null` if loading fails
|
|
123
|
+
* - Remains `null` if loading fails, so the next call retries the import
|
|
124
124
|
*
|
|
125
125
|
* The lazy-loading approach avoids loading native bindings at module import time,
|
|
126
126
|
* which improves startup performance when the preprocessor is registered but no
|
|
@@ -136,17 +136,20 @@ let expandSync = null;
|
|
|
136
136
|
*
|
|
137
137
|
* 1. On first call, dynamically imports the `macroforge` package
|
|
138
138
|
* 2. Extracts and caches the `expandSync` function
|
|
139
|
-
* 3. On subsequent calls, returns the cached function
|
|
139
|
+
* 3. On subsequent calls after a successful load, returns the cached function
|
|
140
|
+
* immediately
|
|
140
141
|
*
|
|
141
142
|
* The function is async because dynamic imports return promises, even though
|
|
142
|
-
* the underlying `expandSync` function is synchronous.
|
|
143
|
-
*
|
|
143
|
+
* the underlying `expandSync` function is synchronous. After a successful
|
|
144
|
+
* initialization, the cached sync function is used directly.
|
|
144
145
|
*
|
|
145
146
|
* ## Error Handling
|
|
146
147
|
*
|
|
147
148
|
* If the native bindings fail to load (e.g., missing native module, architecture
|
|
148
|
-
* mismatch), the function logs a warning and returns `null`.
|
|
149
|
-
*
|
|
149
|
+
* mismatch), the function logs a warning and returns `null`. Because failure
|
|
150
|
+
* leaves the cache `null`, the import (and the warning) is retried on every
|
|
151
|
+
* subsequent call. This allows the preprocessor to skip macro expansion rather
|
|
152
|
+
* than crashing the build.
|
|
150
153
|
*
|
|
151
154
|
* @returns The cached `expandSync` function, or `null` if loading failed
|
|
152
155
|
* @internal
|
|
@@ -155,12 +158,12 @@ async function ensureExpandSync() {
|
|
|
155
158
|
if (expandSync === null) {
|
|
156
159
|
try {
|
|
157
160
|
// Dynamic import defers loading until first use
|
|
158
|
-
const macroforge = await import(
|
|
161
|
+
const macroforge = await import('macroforge');
|
|
159
162
|
expandSync = macroforge.expandSync;
|
|
160
163
|
}
|
|
161
164
|
catch (error) {
|
|
162
165
|
// Log warning but don't throw - allows graceful degradation
|
|
163
|
-
console.warn(
|
|
166
|
+
console.warn('[@macroforge/svelte-preprocessor] Failed to load macroforge native bindings:', error);
|
|
164
167
|
expandSync = null;
|
|
165
168
|
}
|
|
166
169
|
}
|
|
@@ -185,15 +188,18 @@ async function ensureExpandSync() {
|
|
|
185
188
|
* The preprocessor performs these steps for each script block:
|
|
186
189
|
*
|
|
187
190
|
* 1. **Language Check** - Verifies the script is TypeScript (or JavaScript if enabled)
|
|
188
|
-
* 2. **
|
|
189
|
-
* 3. **
|
|
190
|
-
* 4. **
|
|
191
|
-
*
|
|
191
|
+
* 2. **Expansion** - Calls the native engine to expand macros
|
|
192
|
+
* 3. **Diagnostics** - Logs any errors or warnings from expansion
|
|
193
|
+
* 4. **Return** - Returns transformed code or `undefined` if unchanged
|
|
194
|
+
*
|
|
195
|
+
* Every matching script block is passed to the engine; there is no
|
|
196
|
+
* pre-scan for `@derive`, so unchanged blocks simply come back identical.
|
|
192
197
|
*
|
|
193
198
|
* ## Error Handling
|
|
194
199
|
*
|
|
195
200
|
* The preprocessor is designed to be resilient:
|
|
196
|
-
* - If native bindings fail to load, it
|
|
201
|
+
* - If native bindings fail to load, it logs a warning, skips the block, and
|
|
202
|
+
* retries the import on the next block (so a warning is emitted per attempt)
|
|
197
203
|
* - If macro expansion throws, it logs a warning and continues
|
|
198
204
|
* - Svelte compilation proceeds even if preprocessing fails
|
|
199
205
|
*
|
|
@@ -242,9 +248,9 @@ export function macroforgePreprocess(options = {}) {
|
|
|
242
248
|
*
|
|
243
249
|
* @returns An object with `code` property if transformed, or `undefined` if no changes
|
|
244
250
|
*/
|
|
245
|
-
const scriptPreprocessor = async ({ content, filename, attributes
|
|
246
|
-
if (filename?.includes(
|
|
247
|
-
console.log(`[PREPROC DEBUG] file=${filename}, lang=${attributes.lang}, type=${attributes.type}, has @derive=${content.includes(
|
|
251
|
+
const scriptPreprocessor = async ({ content, filename, attributes }) => {
|
|
252
|
+
if (filename?.includes('macroforge.svelte')) {
|
|
253
|
+
console.log(`[PREPROC DEBUG] file=${filename}, lang=${attributes.lang}, type=${attributes.type}, has @derive=${content.includes('@derive')}, has serviceDeserialize=${content.includes('function serviceDeserialize')}`);
|
|
248
254
|
}
|
|
249
255
|
/*
|
|
250
256
|
* STEP 1: Language Detection
|
|
@@ -260,18 +266,15 @@ export function macroforgePreprocess(options = {}) {
|
|
|
260
266
|
* - <script type="module"> → isJavaScript = true
|
|
261
267
|
*/
|
|
262
268
|
const lang = attributes.lang || attributes.type;
|
|
263
|
-
const isTypeScript = lang ===
|
|
264
|
-
const isJavaScript = !lang || lang ===
|
|
265
|
-
lang ===
|
|
269
|
+
const isTypeScript = lang === 'ts' || lang === 'typescript';
|
|
270
|
+
const isJavaScript = !lang || lang === 'js' || lang === 'javascript' ||
|
|
271
|
+
lang === 'module';
|
|
266
272
|
// Skip non-TypeScript blocks unless processJavaScript is enabled
|
|
267
273
|
if (!isTypeScript && !(processJavaScript && isJavaScript)) {
|
|
268
274
|
return; // Return undefined = no changes, Svelte keeps original content
|
|
269
275
|
}
|
|
270
276
|
/*
|
|
271
|
-
* STEP 2:
|
|
272
|
-
*
|
|
273
|
-
/*
|
|
274
|
-
* STEP 3: Load Native Bindings
|
|
277
|
+
* STEP 2: Load Native Bindings
|
|
275
278
|
*
|
|
276
279
|
* The expansion engine is a native module (Rust compiled to Node addon).
|
|
277
280
|
* We lazy-load it on first use to avoid startup overhead.
|
|
@@ -279,36 +282,37 @@ export function macroforgePreprocess(options = {}) {
|
|
|
279
282
|
const expand = await ensureExpandSync();
|
|
280
283
|
if (!expand) {
|
|
281
284
|
// Native bindings unavailable (missing module, architecture mismatch, etc.)
|
|
282
|
-
//
|
|
285
|
+
// ensureExpandSync already logged a warning; skip this block. The import
|
|
286
|
+
// is retried on the next block, so the warning repeats per attempt.
|
|
283
287
|
return;
|
|
284
288
|
}
|
|
285
289
|
try {
|
|
286
290
|
/*
|
|
287
|
-
* STEP
|
|
291
|
+
* STEP 3: Macro Expansion
|
|
288
292
|
*
|
|
289
293
|
* Call the native engine to parse the TypeScript, find @derive decorators,
|
|
290
294
|
* and generate the expanded code with all macro-derived methods/properties.
|
|
291
295
|
*/
|
|
292
|
-
const result = expand(content, filename ||
|
|
293
|
-
keepDecorators
|
|
296
|
+
const result = expand(content, filename || 'component.svelte', {
|
|
297
|
+
keepDecorators
|
|
294
298
|
});
|
|
295
299
|
/*
|
|
296
|
-
* STEP
|
|
300
|
+
* STEP 4: Diagnostic Reporting
|
|
297
301
|
*
|
|
298
302
|
* The expansion engine may report errors (invalid macro syntax, unknown macros)
|
|
299
303
|
* or warnings (deprecated patterns, suggestions). Log these to help developers
|
|
300
304
|
* debug issues without failing the build.
|
|
301
305
|
*/
|
|
302
306
|
for (const diag of result.diagnostics) {
|
|
303
|
-
if (diag.level ===
|
|
307
|
+
if (diag.level === 'error') {
|
|
304
308
|
console.error(`[@macroforge/svelte-preprocessor] Error in ${filename}: ${diag.message}`);
|
|
305
309
|
}
|
|
306
|
-
else if (diag.level ===
|
|
310
|
+
else if (diag.level === 'warning') {
|
|
307
311
|
console.warn(`[@macroforge/svelte-preprocessor] Warning in ${filename}: ${diag.message}`);
|
|
308
312
|
}
|
|
309
313
|
}
|
|
310
314
|
/*
|
|
311
|
-
* STEP
|
|
315
|
+
* STEP 5: Return Transformed Code
|
|
312
316
|
*
|
|
313
317
|
* Only return a result if the code was actually modified. Returning undefined
|
|
314
318
|
* tells Svelte to keep the original content, which is more efficient than
|
|
@@ -316,11 +320,10 @@ export function macroforgePreprocess(options = {}) {
|
|
|
316
320
|
*
|
|
317
321
|
* The return object can include:
|
|
318
322
|
* - code: The transformed source code (required)
|
|
319
|
-
* - map:
|
|
323
|
+
* - map: v3 source map built from the engine's segment mapping (when available)
|
|
320
324
|
*/
|
|
321
325
|
if (result.code && result.code !== content) {
|
|
322
|
-
const mapping = result
|
|
323
|
-
.sourceMapping;
|
|
326
|
+
const mapping = result.sourceMapping;
|
|
324
327
|
const map = mapping?.segments?.length && filename
|
|
325
328
|
? buildSourceMap(content, result.code, mapping, filename)
|
|
326
329
|
: undefined;
|
|
@@ -351,8 +354,8 @@ export function macroforgePreprocess(options = {}) {
|
|
|
351
354
|
* Note: We only handle script blocks, not markup or style blocks.
|
|
352
355
|
*/
|
|
353
356
|
return {
|
|
354
|
-
name:
|
|
355
|
-
script: scriptPreprocessor
|
|
357
|
+
name: 'macroforge',
|
|
358
|
+
script: scriptPreprocessor
|
|
356
359
|
};
|
|
357
360
|
}
|
|
358
361
|
/**
|
package/package.json
CHANGED
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"build": "deno install --node-modules-dir --quiet && deno run -A npm:typescript@5/tsc -p tsconfig.json",
|
|
41
41
|
"clean": "rm -rf dist",
|
|
42
42
|
"cleanbuild": "deno task clean && deno task build",
|
|
43
|
-
"test": "deno
|
|
43
|
+
"test": "deno test --allow-read --allow-env --allow-write --unstable-detect-cjs tests/"
|
|
44
44
|
},
|
|
45
45
|
"type": "module",
|
|
46
46
|
"types": "dist/index.d.ts",
|
|
47
|
-
"version": "0.1.
|
|
47
|
+
"version": "0.1.84"
|
|
48
48
|
}
|