juxscript 1.1.366 → 1.1.367
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/bin/cli.js +140 -2
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import path from 'path';
|
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { spawn } from 'child_process';
|
|
7
|
+
import { createInterface } from 'readline';
|
|
7
8
|
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -287,23 +288,154 @@ Usage:
|
|
|
287
288
|
jux build Build for production
|
|
288
289
|
jux serve Start production server
|
|
289
290
|
jux serve --hot Start dev server with hot reload
|
|
291
|
+
jux comp [name] Add a component preset to your project
|
|
290
292
|
|
|
291
293
|
Options:
|
|
292
294
|
--help, -h Show this help message
|
|
293
295
|
`);
|
|
294
296
|
}
|
|
295
297
|
|
|
298
|
+
// ═══════════════════════════════════════════════════════════════
|
|
299
|
+
// COMMAND: comp [name]
|
|
300
|
+
// Copies a preset component into the project's jux directory
|
|
301
|
+
// ═══════════════════════════════════════════════════════════════
|
|
302
|
+
async function runComp(compName) {
|
|
303
|
+
const presetsDir = path.join(PACKAGE_ROOT, 'presets');
|
|
304
|
+
|
|
305
|
+
if (!fs.existsSync(presetsDir)) {
|
|
306
|
+
console.error('❌ No presets directory found in juxscript package.');
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Discover available presets (each subfolder is a preset)
|
|
311
|
+
const available = fs.readdirSync(presetsDir, { withFileTypes: true })
|
|
312
|
+
.filter(d => d.isDirectory())
|
|
313
|
+
.map(d => d.name);
|
|
314
|
+
|
|
315
|
+
if (available.length === 0) {
|
|
316
|
+
console.error('❌ No presets available.');
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// If no name given, show interactive list
|
|
321
|
+
if (!compName) {
|
|
322
|
+
compName = await promptPresetSelection(available);
|
|
323
|
+
if (!compName) {
|
|
324
|
+
console.log('Cancelled.');
|
|
325
|
+
process.exit(0);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Validate preset exists
|
|
330
|
+
const presetDir = path.join(presetsDir, compName);
|
|
331
|
+
if (!fs.existsSync(presetDir)) {
|
|
332
|
+
console.error(`❌ Preset "${compName}" not found.`);
|
|
333
|
+
console.log(`\nAvailable presets:`);
|
|
334
|
+
available.forEach(p => console.log(` • ${p}`));
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Resolve target directory from juxconfig.js or default 'jux'
|
|
339
|
+
const targetSrcDir = resolveProjectSrcDir();
|
|
340
|
+
|
|
341
|
+
if (!fs.existsSync(targetSrcDir)) {
|
|
342
|
+
fs.mkdirSync(targetSrcDir, { recursive: true });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Copy all files from preset to project src dir
|
|
346
|
+
const presetFiles = fs.readdirSync(presetDir, { withFileTypes: true });
|
|
347
|
+
let copied = 0;
|
|
348
|
+
|
|
349
|
+
for (const entry of presetFiles) {
|
|
350
|
+
if (entry.isFile()) {
|
|
351
|
+
const srcPath = path.join(presetDir, entry.name);
|
|
352
|
+
const destPath = path.join(targetSrcDir, entry.name);
|
|
353
|
+
|
|
354
|
+
if (fs.existsSync(destPath)) {
|
|
355
|
+
const overwrite = await promptYesNo(` ⚠️ "${entry.name}" already exists. Overwrite?`);
|
|
356
|
+
if (!overwrite) {
|
|
357
|
+
console.log(` ⏭️ Skipped ${entry.name}`);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
fs.copyFileSync(srcPath, destPath);
|
|
363
|
+
console.log(` ✅ ${entry.name}`);
|
|
364
|
+
copied++;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
console.log(`\n✅ Copied ${copied} file(s) from preset "${compName}" to ${path.relative(process.cwd(), targetSrcDir)}/\n`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function resolveProjectSrcDir() {
|
|
372
|
+
const projectRoot = process.cwd();
|
|
373
|
+
const configPath = path.join(projectRoot, 'juxconfig.js');
|
|
374
|
+
|
|
375
|
+
if (fs.existsSync(configPath)) {
|
|
376
|
+
try {
|
|
377
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
378
|
+
const srcDirMatch = configContent.match(/srcDir\s*:\s*['"]([^'"]+)['"]/);
|
|
379
|
+
if (srcDirMatch) {
|
|
380
|
+
return path.resolve(projectRoot, srcDirMatch[1]);
|
|
381
|
+
}
|
|
382
|
+
} catch (_) { }
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return path.resolve(projectRoot, 'jux');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function promptPresetSelection(presets) {
|
|
389
|
+
return new Promise((resolve) => {
|
|
390
|
+
console.log('\n📦 Available component presets:\n');
|
|
391
|
+
presets.forEach((p, i) => {
|
|
392
|
+
// Read files in preset to show what's included
|
|
393
|
+
const presetDir = path.join(PACKAGE_ROOT, 'presets', p);
|
|
394
|
+
const files = fs.readdirSync(presetDir).filter(f => !f.startsWith('.'));
|
|
395
|
+
console.log(` ${i + 1}) ${p} (${files.join(', ')})`);
|
|
396
|
+
});
|
|
397
|
+
console.log(` 0) Cancel\n`);
|
|
398
|
+
|
|
399
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
400
|
+
rl.question('Select a preset (number or name): ', (answer) => {
|
|
401
|
+
rl.close();
|
|
402
|
+
const trimmed = answer.trim();
|
|
403
|
+
|
|
404
|
+
// By number
|
|
405
|
+
const num = parseInt(trimmed, 10);
|
|
406
|
+
if (num === 0) return resolve(null);
|
|
407
|
+
if (num >= 1 && num <= presets.length) return resolve(presets[num - 1]);
|
|
408
|
+
|
|
409
|
+
// By name
|
|
410
|
+
if (presets.includes(trimmed)) return resolve(trimmed);
|
|
411
|
+
|
|
412
|
+
console.error(`❌ Invalid selection: "${trimmed}"`);
|
|
413
|
+
resolve(null);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function promptYesNo(question) {
|
|
419
|
+
return new Promise((resolve) => {
|
|
420
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
421
|
+
rl.question(`${question} (y/N): `, (answer) => {
|
|
422
|
+
rl.close();
|
|
423
|
+
resolve(answer.trim().toLowerCase() === 'y');
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
296
428
|
// ═══════════════════════════════════════════════════════════════
|
|
297
429
|
// MAIN ROUTER
|
|
298
430
|
// ═══════════════════════════════════════════════════════════════
|
|
299
431
|
switch (command) {
|
|
300
432
|
case 'create':
|
|
301
|
-
createProject(args[0]);
|
|
433
|
+
createProject(args[0]);
|
|
302
434
|
break;
|
|
303
435
|
|
|
304
436
|
case 'init':
|
|
305
437
|
case 'install':
|
|
306
|
-
initProject();
|
|
438
|
+
initProject();
|
|
307
439
|
break;
|
|
308
440
|
|
|
309
441
|
case 'build':
|
|
@@ -315,6 +447,12 @@ switch (command) {
|
|
|
315
447
|
runServe();
|
|
316
448
|
break;
|
|
317
449
|
|
|
450
|
+
case 'comp':
|
|
451
|
+
case 'component':
|
|
452
|
+
case 'preset':
|
|
453
|
+
runComp(args[0]);
|
|
454
|
+
break;
|
|
455
|
+
|
|
318
456
|
case '--help':
|
|
319
457
|
case '-h':
|
|
320
458
|
case undefined:
|