juxscript 1.1.368 → 1.1.369
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
CHANGED
|
@@ -289,9 +289,11 @@ Usage:
|
|
|
289
289
|
jux serve Start production server
|
|
290
290
|
jux serve --hot Start dev server with hot reload
|
|
291
291
|
jux comp [name] Add a component preset to your project
|
|
292
|
+
jux comp [name] -f Force overwrite (backs up existing files)
|
|
292
293
|
|
|
293
294
|
Options:
|
|
294
295
|
--help, -h Show this help message
|
|
296
|
+
--force, -f Overwrite existing files (creates .bak backups)
|
|
295
297
|
`);
|
|
296
298
|
}
|
|
297
299
|
|
|
@@ -301,6 +303,7 @@ Options:
|
|
|
301
303
|
// ═══════════════════════════════════════════════════════════════
|
|
302
304
|
async function runComp(compName) {
|
|
303
305
|
const presetsDir = path.join(PACKAGE_ROOT, 'presets');
|
|
306
|
+
const forceFlag = args.includes('--force') || args.includes('-f');
|
|
304
307
|
|
|
305
308
|
if (!fs.existsSync(presetsDir)) {
|
|
306
309
|
console.error('❌ No presets directory found in juxscript package.');
|
|
@@ -342,87 +345,109 @@ async function runComp(compName) {
|
|
|
342
345
|
fs.mkdirSync(targetSrcDir, { recursive: true });
|
|
343
346
|
}
|
|
344
347
|
|
|
345
|
-
//
|
|
346
|
-
const
|
|
348
|
+
// Resolve a safe destination folder name
|
|
349
|
+
const destFolderName = resolveDestFolderName(targetSrcDir, compName);
|
|
350
|
+
const destDir = path.join(targetSrcDir, destFolderName);
|
|
351
|
+
|
|
352
|
+
// List what will be copied
|
|
353
|
+
const presetFiles = listFilesRecursive(presetDir);
|
|
354
|
+
|
|
355
|
+
console.log(`\n📦 Preset: ${compName}`);
|
|
356
|
+
console.log(` Source: presets/${compName}/`);
|
|
357
|
+
console.log(` Target: ${path.relative(process.cwd(), destDir)}/\n`);
|
|
358
|
+
|
|
359
|
+
if (destFolderName !== compName) {
|
|
360
|
+
console.log(` ⚠️ "${compName}" already exists, using "${destFolderName}" instead.\n`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
console.log(` Files to copy:`);
|
|
364
|
+
presetFiles.forEach(f => console.log(` 📄 ${f}`));
|
|
365
|
+
console.log('');
|
|
366
|
+
|
|
367
|
+
// If dest exists (shouldn't with our naming, but just in case with --force)
|
|
368
|
+
if (fs.existsSync(destDir) && !forceFlag) {
|
|
369
|
+
const proceed = await promptYesNo(` Directory "${destFolderName}" exists. Overwrite contents?`);
|
|
370
|
+
if (!proceed) {
|
|
371
|
+
console.log(' Cancelled.\n');
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Copy the entire preset folder
|
|
377
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
347
378
|
let copied = 0;
|
|
379
|
+
let backed = 0;
|
|
348
380
|
|
|
349
|
-
for (const
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
}
|
|
381
|
+
for (const relFile of presetFiles) {
|
|
382
|
+
const srcPath = path.join(presetDir, relFile);
|
|
383
|
+
const destPath = path.join(destDir, relFile);
|
|
361
384
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
385
|
+
// Ensure subdirectory exists
|
|
386
|
+
const destFileDir = path.dirname(destPath);
|
|
387
|
+
if (!fs.existsSync(destFileDir)) {
|
|
388
|
+
fs.mkdirSync(destFileDir, { recursive: true });
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (fs.existsSync(destPath)) {
|
|
392
|
+
// Backup existing
|
|
393
|
+
const backupPath = destPath + '.bak';
|
|
394
|
+
fs.copyFileSync(destPath, backupPath);
|
|
395
|
+
backed++;
|
|
396
|
+
console.log(` 🔄 ${relFile} (backed up to ${relFile}.bak)`);
|
|
397
|
+
} else {
|
|
398
|
+
console.log(` ✅ ${relFile}`);
|
|
365
399
|
}
|
|
400
|
+
|
|
401
|
+
fs.copyFileSync(srcPath, destPath);
|
|
402
|
+
copied++;
|
|
366
403
|
}
|
|
367
404
|
|
|
368
|
-
console.log(`\n✅
|
|
405
|
+
console.log(`\n✅ Done: ${copied} file(s) copied to ${path.relative(process.cwd(), destDir)}/`);
|
|
406
|
+
if (backed > 0) {
|
|
407
|
+
console.log(` ${backed} existing file(s) backed up with .bak extension`);
|
|
408
|
+
}
|
|
409
|
+
console.log('');
|
|
369
410
|
}
|
|
370
411
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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;
|
|
374
418
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
} catch (_) { }
|
|
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;
|
|
383
426
|
}
|
|
384
427
|
|
|
385
|
-
|
|
428
|
+
// Last resort — timestamp
|
|
429
|
+
return `${baseName}-${Date.now()}`;
|
|
386
430
|
}
|
|
387
431
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
}
|
|
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 });
|
|
417
438
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
}
|
|
425
|
-
|
|
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;
|
|
426
451
|
}
|
|
427
452
|
|
|
428
453
|
// ═══════════════════════════════════════════════════════════════
|
package/package.json
CHANGED
|
File without changes
|