juxscript 1.0.96 → 1.0.98

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.
@@ -215,16 +215,97 @@ export class JuxCompiler {
215
215
  }
216
216
 
217
217
  generateEntryPoint(views, dataModules, sharedModules) {
218
+ let entry = `// Auto-generated JUX entry point\n\n`;
218
219
  const allIssues = [];
219
220
  const sourceSnapshot = {};
220
221
 
221
- // ═══════════════════════════════════════════════════════════════
222
- // STEP 1: ERROR OVERLAY FIRST (before any imports!)
223
- // This ensures module-level errors are caught
224
- // ═══════════════════════════════════════════════════════════════
225
- let entry = `// Auto-generated JUX entry point
222
+ const juxImports = new Set();
223
+ [...views, ...dataModules, ...sharedModules].forEach(m => {
224
+ for (const match of m.content.matchAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*['"]juxscript['"]/g)) {
225
+ match[1].split(',').map(s => s.trim()).forEach(imp => {
226
+ if (imp) juxImports.add(imp);
227
+ });
228
+ }
229
+ });
230
+
231
+ if (juxImports.size > 0) {
232
+ entry += `import { ${[...juxImports].sort().join(', ')} } from 'juxscript';\n\n`;
233
+ }
234
+
235
+ dataModules.forEach(m => {
236
+ entry += `import * as ${this.sanitizeName(m.name)}Data from './jux/${m.file}';\n`;
237
+ });
238
+ sharedModules.forEach(m => {
239
+ entry += `import * as ${this.sanitizeName(m.name)}Shared from './jux/${m.file}';\n`;
240
+ });
241
+
242
+ entry += `\n// Expose to window\n`;
243
+ dataModules.forEach(m => entry += `Object.assign(window, ${this.sanitizeName(m.name)}Data);\n`);
244
+ sharedModules.forEach(m => entry += `Object.assign(window, ${this.sanitizeName(m.name)}Shared);\n`);
226
245
 
227
- // --- JUX SOURCE LOADER (must be first) ---
246
+ if (juxImports.size > 0) {
247
+ entry += `\nObject.assign(window, { ${[...juxImports].join(', ')} });\n`;
248
+ }
249
+
250
+ entry += `\n// --- VIEW FUNCTIONS ---\n`;
251
+
252
+ views.forEach(v => {
253
+ const capitalized = v.name.charAt(0).toUpperCase() + v.name.slice(1);
254
+ allIssues.push(...this.validateViewCode(v.name, v.content));
255
+
256
+ sourceSnapshot[v.file] = {
257
+ name: v.name,
258
+ file: v.file,
259
+ content: v.content,
260
+ lines: v.content.split('\n')
261
+ };
262
+
263
+ let viewCode = this.removeImports(v.content).replace(/^\s*export\s+default\s+.*$/gm, '');
264
+ const asyncPrefix = viewCode.includes('await ') ? 'async ' : '';
265
+
266
+ entry += `\n${asyncPrefix}function render${capitalized}() {\n${viewCode}\n}\n`;
267
+ });
268
+
269
+ dataModules.forEach(m => {
270
+ sourceSnapshot[m.file] = { name: m.name, file: m.file, content: m.content, lines: m.content.split('\n') };
271
+ });
272
+ sharedModules.forEach(m => {
273
+ sourceSnapshot[m.file] = { name: m.name, file: m.file, content: m.content, lines: m.content.split('\n') };
274
+ });
275
+
276
+ this._sourceSnapshot = sourceSnapshot;
277
+ this._validationIssues = allIssues;
278
+ entry += this._generateRouter(views);
279
+ return entry;
280
+ }
281
+
282
+ reportValidationIssues() {
283
+ const issues = this._validationIssues || [];
284
+ const errors = issues.filter(i => i.type === 'error');
285
+ const warnings = issues.filter(i => i.type === 'warning');
286
+
287
+ if (issues.length > 0) {
288
+ console.log('\n⚠️ Validation Issues:\n');
289
+ issues.forEach(issue => {
290
+ const icon = issue.type === 'error' ? '❌' : '⚠️';
291
+ console.log(`${icon} [${issue.view}:${issue.line}] ${issue.message}`);
292
+ });
293
+ console.log('');
294
+ }
295
+
296
+ return { isValid: errors.length === 0, errors, warnings };
297
+ }
298
+
299
+ _generateRouter(views) {
300
+ let routeMap = '';
301
+ views.forEach(v => {
302
+ const cap = v.name.charAt(0).toUpperCase() + v.name.slice(1);
303
+ if (v.name.toLowerCase() === 'index') routeMap += ` '/': render${cap},\n`;
304
+ routeMap += ` '/${v.name.toLowerCase()}': render${cap},\n`;
305
+ });
306
+
307
+ return `
308
+ // --- JUX SOURCE LOADER ---
228
309
  var __juxSources = null;
229
310
  async function __juxLoadSources() {
230
311
  if (__juxSources) return __juxSources;
@@ -237,6 +318,7 @@ async function __juxLoadSources() {
237
318
  return __juxSources;
238
319
  }
239
320
 
321
+ // Find source file from error stack
240
322
  function __juxFindSource(stack) {
241
323
  var match = stack.match(/render(\\w+)/);
242
324
  if (match) {
@@ -247,12 +329,6 @@ function __juxFindSource(stack) {
247
329
  }
248
330
  }
249
331
  }
250
- // Also check for module names in stack
251
- for (var file in __juxSources || {}) {
252
- if (stack.indexOf(file) > -1 || stack.indexOf(__juxSources[file].name) > -1) {
253
- return { file: file, source: __juxSources[file] };
254
- }
255
- }
256
332
  return null;
257
333
  }
258
334
 
@@ -416,6 +492,7 @@ var __juxErrorOverlay = {
416
492
 
417
493
  document.body.appendChild(overlay);
418
494
 
495
+ // Trigger transition
419
496
  requestAnimationFrame(function() {
420
497
  overlay.classList.add('visible');
421
498
  });
@@ -424,10 +501,7 @@ var __juxErrorOverlay = {
424
501
  }
425
502
  };
426
503
 
427
- // ═══════════════════════════════════════════════════════════════
428
- // INSTALL GLOBAL ERROR HANDLERS IMMEDIATELY (before imports!)
429
- // This catches errors during module loading
430
- // ═══════════════════════════════════════════════════════════════
504
+ // Global error handlers
431
505
  window.addEventListener('error', function(e) {
432
506
  __juxErrorOverlay.show(e.error || new Error(e.message), 'Uncaught Error');
433
507
  }, true);
@@ -436,109 +510,6 @@ window.addEventListener('unhandledrejection', function(e) {
436
510
  __juxErrorOverlay.show(e.reason || new Error('Promise rejected'), 'Unhandled Promise Rejection');
437
511
  }, true);
438
512
 
439
- // ═══════════════════════════════════════════════════════════════
440
- // NOW SAFE TO IMPORT MODULES
441
- // ═══════════════════════════════════════════════════════════════
442
-
443
- `;
444
-
445
- // ═══════════════════════════════════════════════════════════════
446
- // STEP 2: Collect and add imports
447
- // ═══════════════════════════════════════════════════════════════
448
- const juxImports = new Set();
449
- [...views, ...dataModules, ...sharedModules].forEach(m => {
450
- for (const match of m.content.matchAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*['"]juxscript['"]/g)) {
451
- match[1].split(',').map(s => s.trim()).forEach(imp => {
452
- if (imp) juxImports.add(imp);
453
- });
454
- }
455
- });
456
-
457
- if (juxImports.size > 0) {
458
- entry += `import { ${[...juxImports].sort().join(', ')} } from 'juxscript';\n\n`;
459
- }
460
-
461
- dataModules.forEach(m => {
462
- entry += `import * as ${this.sanitizeName(m.name)}Data from './jux/${m.file}';\n`;
463
- });
464
- sharedModules.forEach(m => {
465
- entry += `import * as ${this.sanitizeName(m.name)}Shared from './jux/${m.file}';\n`;
466
- });
467
-
468
- entry += `\n// Expose to window\n`;
469
- dataModules.forEach(m => entry += `Object.assign(window, ${this.sanitizeName(m.name)}Data);\n`);
470
- sharedModules.forEach(m => entry += `Object.assign(window, ${this.sanitizeName(m.name)}Shared);\n`);
471
-
472
- if (juxImports.size > 0) {
473
- entry += `\nObject.assign(window, { ${[...juxImports].join(', ')} });\n`;
474
- }
475
-
476
- // ═══════════════════════════════════════════════════════════════
477
- // STEP 3: View functions
478
- // ═══════════════════════════════════════════════════════════════
479
- entry += `\n// --- VIEW FUNCTIONS ---\n`;
480
-
481
- views.forEach(v => {
482
- const capitalized = v.name.charAt(0).toUpperCase() + v.name.slice(1);
483
- allIssues.push(...this.validateViewCode(v.name, v.content));
484
-
485
- sourceSnapshot[v.file] = {
486
- name: v.name,
487
- file: v.file,
488
- content: v.content,
489
- lines: v.content.split('\n')
490
- };
491
-
492
- let viewCode = this.removeImports(v.content).replace(/^\s*export\s+default\s+.*$/gm, '');
493
- const asyncPrefix = viewCode.includes('await ') ? 'async ' : '';
494
-
495
- entry += `\n${asyncPrefix}function render${capitalized}() {\n${viewCode}\n}\n`;
496
- });
497
-
498
- dataModules.forEach(m => {
499
- sourceSnapshot[m.file] = { name: m.name, file: m.file, content: m.content, lines: m.content.split('\n') };
500
- });
501
- sharedModules.forEach(m => {
502
- sourceSnapshot[m.file] = { name: m.name, file: m.file, content: m.content, lines: m.content.split('\n') };
503
- });
504
-
505
- this._sourceSnapshot = sourceSnapshot;
506
- this._validationIssues = allIssues;
507
-
508
- // ═══════════════════════════════════════════════════════════════
509
- // STEP 4: Router (no error overlay code - it's already at top)
510
- // ═══════════════════════════════════════════════════════════════
511
- entry += this._generateRouter(views);
512
- return entry;
513
- }
514
-
515
- reportValidationIssues() {
516
- const issues = this._validationIssues || [];
517
- const errors = issues.filter(i => i.type === 'error');
518
- const warnings = issues.filter(i => i.type === 'warning');
519
-
520
- if (issues.length > 0) {
521
- console.log('\n⚠️ Validation Issues:\n');
522
- issues.forEach(issue => {
523
- const icon = issue.type === 'error' ? '❌' : '⚠️';
524
- console.log(`${icon} [${issue.view}:${issue.line}] ${issue.message}`);
525
- });
526
- console.log('');
527
- }
528
-
529
- return { isValid: errors.length === 0, errors, warnings };
530
- }
531
-
532
- _generateRouter(views) {
533
- let routeMap = '';
534
- views.forEach(v => {
535
- const cap = v.name.charAt(0).toUpperCase() + v.name.slice(1);
536
- if (v.name.toLowerCase() === 'index') routeMap += ` '/': render${cap},\n`;
537
- routeMap += ` '/${v.name.toLowerCase()}': render${cap},\n`;
538
- });
539
-
540
- // Router ONLY - error handlers are now at the TOP of the bundle
541
- return `
542
513
  // --- JUX ROUTER ---
543
514
  const routes = {\n${routeMap}};
544
515
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.0.96",
3
+ "version": "1.0.98",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "./index.js",