juxscript 1.0.96 → 1.0.97

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`);
245
+
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
+ });
226
268
 
227
- // --- JUX SOURCE LOADER (must be first) ---
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;
@@ -247,9 +328,9 @@ function __juxFindSource(stack) {
247
328
  }
248
329
  }
249
330
  }
250
- // Also check for module names in stack
331
+ // Also try to find by filename in stack
251
332
  for (var file in __juxSources || {}) {
252
- if (stack.indexOf(file) > -1 || stack.indexOf(__juxSources[file].name) > -1) {
333
+ if (stack.indexOf(file) > -1) {
253
334
  return { file: file, source: __juxSources[file] };
254
335
  }
255
336
  }
@@ -416,6 +497,7 @@ var __juxErrorOverlay = {
416
497
 
417
498
  document.body.appendChild(overlay);
418
499
 
500
+ // Trigger transition
419
501
  requestAnimationFrame(function() {
420
502
  overlay.classList.add('visible');
421
503
  });
@@ -424,10 +506,7 @@ var __juxErrorOverlay = {
424
506
  }
425
507
  };
426
508
 
427
- // ═══════════════════════════════════════════════════════════════
428
- // INSTALL GLOBAL ERROR HANDLERS IMMEDIATELY (before imports!)
429
- // This catches errors during module loading
430
- // ═══════════════════════════════════════════════════════════════
509
+ // Install global error handlers IMMEDIATELY
431
510
  window.addEventListener('error', function(e) {
432
511
  __juxErrorOverlay.show(e.error || new Error(e.message), 'Uncaught Error');
433
512
  }, true);
@@ -435,16 +514,14 @@ window.addEventListener('error', function(e) {
435
514
  window.addEventListener('unhandledrejection', function(e) {
436
515
  __juxErrorOverlay.show(e.reason || new Error('Promise rejected'), 'Unhandled Promise Rejection');
437
516
  }, true);
517
+ `;
438
518
 
439
- // ═══════════════════════════════════════════════════════════════
440
- // NOW SAFE TO IMPORT MODULES
441
- // ═══════════════════════════════════════════════════════════════
519
+ // --- END ERROR HANDLER ---
442
520
 
443
- `;
444
521
 
445
- // ═══════════════════════════════════════════════════════════════
446
- // STEP 2: Collect and add imports
447
- // ═══════════════════════════════════════════════════════════════
522
+ const allIssues = [];
523
+ const sourceSnapshot = {};
524
+
448
525
  const juxImports = new Set();
449
526
  [...views, ...dataModules, ...sharedModules].forEach(m => {
450
527
  for (const match of m.content.matchAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*['"]juxscript['"]/g)) {
@@ -473,9 +550,6 @@ window.addEventListener('unhandledrejection', function(e) {
473
550
  entry += `\nObject.assign(window, { ${[...juxImports].join(', ')} });\n`;
474
551
  }
475
552
 
476
- // ═══════════════════════════════════════════════════════════════
477
- // STEP 3: View functions
478
- // ═══════════════════════════════════════════════════════════════
479
553
  entry += `\n// --- VIEW FUNCTIONS ---\n`;
480
554
 
481
555
  views.forEach(v => {
@@ -504,10 +578,6 @@ window.addEventListener('unhandledrejection', function(e) {
504
578
 
505
579
  this._sourceSnapshot = sourceSnapshot;
506
580
  this._validationIssues = allIssues;
507
-
508
- // ═══════════════════════════════════════════════════════════════
509
- // STEP 4: Router (no error overlay code - it's already at top)
510
- // ═══════════════════════════════════════════════════════════════
511
581
  entry += this._generateRouter(views);
512
582
  return entry;
513
583
  }
@@ -537,8 +607,9 @@ window.addEventListener('unhandledrejection', function(e) {
537
607
  routeMap += ` '/${v.name.toLowerCase()}': render${cap},\n`;
538
608
  });
539
609
 
540
- // Router ONLY - error handlers are now at the TOP of the bundle
610
+ // Router only - error handlers are now at the top of the bundle
541
611
  return `
612
+
542
613
  // --- JUX ROUTER ---
543
614
  const routes = {\n${routeMap}};
544
615
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.0.96",
3
+ "version": "1.0.97",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "./index.js",