juxscript 1.1.137 → 1.1.139

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "totalComponents": 69,
3
- "generatedAt": "2026-02-13T17:29:37.469Z",
3
+ "generatedAt": "2026-02-13T18:01:49.517Z",
4
4
  "components": [
5
5
  {
6
6
  "file": "alert.js",
@@ -18,6 +18,7 @@ export class JuxCompiler {
18
18
  this.paths = config.paths || {};
19
19
  this._juxscriptExports = null;
20
20
  this._juxscriptPath = null;
21
+ this._renderFunctionCounter = 0; // ✅ Add counter for unique IDs
21
22
  }
22
23
 
23
24
  /**
@@ -245,48 +246,46 @@ export class JuxCompiler {
245
246
 
246
247
  entry += `\n// --- VIEW FUNCTIONS ---\n`;
247
248
 
249
+ // ✅ Map to store route → function name mappings
250
+ const routeToFunctionMap = new Map();
251
+
248
252
  views.forEach(v => {
249
- // ✅ Sanitize the name for use in function names
250
- // Replace slashes, dots, and other invalid characters with underscores
251
- const sanitizedName = v.name
252
- .replace(/[\/\\.\\-\s]/g, '_') // Replace /, \, ., -, spaces with _
253
- .replace(/[^a-zA-Z0-9_]/g, '_') // Replace any other invalid chars with _
254
- .replace(/_+/g, '_') // Collapse multiple consecutive underscores
255
- .replace(/^_|_$/g, ''); // Remove leading/trailing underscores
256
-
257
- const capitalized = sanitizedName.charAt(0).toUpperCase() + sanitizedName.slice(1);
258
-
259
- // ✅ Check for duplicate function names and warn
260
- const functionName = `render${capitalized}`;
261
- if (sourceSnapshot[functionName]) {
262
- console.error(`❌ DUPLICATE FUNCTION NAME: ${functionName}`);
263
- console.error(` Conflict between:`);
264
- console.error(` 1. ${sourceSnapshot[functionName].file}`);
265
- console.error(` 2. ${v.file}`);
266
- console.error(` This will cause a build error. Rename one of these files.`);
267
- throw new Error(`Duplicate function name: ${functionName}`);
268
- }
253
+ // ✅ Generate TRULY UNIQUE serial ID
254
+ const serialId = this._renderFunctionCounter++;
255
+ const functionName = `renderJux${serialId}`;
269
256
 
270
257
  sourceSnapshot[v.file] = {
271
258
  name: v.name,
272
259
  file: v.file,
273
260
  content: v.content,
274
- lines: v.content.split('\n')
275
- };
276
-
277
- // ✅ Also track by function name to catch duplicates
278
- sourceSnapshot[functionName] = {
279
- name: v.name,
280
- file: v.file,
281
- content: v.content,
282
- lines: v.content.split('\n')
261
+ lines: v.content.split('\n'),
262
+ functionName // ✅ Store the unique function name
283
263
  };
284
264
 
285
265
  let viewCode = this.removeImports(v.content).replace(/^\s*export\s+default\s+.*$/gm, '');
286
266
  const asyncPrefix = viewCode.includes('await ') ? 'async ' : '';
287
267
 
288
- // Use sanitized name in function declaration
268
+ // Use truly unique serial function name
289
269
  entry += `\n${asyncPrefix}function ${functionName}() {\n${viewCode}\n}\n`;
270
+
271
+ // ✅ Generate URL-safe route path from original name
272
+ const routePath = v.name
273
+ .toLowerCase()
274
+ .replace(/\\/g, '/')
275
+ .replace(/\.jux$/i, '')
276
+ .replace(/\./g, '-')
277
+ .replace(/\s+/g, '-')
278
+ .replace(/[^a-z0-9\/_-]/g, '')
279
+ .replace(/-+/g, '-')
280
+ .replace(/^-|-$/g, '');
281
+
282
+ // ✅ Handle index route
283
+ if (routePath === 'index' || routePath === '') {
284
+ routeToFunctionMap.set('/', functionName);
285
+ }
286
+
287
+ // ✅ Map route to function
288
+ routeToFunctionMap.set(`/${routePath}`, functionName);
290
289
  });
291
290
 
292
291
  dataModules.forEach(m => {
@@ -298,7 +297,9 @@ export class JuxCompiler {
298
297
 
299
298
  this._sourceSnapshot = sourceSnapshot;
300
299
  this._validationIssues = allIssues;
301
- entry += this._generateRouter(views);
300
+
301
+ // ✅ Pass the route map to router generator
302
+ entry += this._generateRouter(routeToFunctionMap);
302
303
  return entry;
303
304
  }
304
305
 
@@ -319,39 +320,11 @@ export class JuxCompiler {
319
320
  return { isValid: errors.length === 0, errors, warnings };
320
321
  }
321
322
 
322
- _generateRouter(views) {
323
+ _generateRouter(routeToFunctionMap) {
324
+ // ✅ Build route map from Map object
323
325
  let routeMap = '';
324
- views.forEach(v => {
325
- // Sanitize function name (same as above)
326
- const sanitizedName = v.name
327
- .replace(/[\/\\.\\-\s]/g, '_')
328
- .replace(/[^a-zA-Z0-9_]/g, '_')
329
- .replace(/_+/g, '_')
330
- .replace(/^_|_$/g, '');
331
-
332
- const cap = sanitizedName.charAt(0).toUpperCase() + sanitizedName.slice(1);
333
-
334
- // ✅ Generate URL-safe route path from original name
335
- // Convert: 'menus/main' → '/menus/main'
336
- // Convert: 'about-us' → '/about-us'
337
- // Convert: 'blog.post' → '/blog-post' (dots become dashes for URLs)
338
- const routePath = v.name
339
- .toLowerCase()
340
- .replace(/\\/g, '/') // Normalize backslashes to forward slashes
341
- .replace(/\.jux$/i, '') // Remove .jux extension if present
342
- .replace(/\./g, '-') // Convert dots to dashes (blog.post → blog-post)
343
- .replace(/\s+/g, '-') // Convert spaces to dashes
344
- .replace(/[^a-z0-9\/_-]/g, '') // Remove any other unsafe URL chars
345
- .replace(/-+/g, '-') // Collapse multiple dashes
346
- .replace(/^-|-$/g, ''); // Remove leading/trailing dashes
347
-
348
- // ✅ Handle index route
349
- if (routePath === 'index' || routePath === '') {
350
- routeMap += ` '/': render${cap},\n`;
351
- }
352
-
353
- // ✅ Add regular route
354
- routeMap += ` '/${routePath}': render${cap},\n`;
326
+ routeToFunctionMap.forEach((functionName, route) => {
327
+ routeMap += ` '${route}': ${functionName},\n`;
355
328
  });
356
329
 
357
330
  return `
@@ -369,12 +342,12 @@ async function __juxLoadSources() {
369
342
  }
370
343
 
371
344
  function __juxFindSource(stack) {
372
- var match = stack.match(/render(\\w+)/);
345
+ var match = stack.match(/renderJux(\\d+)/);
373
346
  if (match) {
374
- var viewName = match[1].toLowerCase();
347
+ var functionName = 'renderJux' + match[1];
375
348
  for (var file in __juxSources || {}) {
376
- if (__juxSources[file].name.toLowerCase() === viewName) {
377
- return { file: file, source: __juxSources[file], viewName: match[1] };
349
+ if (__juxSources[file].functionName === functionName) {
350
+ return { file: file, source: __juxSources[file], functionName: functionName };
378
351
  }
379
352
  }
380
353
  }
@@ -537,12 +510,11 @@ document.addEventListener('click', (e) => {
537
510
  const juxDistDir = path.join(this.distDir, 'jux');
538
511
  fs.mkdirSync(juxDistDir, { recursive: true });
539
512
 
540
- // ✅ FIX: Create subdirectories and copy files
513
+ // ✅ Create subdirectories and copy files
541
514
  [...dataModules, ...sharedModules].forEach(m => {
542
515
  const destPath = path.join(juxDistDir, m.file);
543
516
  const destDir = path.dirname(destPath);
544
517
 
545
- // Create subdirectory if it doesn't exist
546
518
  if (!fs.existsSync(destDir)) {
547
519
  fs.mkdirSync(destDir, { recursive: true });
548
520
  }
@@ -574,15 +546,57 @@ document.addEventListener('click', (e) => {
574
546
  platform: 'browser',
575
547
  target: 'esnext',
576
548
  sourcemap: true,
577
- loader: { '.jux': 'js', '.css': 'empty' },
549
+
550
+ // ✅ FIX: Remove external packages restriction - bundle EVERYTHING
551
+ // This allows axios, lodash, date-fns, etc. to be bundled
552
+ // Remove the packages: 'external' or external: [...] config
553
+
554
+ loader: {
555
+ '.jux': 'js',
556
+ '.css': 'empty'
557
+ },
558
+
578
559
  plugins: [{
579
560
  name: 'juxscript-resolver',
580
561
  setup: (build) => {
581
- build.onResolve({ filter: /^juxscript$/ }, () => ({ path: juxscriptPath }));
562
+ // Only resolve juxscript - everything else gets bundled normally
563
+ build.onResolve({ filter: /^juxscript$/ }, () => ({
564
+ path: juxscriptPath
565
+ }));
582
566
  }
583
567
  }],
568
+
569
+ // ✅ NEW: Minify and tree-shake in production
570
+ minify: process.env.NODE_ENV === 'production',
571
+ treeShaking: true,
572
+
573
+ // ✅ NEW: Handle node built-ins (like 'http', 'fs') that axios might use
574
+ // These should NOT be bundled (they don't work in browser)
575
+ external: [
576
+ 'fs',
577
+ 'path',
578
+ 'http',
579
+ 'https',
580
+ 'stream',
581
+ 'zlib',
582
+ 'crypto'
583
+ ],
584
+
585
+ // ✅ NEW: Define globals for node built-ins
586
+ define: {
587
+ 'process.env.NODE_ENV': '"production"',
588
+ 'global': 'window'
589
+ }
584
590
  });
591
+
585
592
  console.log('✅ esbuild complete');
593
+
594
+ // ✅ Show bundle size
595
+ const bundlePath = path.join(this.distDir, 'bundle.js');
596
+ const bundleStats = fs.statSync(bundlePath);
597
+ const bundleSizeKB = (bundleStats.size / 1024).toFixed(2);
598
+ console.log(`📦 Bundle size: ${bundleSizeKB} KB`);
599
+
586
600
  } catch (err) {
587
601
  console.error('❌ esbuild failed:', err);
588
602
  return { success: false, errors: [{ message: err.message }], warnings: [] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.137",
3
+ "version": "1.1.139",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",