slicejs-cli 3.1.0 → 3.2.0
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/README.md +375 -375
- package/client.js +579 -555
- package/commands/Print.js +167 -167
- package/commands/Validations.js +103 -103
- package/commands/build/build.js +40 -40
- package/commands/buildProduction/buildProduction.js +579 -579
- package/commands/bundle/bundle.js +235 -235
- package/commands/createComponent/VisualComponentTemplate.js +55 -55
- package/commands/createComponent/createComponent.js +126 -126
- package/commands/deleteComponent/deleteComponent.js +77 -77
- package/commands/doctor/doctor.js +369 -369
- package/commands/getComponent/getComponent.js +747 -747
- package/commands/init/init.js +261 -261
- package/commands/listComponents/listComponents.js +175 -175
- package/commands/startServer/startServer.js +264 -264
- package/commands/startServer/watchServer.js +79 -79
- package/commands/types/types.js +538 -0
- package/commands/utils/LocalCliDelegation.js +53 -53
- package/commands/utils/PathHelper.js +68 -68
- package/commands/utils/VersionChecker.js +167 -167
- package/commands/utils/bundling/BundleGenerator.js +2292 -2292
- package/commands/utils/bundling/DependencyAnalyzer.js +933 -933
- package/commands/utils/updateManager.js +453 -453
- package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +182 -0
- package/package.json +46 -46
- package/post.js +25 -25
- package/refactor.md +271 -271
- package/tests/bundle-generator.test.js +708 -708
- package/tests/bundle-v2-register-output.test.js +470 -470
- package/tests/client-launcher-contract.test.js +211 -211
- package/tests/client-update-flow-contract.test.js +272 -272
- package/tests/dependency-analyzer.test.js +24 -24
- package/tests/local-cli-delegation.test.js +79 -79
- package/tests/types-generator.test.js +356 -0
- package/tests/update-manager-notifications.test.js +88 -88
package/client.js
CHANGED
|
@@ -1,570 +1,594 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { program } from "commander";
|
|
3
|
-
import inquirer from "inquirer";
|
|
4
|
-
import initializeProject from "./commands/init/init.js";
|
|
5
|
-
import createComponent from "./commands/createComponent/createComponent.js";
|
|
6
|
-
import listComponents from "./commands/listComponents/listComponents.js";
|
|
7
|
-
import deleteComponent from "./commands/deleteComponent/deleteComponent.js";
|
|
8
|
-
import getComponent, { listComponents as listRemoteComponents, syncComponents } from "./commands/getComponent/getComponent.js";
|
|
9
|
-
import startServer from "./commands/startServer/startServer.js";
|
|
10
|
-
import runDiagnostics from "./commands/doctor/doctor.js";
|
|
11
|
-
import versionChecker from "./commands/utils/VersionChecker.js";
|
|
12
|
-
import updateManager from "./commands/utils/updateManager.js";
|
|
13
|
-
import fs from "fs";
|
|
14
|
-
import path from "path";
|
|
15
|
-
import { fileURLToPath } from "url";
|
|
16
|
-
import { getConfigPath, getProjectRoot } from "./commands/utils/PathHelper.js";
|
|
17
|
-
import { exec, spawnSync } from "node:child_process";
|
|
18
|
-
import { promisify } from "util";
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import inquirer from "inquirer";
|
|
4
|
+
import initializeProject from "./commands/init/init.js";
|
|
5
|
+
import createComponent from "./commands/createComponent/createComponent.js";
|
|
6
|
+
import listComponents from "./commands/listComponents/listComponents.js";
|
|
7
|
+
import deleteComponent from "./commands/deleteComponent/deleteComponent.js";
|
|
8
|
+
import getComponent, { listComponents as listRemoteComponents, syncComponents } from "./commands/getComponent/getComponent.js";
|
|
9
|
+
import startServer from "./commands/startServer/startServer.js";
|
|
10
|
+
import runDiagnostics from "./commands/doctor/doctor.js";
|
|
11
|
+
import versionChecker from "./commands/utils/VersionChecker.js";
|
|
12
|
+
import updateManager from "./commands/utils/updateManager.js";
|
|
13
|
+
import fs from "fs";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { fileURLToPath } from "url";
|
|
16
|
+
import { getConfigPath, getProjectRoot } from "./commands/utils/PathHelper.js";
|
|
17
|
+
import { exec, spawnSync } from "node:child_process";
|
|
18
|
+
import { promisify } from "util";
|
|
19
19
|
import validations from "./commands/Validations.js";
|
|
20
20
|
import Print from "./commands/Print.js";
|
|
21
21
|
import build from './commands/build/build.js';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
.
|
|
150
|
-
.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
.
|
|
161
|
-
.
|
|
162
|
-
.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
.
|
|
170
|
-
|
|
171
|
-
process.env.NODE_ENV
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
.
|
|
184
|
-
.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
.
|
|
191
|
-
.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
.option("-
|
|
198
|
-
.option("--
|
|
199
|
-
.option("--no-
|
|
200
|
-
.option("--
|
|
201
|
-
.option("--
|
|
202
|
-
.option("--
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
.
|
|
208
|
-
.
|
|
209
|
-
.option("--
|
|
210
|
-
.
|
|
211
|
-
|
|
212
|
-
process.env.NODE_ENV
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
.
|
|
230
|
-
.
|
|
231
|
-
.
|
|
232
|
-
|
|
233
|
-
process.env.NODE_ENV
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
.
|
|
253
|
-
.
|
|
254
|
-
.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
Print.
|
|
260
|
-
Print.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
Print.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
.
|
|
298
|
-
.
|
|
299
|
-
.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
.
|
|
310
|
-
.
|
|
311
|
-
.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
Print.
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
Print.
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
22
|
+
import { runGenerateTypes } from './commands/types/types.js';
|
|
23
|
+
import { cleanBundles, bundleInfo } from './commands/bundle/bundle.js';
|
|
24
|
+
import {
|
|
25
|
+
isLocalDelegationDisabled,
|
|
26
|
+
findNearestLocalCliEntry,
|
|
27
|
+
resolveLocalCliCandidate,
|
|
28
|
+
shouldDelegateToLocalCli
|
|
29
|
+
} from './commands/utils/LocalCliDelegation.js';
|
|
30
|
+
|
|
31
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
|
|
33
|
+
const loadConfig = () => {
|
|
34
|
+
try {
|
|
35
|
+
const configPath = getConfigPath(import.meta.url);
|
|
36
|
+
const rawData = fs.readFileSync(configPath, "utf-8");
|
|
37
|
+
return JSON.parse(rawData);
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const getCategories = () => {
|
|
44
|
+
const config = loadConfig();
|
|
45
|
+
return config && config.paths?.components ? Object.keys(config.paths.components) : [];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Function to run version check for all commands
|
|
49
|
+
async function runWithVersionCheck(commandFunction, ...args) {
|
|
50
|
+
try {
|
|
51
|
+
const execAsync = promisify(exec);
|
|
52
|
+
await (async () => {
|
|
53
|
+
try {
|
|
54
|
+
const info = await updateManager.detectCliInstall();
|
|
55
|
+
if (info && info.type === 'global') {
|
|
56
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
57
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
58
|
+
let hasPkg = fs.existsSync(pkgPath);
|
|
59
|
+
if (!hasPkg) {
|
|
60
|
+
const { confirmInit } = await inquirer.prompt([
|
|
61
|
+
{
|
|
62
|
+
type: 'confirm',
|
|
63
|
+
name: 'confirmInit',
|
|
64
|
+
message: 'No package.json found. Initialize npm in this project now?',
|
|
65
|
+
default: true
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
if (confirmInit) {
|
|
69
|
+
await execAsync('npm init -y', { cwd: projectRoot });
|
|
70
|
+
hasPkg = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (hasPkg) {
|
|
74
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
75
|
+
const hasFramework = pkg.dependencies?.['slicejs-web-framework'];
|
|
76
|
+
if (!hasFramework) {
|
|
77
|
+
const { confirm } = await inquirer.prompt([
|
|
78
|
+
{
|
|
79
|
+
type: 'confirm',
|
|
80
|
+
name: 'confirm',
|
|
81
|
+
message: 'slicejs-web-framework is not installed in this project. Install it now?',
|
|
82
|
+
default: true
|
|
83
|
+
}
|
|
84
|
+
]);
|
|
85
|
+
if (confirm) {
|
|
86
|
+
await updateManager.updatePackage('slicejs-web-framework');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch {}
|
|
92
|
+
})();
|
|
93
|
+
|
|
94
|
+
updateManager.notifyAvailableUpdates().catch(() => {});
|
|
95
|
+
|
|
96
|
+
const result = await commandFunction(...args);
|
|
97
|
+
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
versionChecker.checkForUpdates(false);
|
|
100
|
+
}, 100);
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
Print.error(`Command execution: ${error.message}`);
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function maybeDelegateToLocalCli() {
|
|
110
|
+
if (isLocalDelegationDisabled(process.env)) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const currentEntryPath = fileURLToPath(import.meta.url);
|
|
115
|
+
const localEntryPath = findNearestLocalCliEntry(process.cwd(), resolveLocalCliCandidate);
|
|
116
|
+
|
|
117
|
+
if (!shouldDelegateToLocalCli(currentEntryPath, localEntryPath)) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const child = spawnSync(
|
|
122
|
+
process.execPath,
|
|
123
|
+
[localEntryPath, ...process.argv.slice(2)],
|
|
124
|
+
{
|
|
125
|
+
stdio: 'inherit',
|
|
126
|
+
cwd: process.cwd(),
|
|
127
|
+
env: process.env
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
process.exit(child.status ?? 1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
maybeDelegateToLocalCli();
|
|
135
|
+
|
|
136
|
+
const sliceClient = program;
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const pkgPath = path.join(__dirname, "./package.json");
|
|
140
|
+
const pkgRaw = fs.readFileSync(pkgPath, "utf-8");
|
|
141
|
+
const pkg = JSON.parse(pkgRaw);
|
|
142
|
+
sliceClient.version(pkg.version).description("CLI for managing Slice.js framework components");
|
|
143
|
+
} catch {
|
|
144
|
+
sliceClient.version("0.0.0").description("CLI for managing Slice.js framework components");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// INIT COMMAND
|
|
148
|
+
sliceClient
|
|
149
|
+
.command("init")
|
|
150
|
+
.description("Initialize a new Slice.js project")
|
|
151
|
+
.action(async () => {
|
|
152
|
+
await runWithVersionCheck(() => {
|
|
153
|
+
initializeProject();
|
|
154
|
+
return Promise.resolve();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// VERSION COMMAND
|
|
159
|
+
sliceClient
|
|
160
|
+
.command("version")
|
|
161
|
+
.alias("v")
|
|
162
|
+
.description("Show version information and check for updates")
|
|
163
|
+
.action(async () => {
|
|
164
|
+
await versionChecker.showVersionInfo();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// BUILD COMMAND
|
|
168
|
+
const buildCommand = sliceClient.command("build")
|
|
169
|
+
.description("Build Slice.js project for production")
|
|
170
|
+
.action(async (options) => {
|
|
171
|
+
const prevEnv = process.env.NODE_ENV;
|
|
172
|
+
process.env.NODE_ENV = 'production';
|
|
173
|
+
try {
|
|
174
|
+
await runWithVersionCheck(async () => {
|
|
175
|
+
await build(options);
|
|
176
|
+
});
|
|
177
|
+
} finally {
|
|
178
|
+
process.env.NODE_ENV = prevEnv;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
buildCommand
|
|
183
|
+
.command("clean")
|
|
184
|
+
.description("Remove all generated bundles")
|
|
185
|
+
.action(async () => {
|
|
186
|
+
await cleanBundles();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
buildCommand
|
|
190
|
+
.command("info")
|
|
191
|
+
.description("Show information about generated bundles")
|
|
192
|
+
.action(async () => {
|
|
193
|
+
await bundleInfo();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
buildCommand
|
|
197
|
+
.option("-a, --analyze", "Analyze project dependencies without bundling")
|
|
198
|
+
.option("-v, --verbose", "Show detailed output")
|
|
199
|
+
.option("--no-minify", "Disable minification (enabled by default)")
|
|
200
|
+
.option("--no-obfuscate", "Disable obfuscation (enabled by default, no prop mangling)")
|
|
201
|
+
.option("--preview", "Start preview server after build")
|
|
202
|
+
.option("--serve", "Start preview server without building")
|
|
203
|
+
.option("--skip-clean", "Skip cleaning dist before build");
|
|
204
|
+
|
|
205
|
+
// DEV COMMAND (DEVELOPMENT)
|
|
206
|
+
sliceClient
|
|
207
|
+
.command("dev")
|
|
208
|
+
.description("Start development server with hot reload enabled by default")
|
|
209
|
+
.option("-p, --port <port>", "Port for development server", 3000)
|
|
210
|
+
.option("--no-hmr", "Disable hot module reload (enabled by default)")
|
|
211
|
+
.action(async (options) => {
|
|
212
|
+
const prevEnv = process.env.NODE_ENV;
|
|
213
|
+
process.env.NODE_ENV = 'development';
|
|
214
|
+
try {
|
|
215
|
+
await runWithVersionCheck(async () => {
|
|
216
|
+
await startServer({
|
|
217
|
+
mode: 'development',
|
|
218
|
+
port: parseInt(options.port),
|
|
219
|
+
watch: options.hmr
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
} finally {
|
|
223
|
+
process.env.NODE_ENV = prevEnv;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// START COMMAND - PRODUCTION MODE
|
|
228
|
+
sliceClient
|
|
229
|
+
.command("start")
|
|
230
|
+
.description("Serve production files from dist/ (requires prior slice build)")
|
|
231
|
+
.option("-p, --port <port>", "Port for server", 3000)
|
|
232
|
+
.action(async (options) => {
|
|
233
|
+
const prevEnv = process.env.NODE_ENV;
|
|
234
|
+
process.env.NODE_ENV = 'production';
|
|
235
|
+
try {
|
|
236
|
+
await runWithVersionCheck(async () => {
|
|
237
|
+
await startServer({
|
|
238
|
+
mode: 'production',
|
|
239
|
+
port: parseInt(options.port)
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
} finally {
|
|
243
|
+
process.env.NODE_ENV = prevEnv;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// COMPONENT COMMAND GROUP - For local component management
|
|
248
|
+
const componentCommand = sliceClient.command("component").alias("comp").description("Manage local project components");
|
|
249
|
+
|
|
250
|
+
// CREATE LOCAL COMPONENT
|
|
251
|
+
componentCommand
|
|
252
|
+
.command("create")
|
|
253
|
+
.alias("new")
|
|
254
|
+
.description("Create a new component in your local project")
|
|
255
|
+
.action(async () => {
|
|
256
|
+
await runWithVersionCheck(async () => {
|
|
257
|
+
const categories = getCategories();
|
|
258
|
+
if (categories.length === 0) {
|
|
259
|
+
Print.error("No categories found in your project configuration");
|
|
260
|
+
Print.info("Run 'slice init' to initialize your project first");
|
|
261
|
+
Print.commandExample("Initialize project", "slice init");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const answers = await inquirer.prompt([
|
|
266
|
+
{
|
|
267
|
+
type: "input",
|
|
268
|
+
name: "componentName",
|
|
269
|
+
message: "Enter the component name:",
|
|
270
|
+
validate: (input) => {
|
|
271
|
+
if (!input) return "Component name cannot be empty";
|
|
272
|
+
if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(input)) {
|
|
273
|
+
return "Component name must start with a letter and contain only alphanumeric characters";
|
|
274
|
+
}
|
|
275
|
+
return true;
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
type: "list",
|
|
280
|
+
name: "category",
|
|
281
|
+
message: "Select the component category:",
|
|
282
|
+
choices: categories,
|
|
283
|
+
}
|
|
284
|
+
]);
|
|
285
|
+
|
|
286
|
+
const result = createComponent(answers.componentName, answers.category);
|
|
287
|
+
if (result) {
|
|
288
|
+
Print.success(`Component '${answers.componentName}' created successfully in category '${answers.category}'`);
|
|
289
|
+
Print.info("Listing updated components:");
|
|
290
|
+
listComponents();
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// LIST LOCAL COMPONENTS
|
|
296
|
+
componentCommand
|
|
297
|
+
.command("list")
|
|
298
|
+
.alias("ls")
|
|
299
|
+
.description("List all components in your local project")
|
|
300
|
+
.action(async () => {
|
|
301
|
+
await runWithVersionCheck(() => {
|
|
302
|
+
listComponents();
|
|
303
|
+
return Promise.resolve();
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// DELETE LOCAL COMPONENT
|
|
308
|
+
componentCommand
|
|
309
|
+
.command("delete")
|
|
310
|
+
.alias("remove")
|
|
311
|
+
.description("Delete a component from your local project")
|
|
312
|
+
.action(async () => {
|
|
313
|
+
await runWithVersionCheck(async () => {
|
|
314
|
+
const categories = getCategories();
|
|
315
|
+
if (categories.length === 0) {
|
|
316
|
+
Print.error("No categories available. Check your configuration");
|
|
317
|
+
Print.info("Run 'slice init' to initialize your project");
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
// Paso 1: Seleccionar categoría
|
|
323
|
+
const categoryAnswer = await inquirer.prompt([
|
|
324
|
+
{
|
|
325
|
+
type: "list",
|
|
326
|
+
name: "category",
|
|
327
|
+
message: "Select the component category:",
|
|
328
|
+
choices: categories,
|
|
329
|
+
}
|
|
330
|
+
]);
|
|
331
|
+
|
|
332
|
+
// Paso 2: Listar componentes de esa categoría
|
|
333
|
+
const config = loadConfig();
|
|
334
|
+
if (!config) {
|
|
335
|
+
Print.error("Could not load configuration");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const categoryPath = config.paths.components[categoryAnswer.category].path;
|
|
340
|
+
const fullPath = path.join(__dirname, "../../src", categoryPath);
|
|
341
|
+
|
|
342
|
+
if (!fs.existsSync(fullPath)) {
|
|
343
|
+
Print.error(`Category path does not exist: ${categoryPath}`);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const components = fs.readdirSync(fullPath).filter(item => {
|
|
348
|
+
const itemPath = path.join(fullPath, item);
|
|
349
|
+
return fs.statSync(itemPath).isDirectory();
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
if (components.length === 0) {
|
|
353
|
+
Print.info(`No components found in category '${categoryAnswer.category}'`);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Paso 3: Seleccionar componente a eliminar
|
|
358
|
+
const componentAnswer = await inquirer.prompt([
|
|
359
|
+
{
|
|
360
|
+
type: "list",
|
|
361
|
+
name: "componentName",
|
|
362
|
+
message: "Select the component to delete:",
|
|
363
|
+
choices: components,
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
type: "confirm",
|
|
367
|
+
name: "confirm",
|
|
368
|
+
message: (answers) => `Are you sure you want to delete '${answers.componentName}'?`,
|
|
369
|
+
default: false,
|
|
370
|
+
}
|
|
371
|
+
]);
|
|
372
|
+
|
|
373
|
+
if (!componentAnswer.confirm) {
|
|
374
|
+
Print.info("Delete operation cancelled");
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Paso 4: Eliminar el componente
|
|
379
|
+
if (deleteComponent(componentAnswer.componentName, categoryAnswer.category)) {
|
|
380
|
+
Print.success(`Component ${componentAnswer.componentName} deleted successfully`);
|
|
381
|
+
Print.info("Listing updated components:");
|
|
382
|
+
listComponents();
|
|
383
|
+
}
|
|
384
|
+
} catch (error) {
|
|
385
|
+
Print.error(`Deleting component: ${error.message}`);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// REGISTRY COMMAND GROUP - For component registry operations
|
|
390
391
|
const registryCommand = sliceClient.command("registry").alias("reg").description("Manage components from official Slice.js repository");
|
|
391
392
|
|
|
392
|
-
//
|
|
393
|
-
|
|
394
|
-
.command("get [components...]")
|
|
395
|
-
.description("Download and install components from official repository")
|
|
396
|
-
.option("-f, --force", "Force overwrite existing components")
|
|
397
|
-
.option("-s, --service", "Install Service components instead of Visual")
|
|
398
|
-
.action(async (components, options) => {
|
|
399
|
-
await runWithVersionCheck(async () => {
|
|
400
|
-
await getComponent(components, {
|
|
401
|
-
force: options.force,
|
|
402
|
-
service: options.service
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
});
|
|
393
|
+
// TYPES COMMAND GROUP - TypeScript declarations from static props
|
|
394
|
+
const typesCommand = sliceClient.command("types").description("Generate TypeScript declarations from component static props");
|
|
406
395
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
.
|
|
410
|
-
.
|
|
411
|
-
.description("List all available components in the official repository")
|
|
412
|
-
.action(async () => {
|
|
413
|
-
await runWithVersionCheck(async () => {
|
|
414
|
-
await listRemoteComponents();
|
|
415
|
-
});
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
// SYNC COMPONENTS FROM REGISTRY
|
|
419
|
-
registryCommand
|
|
420
|
-
.command("sync")
|
|
421
|
-
.description("Update all local components to latest versions from repository")
|
|
422
|
-
.option("-f, --force", "Force update without confirmation")
|
|
396
|
+
typesCommand
|
|
397
|
+
.command("generate")
|
|
398
|
+
.description("Generate src/slice-build.generated.d.ts for slice.build autocomplete")
|
|
399
|
+
.option("-o, --output <path>", "Custom output path", "src/slice-build.generated.d.ts")
|
|
423
400
|
.action(async (options) => {
|
|
424
401
|
await runWithVersionCheck(async () => {
|
|
425
|
-
|
|
426
|
-
|
|
402
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
403
|
+
const outputPath = path.isAbsolute(options.output)
|
|
404
|
+
? options.output
|
|
405
|
+
: path.join(projectRoot, options.output);
|
|
406
|
+
|
|
407
|
+
await runGenerateTypes({
|
|
408
|
+
projectRoot,
|
|
409
|
+
outputPath
|
|
427
410
|
});
|
|
428
411
|
});
|
|
429
412
|
});
|
|
430
|
-
|
|
431
|
-
//
|
|
432
|
-
|
|
433
|
-
.command("get [components...]")
|
|
434
|
-
.description("
|
|
435
|
-
.option("-f, --force", "Force overwrite existing components")
|
|
436
|
-
.option("-s, --service", "Install Service components instead of Visual")
|
|
437
|
-
.action(async (components, options) => {
|
|
438
|
-
await runWithVersionCheck(async () => {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
.
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
413
|
+
|
|
414
|
+
// GET COMPONENTS FROM REGISTRY
|
|
415
|
+
registryCommand
|
|
416
|
+
.command("get [components...]")
|
|
417
|
+
.description("Download and install components from official repository")
|
|
418
|
+
.option("-f, --force", "Force overwrite existing components")
|
|
419
|
+
.option("-s, --service", "Install Service components instead of Visual")
|
|
420
|
+
.action(async (components, options) => {
|
|
421
|
+
await runWithVersionCheck(async () => {
|
|
422
|
+
await getComponent(components, {
|
|
423
|
+
force: options.force,
|
|
424
|
+
service: options.service
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// LIST REGISTRY COMPONENTS
|
|
430
|
+
registryCommand
|
|
431
|
+
.command("list")
|
|
432
|
+
.alias("ls")
|
|
433
|
+
.description("List all available components in the official repository")
|
|
434
|
+
.action(async () => {
|
|
435
|
+
await runWithVersionCheck(async () => {
|
|
436
|
+
await listRemoteComponents();
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// SYNC COMPONENTS FROM REGISTRY
|
|
441
|
+
registryCommand
|
|
442
|
+
.command("sync")
|
|
443
|
+
.description("Update all local components to latest versions from repository")
|
|
444
|
+
.option("-f, --force", "Force update without confirmation")
|
|
445
|
+
.action(async (options) => {
|
|
446
|
+
await runWithVersionCheck(async () => {
|
|
447
|
+
await syncComponents({
|
|
448
|
+
force: options.force
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// SHORTCUTS - Top-level convenient commands
|
|
454
|
+
sliceClient
|
|
455
|
+
.command("get [components...]")
|
|
456
|
+
.description("Quick install components from registry")
|
|
457
|
+
.option("-f, --force", "Force overwrite existing components")
|
|
458
|
+
.option("-s, --service", "Install Service components instead of Visual")
|
|
459
|
+
.action(async (components, options) => {
|
|
460
|
+
await runWithVersionCheck(async () => {
|
|
461
|
+
if (!components || components.length === 0) {
|
|
462
|
+
Print.info("Use 'slice registry list' to see available components");
|
|
463
|
+
Print.commandExample("Get multiple components", "slice get Button Card Input");
|
|
464
|
+
Print.commandExample("Get service component", "slice get FetchManager --service");
|
|
465
|
+
Print.commandExample("Browse components", "slice browse");
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
await getComponent(components, {
|
|
470
|
+
force: options.force,
|
|
471
|
+
service: options.service
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
sliceClient
|
|
477
|
+
.command("browse")
|
|
478
|
+
.description("Quick browse available components")
|
|
479
|
+
.action(async () => {
|
|
480
|
+
await runWithVersionCheck(async () => {
|
|
481
|
+
await listRemoteComponents();
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
sliceClient
|
|
486
|
+
.command("sync")
|
|
487
|
+
.description("Quick sync local components to latest versions")
|
|
488
|
+
.option("-f, --force", "Force update without confirmation")
|
|
489
|
+
.action(async (options) => {
|
|
490
|
+
await runWithVersionCheck(async () => {
|
|
491
|
+
await syncComponents({
|
|
492
|
+
force: options.force
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// LIST COMMAND - Quick shortcut for listing local components
|
|
498
|
+
sliceClient
|
|
499
|
+
.command("list")
|
|
500
|
+
.description("Quick list all local components (alias for component list)")
|
|
501
|
+
.action(async () => {
|
|
502
|
+
await runWithVersionCheck(() => {
|
|
503
|
+
listComponents();
|
|
504
|
+
return Promise.resolve();
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// UPDATE COMMAND
|
|
509
|
+
sliceClient
|
|
510
|
+
.command("update")
|
|
511
|
+
.alias("upgrade")
|
|
512
|
+
.description("Update CLI and framework to latest versions")
|
|
513
|
+
.option("-y, --yes", "Skip confirmation and update all packages automatically")
|
|
514
|
+
.option("--cli", "Update only the Slice.js CLI")
|
|
515
|
+
.option("-f, --framework", "Update only the Slice.js Framework")
|
|
516
|
+
.action(async (options) => {
|
|
517
|
+
await updateManager.checkAndPromptUpdates(options);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
// DOCTOR COMMAND - Diagnose project issues
|
|
521
|
+
sliceClient
|
|
522
|
+
.command("doctor")
|
|
523
|
+
.alias("diagnose")
|
|
524
|
+
.description("Run diagnostics to check project health")
|
|
525
|
+
.action(async () => {
|
|
526
|
+
await runWithVersionCheck(async () => {
|
|
527
|
+
await runDiagnostics();
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Enhanced help
|
|
532
|
+
sliceClient
|
|
533
|
+
.option("--no-version-check", "Skip version check for this command")
|
|
534
|
+
.configureHelp({
|
|
535
|
+
sortSubcommands: true,
|
|
536
|
+
subcommandTerm: (cmd) => cmd.name() + ' ' + cmd.usage()
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
// Custom help - SIMPLIFICADO para development only
|
|
541
|
+
sliceClient.addHelpText('after', `
|
|
542
|
+
Common Usage Examples:
|
|
543
|
+
slice init - Initialize new Slice.js project
|
|
544
|
+
slice dev - Start development server
|
|
545
|
+
slice build - Build production output (bundles + dist)
|
|
546
|
+
slice start - Start production server
|
|
547
|
+
slice get Button Card Input - Install Visual components from registry
|
|
548
|
+
slice get FetchManager -s - Install Service component from registry
|
|
549
|
+
slice browse - Browse all available components
|
|
550
|
+
slice sync - Update local components to latest versions
|
|
551
|
+
slice component create - Create new local component
|
|
552
|
+
slice list - List all local components
|
|
531
553
|
slice doctor - Run project diagnostics
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
•
|
|
554
|
+
slice types generate - Generate TypeScript typings for slice.build
|
|
555
|
+
|
|
556
|
+
Command Categories:
|
|
557
|
+
• init, dev, start - Project lifecycle (development only)
|
|
558
|
+
• get, browse, sync, list - Quick shortcuts
|
|
536
559
|
• component <cmd> - Local component management
|
|
537
560
|
• registry <cmd> - Official repository operations
|
|
561
|
+
• types generate - Type declarations from static props
|
|
538
562
|
• version, update, doctor - Maintenance commands
|
|
539
|
-
|
|
540
|
-
Development Workflow:
|
|
541
|
-
• slice init - Initialize project
|
|
542
|
-
• slice dev - Start development server (serves from /src)
|
|
543
|
-
• slice build - Build production output to /dist (includes bundles)
|
|
544
|
-
• slice start - Serve production build from /dist
|
|
545
|
-
|
|
546
|
-
More info: https://slice-js-docs.vercel.app/
|
|
547
|
-
`);
|
|
548
|
-
|
|
549
|
-
// Default action with better messaging
|
|
550
|
-
if (!process.argv.slice(2).length) {
|
|
551
|
-
Print.newLine();
|
|
552
|
-
Print.info("Start with: slice init");
|
|
553
|
-
Print.commandExample("Development", "slice dev");
|
|
554
|
-
Print.commandExample("View available components", "slice browse");
|
|
555
|
-
Print.info("Use 'slice --help' for full help");
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Error handling for unknown commands
|
|
559
|
-
program.on('command:*', () => {
|
|
560
|
-
Print.error('Invalid command. See available commands above');
|
|
561
|
-
Print.info("Use 'slice --help' for help");
|
|
562
|
-
process.exit(1);
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
// HELP Command
|
|
566
|
-
const helpCommand = sliceClient.command("help").description("Display help information for Slice.js CLI").action(() => {
|
|
567
|
-
sliceClient.outputHelp();
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
program.parse();
|
|
563
|
+
|
|
564
|
+
Development Workflow:
|
|
565
|
+
• slice init - Initialize project
|
|
566
|
+
• slice dev - Start development server (serves from /src)
|
|
567
|
+
• slice build - Build production output to /dist (includes bundles)
|
|
568
|
+
• slice start - Serve production build from /dist
|
|
569
|
+
|
|
570
|
+
More info: https://slice-js-docs.vercel.app/
|
|
571
|
+
`);
|
|
572
|
+
|
|
573
|
+
// Default action with better messaging
|
|
574
|
+
if (!process.argv.slice(2).length) {
|
|
575
|
+
Print.newLine();
|
|
576
|
+
Print.info("Start with: slice init");
|
|
577
|
+
Print.commandExample("Development", "slice dev");
|
|
578
|
+
Print.commandExample("View available components", "slice browse");
|
|
579
|
+
Print.info("Use 'slice --help' for full help");
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Error handling for unknown commands
|
|
583
|
+
program.on('command:*', () => {
|
|
584
|
+
Print.error('Invalid command. See available commands above');
|
|
585
|
+
Print.info("Use 'slice --help' for help");
|
|
586
|
+
process.exit(1);
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// HELP Command
|
|
590
|
+
const helpCommand = sliceClient.command("help").description("Display help information for Slice.js CLI").action(() => {
|
|
591
|
+
sliceClient.outputHelp();
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
program.parse();
|