juxscript 1.1.369 → 1.1.371

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.
Files changed (2) hide show
  1. package/bin/cli.js +111 -82
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -12,6 +12,117 @@ const PACKAGE_ROOT = path.resolve(__dirname, '..');
12
12
 
13
13
  const [, , command, ...args] = process.argv;
14
14
 
15
+ // ═══════════════════════════════════════════════════════════════
16
+ // UTILITIES (must be defined before commands that use them)
17
+ // ═══════════════════════════════════════════════════════════════
18
+ function copyDirRecursive(src, dest) {
19
+ if (!fs.existsSync(dest)) {
20
+ fs.mkdirSync(dest, { recursive: true });
21
+ }
22
+
23
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
24
+ if (entry.name.startsWith('.')) continue;
25
+
26
+ const srcPath = path.join(src, entry.name);
27
+ const destPath = path.join(dest, entry.name);
28
+
29
+ if (entry.isDirectory()) {
30
+ copyDirRecursive(srcPath, destPath);
31
+ } else {
32
+ fs.copyFileSync(srcPath, destPath);
33
+ }
34
+ }
35
+ }
36
+
37
+ function resolveProjectSrcDir() {
38
+ const projectRoot = process.cwd();
39
+ const configPath = path.join(projectRoot, 'juxconfig.js');
40
+
41
+ if (fs.existsSync(configPath)) {
42
+ try {
43
+ const configContent = fs.readFileSync(configPath, 'utf8');
44
+ const srcDirMatch = configContent.match(/srcDir\s*:\s*['"]([^'"]+)['"]/);
45
+ if (srcDirMatch) {
46
+ return path.resolve(projectRoot, srcDirMatch[1]);
47
+ }
48
+ } catch (_) { }
49
+ }
50
+
51
+ return path.resolve(projectRoot, 'jux');
52
+ }
53
+
54
+ function resolveDestFolderName(parentDir, baseName) {
55
+ const first = path.join(parentDir, baseName);
56
+ if (!fs.existsSync(first)) return baseName;
57
+
58
+ const juxName = baseName + '-jux';
59
+ const second = path.join(parentDir, juxName);
60
+ if (!fs.existsSync(second)) return juxName;
61
+
62
+ for (let i = 1; i <= 99; i++) {
63
+ const numbered = `${baseName}-${i}`;
64
+ if (!fs.existsSync(path.join(parentDir, numbered))) return numbered;
65
+ }
66
+
67
+ return `${baseName}-${Date.now()}`;
68
+ }
69
+
70
+ function promptPresetSelection(presets) {
71
+ return new Promise((resolve) => {
72
+ console.log('\n📦 Available component presets:\n');
73
+ presets.forEach((p, i) => {
74
+ const presetDir = path.join(PACKAGE_ROOT, 'presets', p);
75
+ const files = fs.readdirSync(presetDir).filter(f => !f.startsWith('.'));
76
+ console.log(` ${i + 1}) ${p} (${files.join(', ')})`);
77
+ });
78
+ console.log(` 0) Cancel\n`);
79
+
80
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
81
+ rl.question('Select a preset (number or name): ', (answer) => {
82
+ rl.close();
83
+ const trimmed = answer.trim();
84
+
85
+ const num = parseInt(trimmed, 10);
86
+ if (num === 0) return resolve(null);
87
+ if (num >= 1 && num <= presets.length) return resolve(presets[num - 1]);
88
+
89
+ if (presets.includes(trimmed)) return resolve(trimmed);
90
+
91
+ console.error(`❌ Invalid selection: "${trimmed}"`);
92
+ resolve(null);
93
+ });
94
+ });
95
+ }
96
+
97
+ function promptYesNo(question) {
98
+ return new Promise((resolve) => {
99
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
100
+ rl.question(`${question} (y/N): `, (answer) => {
101
+ rl.close();
102
+ resolve(answer.trim().toLowerCase() === 'y');
103
+ });
104
+ });
105
+ }
106
+
107
+ function showHelp() {
108
+ console.log(`
109
+ JUX CLI
110
+
111
+ Usage:
112
+ jux create <name> Create a new JUX project
113
+ jux init Initialize JUX in current directory
114
+ jux build Build for production
115
+ jux serve Start production server
116
+ jux serve --hot Start dev server with hot reload
117
+ jux comp [name] Add a component preset to your project
118
+ jux comp [name] -f Force overwrite (backs up existing files)
119
+
120
+ Options:
121
+ --help, -h Show this help message
122
+ --force, -f Overwrite existing files (creates .bak backups)
123
+ `);
124
+ }
125
+
15
126
  // ═══════════════════════════════════════════════════════════════
16
127
  // COMMAND: create <project-name>
17
128
  // Creates a new JUX project from the template
@@ -256,47 +367,6 @@ function runServe() {
256
367
  child.on('close', (code) => process.exit(code || 0));
257
368
  }
258
369
 
259
- // ═══════════════════════════════════════════════════════════════
260
- // UTILITIES
261
- // ═══════════════════════════════════════════════════════════════
262
- function copyDirRecursive(src, dest) {
263
- if (!fs.existsSync(dest)) {
264
- fs.mkdirSync(dest, { recursive: true });
265
- }
266
-
267
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
268
- if (entry.name.startsWith('.')) continue; // Skip hidden files
269
-
270
- const srcPath = path.join(src, entry.name);
271
- const destPath = path.join(dest, entry.name);
272
-
273
- if (entry.isDirectory()) {
274
- copyDirRecursive(srcPath, destPath);
275
- } else {
276
- fs.copyFileSync(srcPath, destPath);
277
- }
278
- }
279
- }
280
-
281
- function showHelp() {
282
- console.log(`
283
- JUX CLI
284
-
285
- Usage:
286
- jux create <name> Create a new JUX project
287
- jux init Initialize JUX in current directory
288
- jux build Build for production
289
- jux serve Start production server
290
- jux serve --hot Start dev server with hot reload
291
- jux comp [name] Add a component preset to your project
292
- jux comp [name] -f Force overwrite (backs up existing files)
293
-
294
- Options:
295
- --help, -h Show this help message
296
- --force, -f Overwrite existing files (creates .bak backups)
297
- `);
298
- }
299
-
300
370
  // ═══════════════════════════════════════════════════════════════
301
371
  // COMMAND: comp [name]
302
372
  // Copies a preset component into the project's jux directory
@@ -409,47 +479,6 @@ async function runComp(compName) {
409
479
  console.log('');
410
480
  }
411
481
 
412
- /**
413
- * Resolve a safe folder name: compName -> compName-jux -> compName-1, compName-2, ...
414
- */
415
- function resolveDestFolderName(parentDir, baseName) {
416
- const first = path.join(parentDir, baseName);
417
- if (!fs.existsSync(first)) return baseName;
418
-
419
- const juxName = baseName + '-jux';
420
- const second = path.join(parentDir, juxName);
421
- if (!fs.existsSync(second)) return juxName;
422
-
423
- for (let i = 1; i <= 99; i++) {
424
- const numbered = `${baseName}-${i}`;
425
- if (!fs.existsSync(path.join(parentDir, numbered))) return numbered;
426
- }
427
-
428
- // Last resort — timestamp
429
- return `${baseName}-${Date.now()}`;
430
- }
431
-
432
- /**
433
- * List all files in a directory recursively, returning relative paths
434
- */
435
- function listFilesRecursive(dir, base = '') {
436
- const results = [];
437
- const entries = fs.readdirSync(dir, { withFileTypes: true });
438
-
439
- for (const entry of entries) {
440
- if (entry.name.startsWith('.')) continue;
441
- const rel = base ? path.join(base, entry.name) : entry.name;
442
-
443
- if (entry.isDirectory()) {
444
- results.push(...listFilesRecursive(path.join(dir, entry.name), rel));
445
- } else {
446
- results.push(rel);
447
- }
448
- }
449
-
450
- return results;
451
- }
452
-
453
482
  // ═══════════════════════════════════════════════════════════════
454
483
  // MAIN ROUTER
455
484
  // ═══════════════════════════════════════════════════════════════
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.369",
3
+ "version": "1.1.371",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "./dist/lib/index.js",