juxscript 1.0.72 → 1.0.74
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 +87 -3
- package/package.json +1 -1
package/machinery/compiler.js
CHANGED
|
@@ -367,7 +367,19 @@ function transformJuxToViewFunction(juxContent, functionName, pageName, relative
|
|
|
367
367
|
}
|
|
368
368
|
result = result.replace(/\.renderTo\(container\)/g, '.render("#app")').replace(/\.render\(\s*\)/g, '.render("#app")');
|
|
369
369
|
const cleanName = functionName.replace(/[-_]/g, ' ').split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join('');
|
|
370
|
-
|
|
370
|
+
|
|
371
|
+
// ✅ Wrap View implementation in underscore function, then export Wrapped version
|
|
372
|
+
return `
|
|
373
|
+
// View: ${cleanName}
|
|
374
|
+
function _${cleanName}() {
|
|
375
|
+
${result}
|
|
376
|
+
|
|
377
|
+
return document.getElementById('app');
|
|
378
|
+
}
|
|
379
|
+
const ${cleanName} = JuxError.wrap('${cleanName}', _${cleanName});
|
|
380
|
+
// Register Source
|
|
381
|
+
JuxError.register('${cleanName}', '${relativePath}');
|
|
382
|
+
`;
|
|
371
383
|
}
|
|
372
384
|
|
|
373
385
|
function resolveImportPath(importPath, currentFilePath) {
|
|
@@ -428,13 +440,85 @@ function generateRouterBundle(views, routes, sharedModules = new Map(), allImpor
|
|
|
428
440
|
else if (parts.length > 0) filteredImports.push(`import ${parts.join(', ')} from '${source}';`);
|
|
429
441
|
});
|
|
430
442
|
|
|
443
|
+
const juxDebugUtils = `
|
|
444
|
+
// ============================================
|
|
445
|
+
// JUX DEBUG UTILITIES
|
|
446
|
+
// ============================================
|
|
447
|
+
const JUX_DEBUG = true;
|
|
448
|
+
|
|
449
|
+
const JuxError = {
|
|
450
|
+
sourceMap: {},
|
|
451
|
+
|
|
452
|
+
register(viewName, sourceFile) {
|
|
453
|
+
this.sourceMap[viewName] = sourceFile;
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
// Global Error Handler Setup
|
|
457
|
+
init() {
|
|
458
|
+
window.addEventListener('error', (event) => {
|
|
459
|
+
JuxError.displayError('Uncaught Exception', event.error);
|
|
460
|
+
});
|
|
461
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
462
|
+
JuxError.displayError('Unhandled Promise Rejection', event.reason);
|
|
463
|
+
});
|
|
464
|
+
},
|
|
465
|
+
|
|
466
|
+
displayError(title, error) {
|
|
467
|
+
console.error(\`🚨 JUX \${title}\`, error);
|
|
468
|
+
const app = document.getElementById('app');
|
|
469
|
+
if (app) {
|
|
470
|
+
// Prevent multiple error overlays stacking
|
|
471
|
+
if (document.getElementById('jux-error-overlay')) return;
|
|
472
|
+
|
|
473
|
+
app.innerHTML = \`
|
|
474
|
+
<div id="jux-error-overlay" style="font-family: monospace; background: #1e1e1e; color: #ff6b6b; min-height: 100vh; padding: 2rem; position:fixed; top:0; left:0; width:100%; z-index:99999;">
|
|
475
|
+
<div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 2rem;">
|
|
476
|
+
<div style="font-size: 2rem;">🚨</div>
|
|
477
|
+
<div>
|
|
478
|
+
<h1 style="margin:0; font-size: 1.5rem; color: #ff6b6b;">JUX Runtime Error</h1>
|
|
479
|
+
<div style="color: #888; margin-top: 4px;">\${title}</div>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
|
|
483
|
+
<pre style="background: #2d2d2d; padding: 20px; border-radius: 8px; overflow-x: auto; color: #e0e0e0; border-left: 4px solid #ff6b6b; font-size: 14px; line-height: 1.5;">\${error?.stack || error?.message || String(error)}</pre>
|
|
484
|
+
|
|
485
|
+
<button onclick="window.location.reload()" style="margin-top:20px; padding: 10px 20px; background: #333; color: white; border: 1px solid #555; cursor: pointer; border-radius: 4px;">Reload Application</button>
|
|
486
|
+
</div>
|
|
487
|
+
\`;
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
|
|
491
|
+
wrap(viewName, viewFn) {
|
|
492
|
+
return function() {
|
|
493
|
+
const sourceFile = JuxError.sourceMap[viewName] || 'unknown';
|
|
494
|
+
if (JUX_DEBUG) console.log(\`🚀 [JUX] Rendering: \${viewName} (\${sourceFile})\`);
|
|
495
|
+
|
|
496
|
+
try {
|
|
497
|
+
return viewFn.apply(this, arguments);
|
|
498
|
+
} catch (error) {
|
|
499
|
+
// Enhance error object with view context if possible
|
|
500
|
+
error.message = \`[View: \${viewName}] \${error.message}\`;
|
|
501
|
+
JuxError.displayError('View Rendering Error', error);
|
|
502
|
+
// We do NOT rethrow here to prevent console noise, as we handled it UI-wise.
|
|
503
|
+
// However, stopping execution flow is implicitly handled by not returning valid DOM.
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// Initialize Global Handlers
|
|
510
|
+
JuxError.init();
|
|
511
|
+
`;
|
|
512
|
+
|
|
431
513
|
return `// Generated Jux Router Bundle
|
|
432
514
|
${filteredImports.join('\n')}
|
|
433
515
|
|
|
516
|
+
${juxDebugUtils}
|
|
517
|
+
|
|
434
518
|
// SHARED MODULES
|
|
435
519
|
${Array.from(sharedModules.values()).filter(c => c.trim()).join('\n\n')}
|
|
436
520
|
|
|
437
|
-
// VIEWS
|
|
521
|
+
// VIEWS (Wrapped in JuxError)
|
|
438
522
|
${views.filter(v => v.trim()).join('\n\n')}
|
|
439
523
|
|
|
440
524
|
function JuxNotFound() { jux.heading(1, { text: '404 - Page Not Found' }).render('#app'); return document.getElementById('app'); }
|
|
@@ -459,7 +543,7 @@ document.addEventListener('click', e => {
|
|
|
459
543
|
const a = e.target.closest('a');
|
|
460
544
|
if (!a || a.dataset.router === 'false' || new URL(a.href).origin !== location.origin) return;
|
|
461
545
|
e.preventDefault();
|
|
462
|
-
history.pushState({}, '',
|
|
546
|
+
history.pushState({}, '', a.href);
|
|
463
547
|
render();
|
|
464
548
|
});
|
|
465
549
|
window.addEventListener('popstate', render);
|