slicejs-cli 3.6.0 → 3.6.2
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 +47 -11
- package/client.js +10 -7
- package/commands/buildProduction/buildProduction.js +6 -3
- package/commands/doctor/doctor.js +1 -2
- package/commands/init/init.js +97 -28
- package/commands/utils/PackageManager.js +11 -11
- package/commands/utils/sliceScripts.js +15 -13
- package/package.json +5 -3
- package/post.js +5 -3
package/README.md
CHANGED
|
@@ -70,6 +70,38 @@ so each project keeps its pinned CLI version.
|
|
|
70
70
|
|
|
71
71
|
## Main commands
|
|
72
72
|
|
|
73
|
+
Inside initialized projects, prefer package scripts (`pnpm run ...`, `npm run ...`)
|
|
74
|
+
over direct binary calls.
|
|
75
|
+
|
|
76
|
+
Common script workflow:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pnpm run dev
|
|
80
|
+
pnpm run build
|
|
81
|
+
pnpm run start
|
|
82
|
+
pnpm run browse
|
|
83
|
+
pnpm run get -- Button
|
|
84
|
+
pnpm run sync
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Alternative with local devDependency resolution:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pnpm exec slice dev
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If `slicejs-cli` is installed globally, `slice` can be executed directly from PATH.
|
|
94
|
+
|
|
95
|
+
For pnpm v10+, if build scripts are restricted, configure `allowBuilds` in
|
|
96
|
+
`pnpm-workspace.yaml`:
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
allowBuilds:
|
|
100
|
+
slicejs-cli: true
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`slice init --pm pnpm` now writes this automatically.
|
|
104
|
+
|
|
73
105
|
| Command | Description |
|
|
74
106
|
|---------|-------------|
|
|
75
107
|
| `slice init` | Initialize a Slice.js project |
|
|
@@ -89,17 +121,21 @@ When you install `slicejs-cli`, the `postinstall` script automatically configure
|
|
|
89
121
|
```json
|
|
90
122
|
{
|
|
91
123
|
"scripts": {
|
|
92
|
-
"slice:
|
|
93
|
-
"slice:
|
|
94
|
-
"slice:
|
|
95
|
-
"slice:
|
|
96
|
-
"slice:
|
|
97
|
-
"slice:
|
|
98
|
-
"slice:
|
|
99
|
-
"slice:
|
|
100
|
-
"slice:
|
|
101
|
-
"slice:
|
|
102
|
-
"slice:
|
|
124
|
+
"slice:init": "node ./node_modules/slicejs-cli/client.js init",
|
|
125
|
+
"slice:dev": "node ./node_modules/slicejs-cli/client.js dev",
|
|
126
|
+
"slice:build": "node ./node_modules/slicejs-cli/client.js build",
|
|
127
|
+
"slice:start": "node ./node_modules/slicejs-cli/client.js start",
|
|
128
|
+
"slice:create": "node ./node_modules/slicejs-cli/client.js component create",
|
|
129
|
+
"slice:list": "node ./node_modules/slicejs-cli/client.js component list",
|
|
130
|
+
"slice:delete": "node ./node_modules/slicejs-cli/client.js component delete",
|
|
131
|
+
"slice:get": "node ./node_modules/slicejs-cli/client.js get",
|
|
132
|
+
"slice:browse": "node ./node_modules/slicejs-cli/client.js browse",
|
|
133
|
+
"slice:sync": "node ./node_modules/slicejs-cli/client.js sync",
|
|
134
|
+
"slice:doctor": "node ./node_modules/slicejs-cli/client.js doctor",
|
|
135
|
+
"slice:version": "node ./node_modules/slicejs-cli/client.js version",
|
|
136
|
+
"slice:help": "node ./node_modules/slicejs-cli/client.js --help",
|
|
137
|
+
"slice:update": "node ./node_modules/slicejs-cli/client.js update",
|
|
138
|
+
"slice:types": "node ./node_modules/slicejs-cli/client.js types generate"
|
|
103
139
|
}
|
|
104
140
|
}
|
|
105
141
|
```
|
package/client.js
CHANGED
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
detectPackageManager,
|
|
32
32
|
getAvailablePackageManagers,
|
|
33
33
|
isPackageManagerAvailable,
|
|
34
|
+
resolvePackageManager,
|
|
35
|
+
runScriptCommand,
|
|
34
36
|
SUPPORTED_PACKAGE_MANAGERS
|
|
35
37
|
} from './commands/utils/PackageManager.js';
|
|
36
38
|
import { SLICE_SCRIPTS } from './commands/utils/sliceScripts.js';
|
|
@@ -103,7 +105,7 @@ sliceClient
|
|
|
103
105
|
.command("init")
|
|
104
106
|
.description("Initialize a new Slice.js project")
|
|
105
107
|
.option("-y, --yes [name]", "Skip prompts and initialize with project name")
|
|
106
|
-
.option("--pm <packageManager>", "Package manager to use (
|
|
108
|
+
.option("--pm <packageManager>", "Package manager to use (pnpm or npm). Auto-detected when omitted")
|
|
107
109
|
.action(async (options) => {
|
|
108
110
|
let projectName = 'my-slice-app';
|
|
109
111
|
if (options.yes) {
|
|
@@ -150,7 +152,7 @@ sliceClient
|
|
|
150
152
|
} else if (!options.yes) {
|
|
151
153
|
const available = getAvailablePackageManagers();
|
|
152
154
|
if (available.length === 0) {
|
|
153
|
-
Print.error('No package manager found (
|
|
155
|
+
Print.error('No package manager found (pnpm or npm). Install one and retry.');
|
|
154
156
|
return;
|
|
155
157
|
}
|
|
156
158
|
const { pm } = await inquirer.prompt([
|
|
@@ -165,9 +167,9 @@ sliceClient
|
|
|
165
167
|
packageManager = pm;
|
|
166
168
|
} else {
|
|
167
169
|
const available = getAvailablePackageManagers();
|
|
168
|
-
packageManager = available.includes('
|
|
170
|
+
packageManager = available.includes('pnpm') ? 'pnpm' : available[0];
|
|
169
171
|
if (!packageManager) {
|
|
170
|
-
Print.error('No package manager found (
|
|
172
|
+
Print.error('No package manager found (pnpm or npm). Install one and retry.');
|
|
171
173
|
return;
|
|
172
174
|
}
|
|
173
175
|
}
|
|
@@ -638,6 +640,7 @@ sliceClient
|
|
|
638
640
|
|
|
639
641
|
const projectRoot = getProjectRoot(import.meta.url);
|
|
640
642
|
const pkgPath = path.join(projectRoot, 'package.json');
|
|
643
|
+
const packageManager = resolvePackageManager(projectRoot).name;
|
|
641
644
|
|
|
642
645
|
// Shared with post.js and slice init — see commands/utils/sliceScripts.js
|
|
643
646
|
const sliceScripts = SLICE_SCRIPTS;
|
|
@@ -665,12 +668,12 @@ sliceClient
|
|
|
665
668
|
}
|
|
666
669
|
|
|
667
670
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2), 'utf-8');
|
|
668
|
-
console.log(`✅ slicejs-cli installed successfully. Added ${addedCount}
|
|
669
|
-
console.log(
|
|
671
|
+
console.log(`✅ slicejs-cli installed successfully. Added ${addedCount} package scripts to package.json.`);
|
|
672
|
+
console.log(` Run: ${runScriptCommand(packageManager, 'slice:dev')}`);
|
|
670
673
|
} catch (err) {
|
|
671
674
|
console.log('✅ slicejs-cli installed successfully.');
|
|
672
675
|
console.log(' Could not auto-configure scripts:', err.message);
|
|
673
|
-
console.log(
|
|
676
|
+
console.log(` Configure scripts manually and run: ${runScriptCommand(packageManager, 'slice:dev')}`);
|
|
674
677
|
}
|
|
675
678
|
});
|
|
676
679
|
|
|
@@ -6,7 +6,8 @@ import { minify as terserMinify } from 'terser';
|
|
|
6
6
|
import { minify } from 'html-minifier-terser';
|
|
7
7
|
import CleanCSS from 'clean-css';
|
|
8
8
|
import Print from '../Print.js';
|
|
9
|
-
import { getSrcPath, getDistPath, getConfigPath } from '../utils/PathHelper.js';
|
|
9
|
+
import { getSrcPath, getDistPath, getConfigPath, getProjectRoot } from '../utils/PathHelper.js';
|
|
10
|
+
import { resolvePackageManager, runScriptCommand } from '../utils/PackageManager.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Loads configuration from sliceConfig.json
|
|
@@ -441,6 +442,7 @@ async function analyzeBuild() {
|
|
|
441
442
|
*/
|
|
442
443
|
export default async function buildProduction(options = {}) {
|
|
443
444
|
const startTime = Date.now();
|
|
445
|
+
const packageManager = resolvePackageManager(getProjectRoot(import.meta.url)).name;
|
|
444
446
|
|
|
445
447
|
try {
|
|
446
448
|
Print.title('🔨 Building Slice.js project for production...');
|
|
@@ -483,7 +485,7 @@ export default async function buildProduction(options = {}) {
|
|
|
483
485
|
Print.info('Your optimized project is ready in the /dist directory');
|
|
484
486
|
Print.newLine();
|
|
485
487
|
Print.info('Next steps:');
|
|
486
|
-
console.log(
|
|
488
|
+
console.log(` • Use "${runScriptCommand(packageManager, 'start')}" to test the production build`);
|
|
487
489
|
console.log(' • All Slice.js components and architecture preserved');
|
|
488
490
|
|
|
489
491
|
return true;
|
|
@@ -499,6 +501,7 @@ export default async function buildProduction(options = {}) {
|
|
|
499
501
|
*/
|
|
500
502
|
export async function serveProductionBuild(port) {
|
|
501
503
|
try {
|
|
504
|
+
const packageManager = resolvePackageManager(getProjectRoot(import.meta.url)).name;
|
|
502
505
|
const config = loadConfig();
|
|
503
506
|
const defaultPort = config?.server?.port || 3001;
|
|
504
507
|
const finalPort = port || defaultPort;
|
|
@@ -533,7 +536,7 @@ export async function serveProductionBuild(port) {
|
|
|
533
536
|
Print.success(`Production preview server running at http://localhost:${finalPort}`);
|
|
534
537
|
Print.info('Press Ctrl+C to stop the server');
|
|
535
538
|
Print.info('This server previews your production build from /dist');
|
|
536
|
-
Print.warning(
|
|
539
|
+
Print.warning(`This is a preview server - use "${runScriptCommand(packageManager, 'start')}" for the full production server`);
|
|
537
540
|
});
|
|
538
541
|
|
|
539
542
|
} catch (error) {
|
|
@@ -154,8 +154,7 @@ export async function checkPackageManagerSetup(projectRoot = getProjectRoot(impo
|
|
|
154
154
|
|
|
155
155
|
const LOCKFILE_PM = {
|
|
156
156
|
'package-lock.json': 'npm',
|
|
157
|
-
'pnpm-lock.yaml': 'pnpm'
|
|
158
|
-
'yarn.lock': 'yarn'
|
|
157
|
+
'pnpm-lock.yaml': 'pnpm'
|
|
159
158
|
};
|
|
160
159
|
const lockfiles = [];
|
|
161
160
|
for (const lockfile of Object.keys(LOCKFILE_PM)) {
|
package/commands/init/init.js
CHANGED
|
@@ -32,6 +32,61 @@ async function fetchLatestVersion(packageName) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function getRunningCliVersion() {
|
|
36
|
+
try {
|
|
37
|
+
const cliRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
38
|
+
const cliPkg = fs.readJsonSync(path.join(cliRoot, 'package.json'));
|
|
39
|
+
return typeof cliPkg.version === 'string' ? cliPkg.version : null;
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function ensurePnpmAllowBuilds(projectRoot) {
|
|
46
|
+
const workspacePath = path.join(projectRoot, 'pnpm-workspace.yaml');
|
|
47
|
+
const allowBuildLine = ' slicejs-cli: true';
|
|
48
|
+
|
|
49
|
+
if (!(await fs.pathExists(workspacePath))) {
|
|
50
|
+
await fs.writeFile(workspacePath, `allowBuilds:\n${allowBuildLine}\n`, 'utf8');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const raw = await fs.readFile(workspacePath, 'utf8');
|
|
55
|
+
const lines = raw.split(/\r?\n/);
|
|
56
|
+
const allowIdx = lines.findIndex((line) => /^allowBuilds:\s*$/.test(line));
|
|
57
|
+
|
|
58
|
+
if (allowIdx === -1) {
|
|
59
|
+
const suffix = raw.endsWith('\n') ? '' : '\n';
|
|
60
|
+
await fs.writeFile(workspacePath, `${raw}${suffix}allowBuilds:\n${allowBuildLine}\n`, 'utf8');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let blockEnd = lines.length;
|
|
65
|
+
for (let i = allowIdx + 1; i < lines.length; i++) {
|
|
66
|
+
const line = lines[i];
|
|
67
|
+
if (!line.trim()) continue;
|
|
68
|
+
if (!/^\s/.test(line)) {
|
|
69
|
+
blockEnd = i;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let found = false;
|
|
75
|
+
for (let i = allowIdx + 1; i < blockEnd; i++) {
|
|
76
|
+
if (/^\s+slicejs-cli\s*:/.test(lines[i])) {
|
|
77
|
+
lines[i] = allowBuildLine;
|
|
78
|
+
found = true;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!found) {
|
|
84
|
+
lines.splice(blockEnd, 0, allowBuildLine);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await fs.writeFile(workspacePath, `${lines.join('\n').replace(/\n*$/, '\n')}`, 'utf8');
|
|
88
|
+
}
|
|
89
|
+
|
|
35
90
|
// Create the project manifest BEFORE any install runs. Without a package.json in
|
|
36
91
|
// the project folder, npm/pnpm walk up the directory tree looking for the nearest
|
|
37
92
|
// manifest and anchor node_modules (and the dependency entry) OUTSIDE the project.
|
|
@@ -93,6 +148,10 @@ export default async function initializeProject(options = {}) {
|
|
|
93
148
|
const packageManager = options.packageManager
|
|
94
149
|
|| resolvePackageManager(projectRoot).name;
|
|
95
150
|
|
|
151
|
+
if (packageManager === 'pnpm') {
|
|
152
|
+
await ensurePnpmAllowBuilds(projectRoot);
|
|
153
|
+
}
|
|
154
|
+
|
|
96
155
|
// 0. CREATE PROJECT MANIFEST FIRST — must exist before any install so the
|
|
97
156
|
// package manager anchors node_modules inside the project folder.
|
|
98
157
|
await ensureProjectManifest(projectRoot, packageManager);
|
|
@@ -103,6 +162,9 @@ export default async function initializeProject(options = {}) {
|
|
|
103
162
|
let sliceBaseDir;
|
|
104
163
|
try {
|
|
105
164
|
latestVersion = await fetchLatestVersion('slicejs-web-framework');
|
|
165
|
+
const frameworkPackage = latestVersion
|
|
166
|
+
? `slicejs-web-framework@${latestVersion}`
|
|
167
|
+
: 'slicejs-web-framework';
|
|
106
168
|
const installedPkgPath = getPath(import.meta.url, 'node_modules', 'slicejs-web-framework', 'package.json');
|
|
107
169
|
let installed = null;
|
|
108
170
|
if (await fs.pathExists(installedPkgPath)) {
|
|
@@ -110,11 +172,7 @@ export default async function initializeProject(options = {}) {
|
|
|
110
172
|
installed = pkg.version;
|
|
111
173
|
}
|
|
112
174
|
if (!installed || (latestVersion && installed !== latestVersion)) {
|
|
113
|
-
|
|
114
|
-
// resolves it under its own policies (e.g. pnpm minimumReleaseAge
|
|
115
|
-
// quarantines versions younger than the configured age — pinning
|
|
116
|
-
// the registry's freshest version would make resolution fail).
|
|
117
|
-
execSync(installCommand(packageManager, 'slicejs-web-framework'), { cwd: projectRoot, stdio: 'inherit' });
|
|
175
|
+
execSync(installCommand(packageManager, frameworkPackage), { cwd: projectRoot, stdio: 'inherit' });
|
|
118
176
|
}
|
|
119
177
|
if (await fs.pathExists(installedPkgPath)) {
|
|
120
178
|
const pkg = await fs.readJson(installedPkgPath);
|
|
@@ -145,13 +203,24 @@ export default async function initializeProject(options = {}) {
|
|
|
145
203
|
const cliSpinner = ora('Installing slicejs-cli as devDependency...').start();
|
|
146
204
|
try {
|
|
147
205
|
const cliPkgPath = getPath(import.meta.url, 'node_modules', 'slicejs-cli', 'package.json');
|
|
148
|
-
|
|
149
|
-
|
|
206
|
+
const currentCliVersion = getRunningCliVersion();
|
|
207
|
+
const cliPackage = currentCliVersion
|
|
208
|
+
? `slicejs-cli@${currentCliVersion}`
|
|
209
|
+
: 'slicejs-cli';
|
|
210
|
+
|
|
211
|
+
let installedCliVersion = null;
|
|
212
|
+
if (await fs.pathExists(cliPkgPath)) {
|
|
213
|
+
const pkg = await fs.readJson(cliPkgPath);
|
|
214
|
+
installedCliVersion = pkg.version;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!installedCliVersion || (currentCliVersion && installedCliVersion !== currentCliVersion)) {
|
|
218
|
+
execSync(installCommand(packageManager, cliPackage, { dev: true }), { cwd: projectRoot, stdio: 'inherit' });
|
|
150
219
|
}
|
|
151
220
|
cliSpinner.succeed('slicejs-cli installed locally');
|
|
152
221
|
} catch (err) {
|
|
153
222
|
cliSpinner.warn('Could not install slicejs-cli locally — scripts will use the global CLI');
|
|
154
|
-
Print.info(`You can add it later with: ${installCommand(packageManager,
|
|
223
|
+
Print.info(`You can add it later with: ${installCommand(packageManager, `slicejs-cli@${getRunningCliVersion() || 'latest'}`, { dev: true })}`);
|
|
155
224
|
}
|
|
156
225
|
|
|
157
226
|
// These derive from sliceBaseDir (which comes from npm install or fallback),
|
|
@@ -256,20 +325,20 @@ export default async function initializeProject(options = {}) {
|
|
|
256
325
|
componentsSpinner.succeed(`All ${successful} Visual components installed successfully`);
|
|
257
326
|
} else if (successful > 0) {
|
|
258
327
|
componentsSpinner.warn(`${successful} components installed, ${failed} failed`);
|
|
259
|
-
Print.info(
|
|
328
|
+
Print.info(`You can install failed components later using "${packageManager} run get -- <component-name>"`);
|
|
260
329
|
} else {
|
|
261
330
|
componentsSpinner.fail('Failed to install Visual components');
|
|
262
331
|
}
|
|
263
332
|
} else {
|
|
264
333
|
componentsSpinner.warn('No Visual components found in registry');
|
|
265
|
-
Print.info(
|
|
334
|
+
Print.info(`You can add components later using "${packageManager} run get -- <component-name>"`);
|
|
266
335
|
}
|
|
267
336
|
|
|
268
337
|
} catch (error) {
|
|
269
338
|
componentsSpinner.fail('Could not download Visual components from official repository');
|
|
270
339
|
Print.error(`Repository error: ${error.message}`);
|
|
271
340
|
Print.info('Project initialized without Visual components');
|
|
272
|
-
Print.info(
|
|
341
|
+
Print.info(`You can add them later using "${packageManager} run get -- <component-name>"`);
|
|
273
342
|
}
|
|
274
343
|
|
|
275
344
|
// 3b. DOWNLOAD STARTER SERVICE COMPONENTS FROM OFFICIAL REPOSITORY
|
|
@@ -295,7 +364,7 @@ export default async function initializeProject(options = {}) {
|
|
|
295
364
|
serviceSpinner.succeed(`All ${successful} Service components installed successfully`);
|
|
296
365
|
} else if (successful > 0) {
|
|
297
366
|
serviceSpinner.warn(`${successful} Service components installed, ${failed} failed`);
|
|
298
|
-
Print.info(
|
|
367
|
+
Print.info(`You can install failed components later using "${packageManager} run get -- <component-name>"`);
|
|
299
368
|
} else {
|
|
300
369
|
serviceSpinner.fail('Failed to install Service components');
|
|
301
370
|
}
|
|
@@ -305,7 +374,7 @@ export default async function initializeProject(options = {}) {
|
|
|
305
374
|
} catch (error) {
|
|
306
375
|
serviceSpinner.fail('Could not download Service components from official repository');
|
|
307
376
|
Print.error(`Repository error: ${error.message}`);
|
|
308
|
-
Print.info(
|
|
377
|
+
Print.info(`You can add them later using "${packageManager} run get -- <component-name>"`);
|
|
309
378
|
}
|
|
310
379
|
|
|
311
380
|
// 4. CONFIGURE SCRIPTS IN PROJECT package.json
|
|
@@ -330,25 +399,25 @@ export default async function initializeProject(options = {}) {
|
|
|
330
399
|
pkg.scripts = pkg.scripts || {};
|
|
331
400
|
pkg.dependencies = pkg.dependencies || {};
|
|
332
401
|
|
|
333
|
-
//
|
|
334
|
-
pkg.scripts['dev'] = 'slice
|
|
335
|
-
pkg.scripts['build'] = 'slice
|
|
336
|
-
pkg.scripts['start'] = 'slice
|
|
402
|
+
// Main scripts (local CLI path, no global launcher dependency)
|
|
403
|
+
pkg.scripts['dev'] = SLICE_SCRIPTS['slice:dev'];
|
|
404
|
+
pkg.scripts['build'] = SLICE_SCRIPTS['slice:build'];
|
|
405
|
+
pkg.scripts['start'] = SLICE_SCRIPTS['slice:start'];
|
|
337
406
|
|
|
338
407
|
// Component management
|
|
339
|
-
pkg.scripts['component:create'] = 'slice
|
|
340
|
-
pkg.scripts['component:list'] = 'slice
|
|
341
|
-
pkg.scripts['component:delete'] = 'slice
|
|
408
|
+
pkg.scripts['component:create'] = SLICE_SCRIPTS['slice:create'];
|
|
409
|
+
pkg.scripts['component:list'] = SLICE_SCRIPTS['slice:list'];
|
|
410
|
+
pkg.scripts['component:delete'] = SLICE_SCRIPTS['slice:delete'];
|
|
342
411
|
|
|
343
|
-
//
|
|
344
|
-
pkg.scripts['get'] = 'slice
|
|
345
|
-
pkg.scripts['browse'] = 'slice
|
|
346
|
-
pkg.scripts['sync'] = 'slice
|
|
412
|
+
// Registry shortcuts
|
|
413
|
+
pkg.scripts['get'] = SLICE_SCRIPTS['slice:get'];
|
|
414
|
+
pkg.scripts['browse'] = SLICE_SCRIPTS['slice:browse'];
|
|
415
|
+
pkg.scripts['sync'] = SLICE_SCRIPTS['slice:sync'];
|
|
347
416
|
|
|
348
417
|
// slice:* namespaced set — shared with post.js and `slice postinstall`
|
|
349
418
|
// (commands/utils/sliceScripts.js) so the three never drift apart.
|
|
350
419
|
Object.assign(pkg.scripts, SLICE_SCRIPTS);
|
|
351
|
-
pkg.scripts['run'] = 'slice
|
|
420
|
+
pkg.scripts['run'] = SLICE_SCRIPTS['slice:dev'];
|
|
352
421
|
|
|
353
422
|
// Module configuration
|
|
354
423
|
pkg.type = 'module';
|
|
@@ -378,9 +447,9 @@ export default async function initializeProject(options = {}) {
|
|
|
378
447
|
Print.title('Next steps:');
|
|
379
448
|
console.log(` cd ${projectName}`);
|
|
380
449
|
console.log(` ${packageManager} run dev - Start development server`);
|
|
381
|
-
console.log(
|
|
382
|
-
console.log(
|
|
383
|
-
console.log(
|
|
450
|
+
console.log(` ${packageManager} run browse - View available components`);
|
|
451
|
+
console.log(` ${packageManager} run get -- Button - Install specific components`);
|
|
452
|
+
console.log(` ${packageManager} run sync - Update all components to latest versions`);
|
|
384
453
|
|
|
385
454
|
} catch (error) {
|
|
386
455
|
Print.error('Unexpected error initializing project:', error.message);
|
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
// commands/utils/PackageManager.js
|
|
2
2
|
//
|
|
3
|
-
// Package manager detection and command building (
|
|
3
|
+
// Package manager detection and command building (pnpm / npm).
|
|
4
4
|
// Resolution priority for an existing project:
|
|
5
5
|
// 1. "packageManager" field in the project package.json (corepack convention)
|
|
6
6
|
// 2. Lockfile present at the project root
|
|
7
7
|
// 3. npm_config_user_agent (set when the CLI runs via `npx` / `pnpm dlx` / a PM script)
|
|
8
8
|
// 4. The only PM binary available on PATH (if exactly one)
|
|
9
9
|
// When everything is ambiguous, detectPackageManager() returns null so callers
|
|
10
|
-
// can prompt the user (interactive init) or fall back to
|
|
10
|
+
// can prompt the user (interactive init) or fall back to pnpm (non-interactive).
|
|
11
11
|
|
|
12
12
|
import fs from 'fs-extra'
|
|
13
13
|
import path from 'path'
|
|
14
14
|
import { spawnSync } from 'node:child_process'
|
|
15
15
|
|
|
16
|
-
export const SUPPORTED_PACKAGE_MANAGERS = ['
|
|
16
|
+
export const SUPPORTED_PACKAGE_MANAGERS = ['pnpm', 'npm']
|
|
17
17
|
|
|
18
18
|
const LOCKFILES = {
|
|
19
19
|
'pnpm-lock.yaml': 'pnpm',
|
|
20
|
-
'package-lock.json': 'npm'
|
|
21
|
-
'yarn.lock': 'yarn'
|
|
20
|
+
'package-lock.json': 'npm'
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
export function parseUserAgent(userAgent = process.env.npm_config_user_agent) {
|
|
25
24
|
if (!userAgent) return null
|
|
26
|
-
const match = userAgent.match(/^(npm|pnpm
|
|
25
|
+
const match = userAgent.match(/^(npm|pnpm)\/(\S+)/)
|
|
27
26
|
if (!match) return null
|
|
28
27
|
return { name: match[1], version: match[2], source: 'user-agent' }
|
|
29
28
|
}
|
|
@@ -34,7 +33,7 @@ export function fromPackageManagerField(projectRoot) {
|
|
|
34
33
|
if (!fs.pathExistsSync(pkgPath)) return null
|
|
35
34
|
const pkg = fs.readJsonSync(pkgPath)
|
|
36
35
|
if (typeof pkg.packageManager !== 'string') return null
|
|
37
|
-
const match = pkg.packageManager.match(/^(npm|pnpm
|
|
36
|
+
const match = pkg.packageManager.match(/^(npm|pnpm)@(\S+)/)
|
|
38
37
|
if (!match) return null
|
|
39
38
|
return { name: match[1], version: match[2], source: 'package-manager-field' }
|
|
40
39
|
} catch {
|
|
@@ -109,7 +108,7 @@ export function detectPackageManager(projectRoot, { userAgent = process.env.npm_
|
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
/**
|
|
112
|
-
* Non-interactive resolution: detection first, then
|
|
111
|
+
* Non-interactive resolution: detection first, then pnpm if available,
|
|
113
112
|
* then whatever binary exists. Never returns null so update/doctor flows
|
|
114
113
|
* always have a usable PM name (commands fail later with a clear error
|
|
115
114
|
* if no PM is actually installed).
|
|
@@ -119,16 +118,17 @@ export function resolvePackageManager(projectRoot, options = {}) {
|
|
|
119
118
|
if (detected) return detected
|
|
120
119
|
|
|
121
120
|
const available = getAvailablePackageManagers()
|
|
121
|
+
if (available.includes('pnpm')) return { name: 'pnpm', version: null, source: 'fallback' }
|
|
122
122
|
if (available.includes('npm')) return { name: 'npm', version: null, source: 'fallback' }
|
|
123
123
|
if (available.length > 0) return { name: available[0], version: null, source: 'fallback' }
|
|
124
|
-
return { name: '
|
|
124
|
+
return { name: 'pnpm', version: null, source: 'fallback (none detected)' }
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export function installCommand(pmName, packages, { dev = false, global: isGlobal = false } = {}) {
|
|
128
128
|
const pkgs = Array.isArray(packages) ? packages.join(' ') : packages
|
|
129
129
|
const flags = [isGlobal ? '-g' : '', dev ? '-D' : ''].filter(Boolean).join(' ')
|
|
130
130
|
const flagSuffix = flags ? ` ${flags}` : ''
|
|
131
|
-
if (pmName === 'pnpm'
|
|
131
|
+
if (pmName === 'pnpm') {
|
|
132
132
|
return `${pmName} add${flagSuffix} ${pkgs}`
|
|
133
133
|
}
|
|
134
134
|
return `npm install${flagSuffix} ${pkgs}`
|
|
@@ -137,7 +137,7 @@ export function installCommand(pmName, packages, { dev = false, global: isGlobal
|
|
|
137
137
|
export function uninstallCommand(pmName, packages, { global: isGlobal = false } = {}) {
|
|
138
138
|
const pkgs = Array.isArray(packages) ? packages.join(' ') : packages
|
|
139
139
|
const flagSuffix = isGlobal ? ' -g' : ''
|
|
140
|
-
if (pmName === 'pnpm'
|
|
140
|
+
if (pmName === 'pnpm') {
|
|
141
141
|
return `${pmName} remove${flagSuffix} ${pkgs}`
|
|
142
142
|
}
|
|
143
143
|
return `npm uninstall${flagSuffix} ${pkgs}`
|
|
@@ -5,17 +5,19 @@
|
|
|
5
5
|
// client.js, and `slice init` — so the three can never drift apart (they did:
|
|
6
6
|
// client.js was missing slice:types, and none of them had slice:build).
|
|
7
7
|
export const SLICE_SCRIPTS = {
|
|
8
|
-
'slice:init': '
|
|
9
|
-
'slice:dev': '
|
|
10
|
-
'slice:build': '
|
|
11
|
-
'slice:start': '
|
|
12
|
-
'slice:create': '
|
|
13
|
-
'slice:list': '
|
|
14
|
-
'slice:delete': '
|
|
15
|
-
'slice:get': '
|
|
16
|
-
'slice:browse': '
|
|
17
|
-
'slice:sync': '
|
|
18
|
-
'slice:
|
|
19
|
-
'slice:
|
|
20
|
-
'slice:
|
|
8
|
+
'slice:init': 'node ./node_modules/slicejs-cli/client.js init',
|
|
9
|
+
'slice:dev': 'node ./node_modules/slicejs-cli/client.js dev',
|
|
10
|
+
'slice:build': 'node ./node_modules/slicejs-cli/client.js build',
|
|
11
|
+
'slice:start': 'node ./node_modules/slicejs-cli/client.js start',
|
|
12
|
+
'slice:create': 'node ./node_modules/slicejs-cli/client.js component create',
|
|
13
|
+
'slice:list': 'node ./node_modules/slicejs-cli/client.js component list',
|
|
14
|
+
'slice:delete': 'node ./node_modules/slicejs-cli/client.js component delete',
|
|
15
|
+
'slice:get': 'node ./node_modules/slicejs-cli/client.js get',
|
|
16
|
+
'slice:browse': 'node ./node_modules/slicejs-cli/client.js browse',
|
|
17
|
+
'slice:sync': 'node ./node_modules/slicejs-cli/client.js sync',
|
|
18
|
+
'slice:doctor': 'node ./node_modules/slicejs-cli/client.js doctor',
|
|
19
|
+
'slice:version': 'node ./node_modules/slicejs-cli/client.js version',
|
|
20
|
+
'slice:help': 'node ./node_modules/slicejs-cli/client.js --help',
|
|
21
|
+
'slice:update': 'node ./node_modules/slicejs-cli/client.js update',
|
|
22
|
+
'slice:types': 'node ./node_modules/slicejs-cli/client.js types generate',
|
|
21
23
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slicejs-cli",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.2",
|
|
4
4
|
"description": "Command client for developing web applications with Slice.js framework",
|
|
5
5
|
"main": "client.js",
|
|
6
6
|
"bin": {
|
|
@@ -34,7 +34,9 @@
|
|
|
34
34
|
"slice:sync": "slice sync",
|
|
35
35
|
"slice:version": "slice version",
|
|
36
36
|
"slice:update": "slice update",
|
|
37
|
-
"slice:types": "slice types generate"
|
|
37
|
+
"slice:types": "slice types generate",
|
|
38
|
+
"slice:doctor": "node ./node_modules/slicejs-cli/client.js doctor",
|
|
39
|
+
"slice:help": "node ./node_modules/slicejs-cli/client.js --help"
|
|
38
40
|
},
|
|
39
41
|
"keywords": [
|
|
40
42
|
"framework",
|
|
@@ -69,4 +71,4 @@
|
|
|
69
71
|
"devDependencies": {
|
|
70
72
|
"@playwright/test": "^1.60.0"
|
|
71
73
|
}
|
|
72
|
-
}
|
|
74
|
+
}
|
package/post.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { getProjectRoot, getPath } from './commands/utils/PathHelper.js';
|
|
5
5
|
import { SLICE_SCRIPTS } from './commands/utils/sliceScripts.js';
|
|
6
|
+
import { resolvePackageManager, runScriptCommand } from './commands/utils/PackageManager.js';
|
|
6
7
|
|
|
7
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
9
|
|
|
@@ -21,6 +22,7 @@ if (isGlobal) {
|
|
|
21
22
|
|
|
22
23
|
const projectRoot = getProjectRoot(import.meta.url);
|
|
23
24
|
const pkgPath = getPath(import.meta.url, 'package.json');
|
|
25
|
+
const packageManager = resolvePackageManager(projectRoot).name;
|
|
24
26
|
|
|
25
27
|
const sliceScripts = SLICE_SCRIPTS;
|
|
26
28
|
|
|
@@ -47,12 +49,12 @@ try {
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2), 'utf-8');
|
|
50
|
-
console.log(`✅ slicejs-cli installed successfully. Added ${addedCount}
|
|
51
|
-
console.log(
|
|
52
|
+
console.log(`✅ slicejs-cli installed successfully. Added ${addedCount} package scripts to package.json.`);
|
|
53
|
+
console.log(` Run: ${runScriptCommand(packageManager, 'slice:dev')}`);
|
|
52
54
|
} catch (err) {
|
|
53
55
|
console.log('✅ slicejs-cli installed successfully.');
|
|
54
56
|
console.log(' Could not auto-configure scripts:', err.message);
|
|
55
|
-
console.log(
|
|
57
|
+
console.log(` Configure scripts manually and run: ${runScriptCommand(packageManager, 'slice:dev')}`);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
process.exit(0);
|