juxscript 1.1.369 → 1.1.370
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 +129 -41
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -12,6 +12,135 @@ 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 listFilesRecursive(dir, base = '') {
|
|
71
|
+
const results = [];
|
|
72
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
73
|
+
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
if (entry.name.startsWith('.')) continue;
|
|
76
|
+
const rel = base ? path.join(base, entry.name) : entry.name;
|
|
77
|
+
|
|
78
|
+
if (entry.isDirectory()) {
|
|
79
|
+
results.push(...listFilesRecursive(path.join(dir, entry.name), rel));
|
|
80
|
+
} else {
|
|
81
|
+
results.push(rel);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function promptPresetSelection(presets) {
|
|
89
|
+
return new Promise((resolve) => {
|
|
90
|
+
console.log('\n📦 Available component presets:\n');
|
|
91
|
+
presets.forEach((p, i) => {
|
|
92
|
+
const presetDir = path.join(PACKAGE_ROOT, 'presets', p);
|
|
93
|
+
const files = fs.readdirSync(presetDir).filter(f => !f.startsWith('.'));
|
|
94
|
+
console.log(` ${i + 1}) ${p} (${files.join(', ')})`);
|
|
95
|
+
});
|
|
96
|
+
console.log(` 0) Cancel\n`);
|
|
97
|
+
|
|
98
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
99
|
+
rl.question('Select a preset (number or name): ', (answer) => {
|
|
100
|
+
rl.close();
|
|
101
|
+
const trimmed = answer.trim();
|
|
102
|
+
|
|
103
|
+
const num = parseInt(trimmed, 10);
|
|
104
|
+
if (num === 0) return resolve(null);
|
|
105
|
+
if (num >= 1 && num <= presets.length) return resolve(presets[num - 1]);
|
|
106
|
+
|
|
107
|
+
if (presets.includes(trimmed)) return resolve(trimmed);
|
|
108
|
+
|
|
109
|
+
console.error(`❌ Invalid selection: "${trimmed}"`);
|
|
110
|
+
resolve(null);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function promptYesNo(question) {
|
|
116
|
+
return new Promise((resolve) => {
|
|
117
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
118
|
+
rl.question(`${question} (y/N): `, (answer) => {
|
|
119
|
+
rl.close();
|
|
120
|
+
resolve(answer.trim().toLowerCase() === 'y');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function showHelp() {
|
|
126
|
+
console.log(`
|
|
127
|
+
JUX CLI
|
|
128
|
+
|
|
129
|
+
Usage:
|
|
130
|
+
jux create <name> Create a new JUX project
|
|
131
|
+
jux init Initialize JUX in current directory
|
|
132
|
+
jux build Build for production
|
|
133
|
+
jux serve Start production server
|
|
134
|
+
jux serve --hot Start dev server with hot reload
|
|
135
|
+
jux comp [name] Add a component preset to your project
|
|
136
|
+
jux comp [name] -f Force overwrite (backs up existing files)
|
|
137
|
+
|
|
138
|
+
Options:
|
|
139
|
+
--help, -h Show this help message
|
|
140
|
+
--force, -f Overwrite existing files (creates .bak backups)
|
|
141
|
+
`);
|
|
142
|
+
}
|
|
143
|
+
|
|
15
144
|
// ═══════════════════════════════════════════════════════════════
|
|
16
145
|
// COMMAND: create <project-name>
|
|
17
146
|
// Creates a new JUX project from the template
|
|
@@ -256,47 +385,6 @@ function runServe() {
|
|
|
256
385
|
child.on('close', (code) => process.exit(code || 0));
|
|
257
386
|
}
|
|
258
387
|
|
|
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
388
|
// ═══════════════════════════════════════════════════════════════
|
|
301
389
|
// COMMAND: comp [name]
|
|
302
390
|
// Copies a preset component into the project's jux directory
|