juxscript 1.0.82 → 1.0.83
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/machinery/compiler.js +69 -37
- package/package.json +1 -1
package/machinery/compiler.js
CHANGED
|
@@ -301,44 +301,78 @@ export async function bundleJuxFilesToRouter(projectRoot, distDir, options = {})
|
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
function extractSharedModule(juxContent, moduleName, sourceFilePath) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const ast = acorn.parse(juxContent, { ecmaVersion: 'latest', sourceType: 'module' });
|
|
307
|
-
ast.body.forEach(node => {
|
|
308
|
-
if (node.type === 'ExportNamedDeclaration' && node.declaration) {
|
|
309
|
-
const exportCode = juxContent.slice(node.start, node.end).replace(/^export\s+/, '');
|
|
310
|
-
exportLines.push(`// From: ${sourceFilePath}\n${namespaceExportedIdentifiers(exportCode, sourceFilePath)}`);
|
|
311
|
-
} else if (node.type === 'ExportDefaultDeclaration') {
|
|
312
|
-
const exportCode = juxContent.slice(node.start, node.end).replace(/^export\s+default\s+/, '');
|
|
313
|
-
exportLines.push(`// From: ${sourceFilePath}\n${namespaceExportedIdentifiers(exportCode, sourceFilePath)}`);
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
} catch (err) {
|
|
317
|
-
throw new Error(`Invalid JavaScript syntax in ${sourceFilePath}.`);
|
|
318
|
-
}
|
|
319
|
-
return exportLines.join('\n\n');
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function namespaceExportedIdentifiers(code, sourceFilePath) {
|
|
323
|
-
// ✅ FIX: Strip .jux AND .js extensions for stable namespacing
|
|
304
|
+
// 1. Calculate Namespace
|
|
305
|
+
// Ensure we have a valid JS identifier suffix
|
|
324
306
|
const namespace = sourceFilePath.replace(/\.(jux|js)$/, '').replace(/[\/\\]/g, '$').replace(/[^a-zA-Z0-9$]/g, '_');
|
|
307
|
+
|
|
308
|
+
let ast;
|
|
325
309
|
try {
|
|
326
|
-
|
|
327
|
-
const identifiers = [];
|
|
328
|
-
ast.body.forEach(node => {
|
|
329
|
-
if (node.type === 'FunctionDeclaration' && node.id) identifiers.push(node.id);
|
|
330
|
-
else if (node.type === 'VariableDeclaration') node.declarations.forEach(d => { if (d.id.type === 'Identifier') identifiers.push(d.id); });
|
|
331
|
-
else if (node.type === 'ClassDeclaration' && node.id) identifiers.push(node.id);
|
|
332
|
-
});
|
|
333
|
-
identifiers.sort((a, b) => b.start - a.start);
|
|
334
|
-
let result = code;
|
|
335
|
-
identifiers.forEach(id => {
|
|
336
|
-
result = result.slice(0, id.start) + `${id.name}$${namespace}` + result.slice(id.end);
|
|
337
|
-
});
|
|
338
|
-
return result;
|
|
310
|
+
ast = acorn.parse(juxContent, { ecmaVersion: 'latest', sourceType: 'module' });
|
|
339
311
|
} catch (err) {
|
|
340
|
-
|
|
312
|
+
throw new Error(`Invalid JavaScript syntax in ${sourceFilePath}: ${err.message}`);
|
|
341
313
|
}
|
|
314
|
+
|
|
315
|
+
// 2. Identify ALL Top-Level Identifiers (Exported or Local) to rename
|
|
316
|
+
// We must rename everything to avoid global collision in the flat bundle
|
|
317
|
+
const identifiersToRename = new Map();
|
|
318
|
+
|
|
319
|
+
const addId = (idNode) => {
|
|
320
|
+
if (idNode && idNode.type === 'Identifier') {
|
|
321
|
+
identifiersToRename.set(idNode.name, `${idNode.name}$${namespace}`);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
ast.body.forEach(node => {
|
|
326
|
+
if (node.type === 'FunctionDeclaration' || node.type === 'ClassDeclaration') {
|
|
327
|
+
addId(node.id);
|
|
328
|
+
} else if (node.type === 'VariableDeclaration') {
|
|
329
|
+
node.declarations.forEach(d => addId(d.id));
|
|
330
|
+
} else if ((node.type === 'ExportNamedDeclaration' || node.type === 'ExportDefaultDeclaration') && node.declaration) {
|
|
331
|
+
const d = node.declaration;
|
|
332
|
+
if (d.type === 'FunctionDeclaration' || d.type === 'ClassDeclaration') addId(d.id);
|
|
333
|
+
else if (d.type === 'VariableDeclaration') d.declarations.forEach(v => addId(v.id));
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// 3. Reconstruct Code Line-by-Line (Node-by-Node)
|
|
338
|
+
const outputLines = [`// From: ${sourceFilePath}`];
|
|
339
|
+
|
|
340
|
+
// Sort keys by length desc to avoid partial replacement issues
|
|
341
|
+
const sortedKeys = Array.from(identifiersToRename.keys()).sort((a, b) => b.length - a.length);
|
|
342
|
+
|
|
343
|
+
ast.body.forEach(node => {
|
|
344
|
+
// Skip Imports (handled globally in bundling phase)
|
|
345
|
+
if (node.type === 'ImportDeclaration') return;
|
|
346
|
+
// Skip "export { a, b }" (re-exports) as 'a' and 'b' are already declared/renamed locally
|
|
347
|
+
if (node.type === 'ExportNamedDeclaration' && !node.declaration) return;
|
|
348
|
+
|
|
349
|
+
// Extract relevant code slice
|
|
350
|
+
let code = '';
|
|
351
|
+
if (node.type === 'ExportNamedDeclaration' || node.type === 'ExportDefaultDeclaration') {
|
|
352
|
+
if (node.declaration) {
|
|
353
|
+
code = juxContent.slice(node.declaration.start, node.declaration.end);
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
code = juxContent.slice(node.start, node.end);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (!code) return;
|
|
360
|
+
|
|
361
|
+
// Replace Identifiers in this block
|
|
362
|
+
// Regex:
|
|
363
|
+
// (?<!\.) -> Negative lookbehind to avoid property access (obj.foo)
|
|
364
|
+
// \bkey\b -> Word boundary
|
|
365
|
+
// (?!\s*:) -> Negative lookahead to avoid object keys ({ foo: 1 })
|
|
366
|
+
for (const key of sortedKeys) {
|
|
367
|
+
const namespaced = identifiersToRename.get(key);
|
|
368
|
+
const regex = new RegExp(`(?<!\\.)\\b${key}\\b(?!\\s*:)`, 'g');
|
|
369
|
+
code = code.replace(regex, namespaced);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
outputLines.push(code);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
return outputLines.join('\n\n');
|
|
342
376
|
}
|
|
343
377
|
|
|
344
378
|
function transformJuxToViewFunction(juxContent, functionName, pageName, relativePath, sharedModules, bundledPaths) {
|
|
@@ -367,9 +401,7 @@ function transformJuxToViewFunction(juxContent, functionName, pageName, relative
|
|
|
367
401
|
}
|
|
368
402
|
|
|
369
403
|
// 🔥 FIX: Always remove ImportDeclaration from the view function contents.
|
|
370
|
-
//
|
|
371
|
-
// Local/Bundled imports are hoisted via sharedModules mechanism with namespacing.
|
|
372
|
-
// Leaving import statements inside the function body causes SyntaxError.
|
|
404
|
+
// Leftover imports inside a function body cause SyntaxError.
|
|
373
405
|
nodesToRemove.push({ start: node.start, end: node.end });
|
|
374
406
|
}
|
|
375
407
|
if (node.type === 'ExportNamedDeclaration' || node.type === 'ExportDefaultDeclaration') {
|