slicejs-cli 3.5.1 → 3.6.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 +34 -15
- package/client.js +67 -20
- package/commands/doctor/doctor.js +69 -3
- package/commands/getComponent/getComponent.js +33 -25
- package/commands/init/init.js +106 -28
- package/commands/utils/PackageManager.js +148 -0
- package/commands/utils/VersionChecker.js +6 -4
- package/commands/utils/sliceScripts.js +21 -0
- package/commands/utils/updateManager.js +54 -35
- package/package.json +12 -1
- package/post.js +8 -16
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -29
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -25
- package/.github/pull_request_template.md +0 -22
- package/.github/workflows/ci.yml +0 -43
- package/AGENTS.md +0 -247
- package/CODE_OF_CONDUCT.md +0 -126
- package/ECOSYSTEM.md +0 -9
- package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +0 -182
- package/playwright.config.js +0 -51
- package/tests/build-command-integration.test.js +0 -87
- package/tests/build-production-e2e.test.js +0 -140
- package/tests/builder-edge-cases.test.js +0 -322
- package/tests/bundle-generate-e2e.test.js +0 -115
- package/tests/bundle-generator.test.js +0 -691
- package/tests/bundle-v2-register-output.test.js +0 -470
- package/tests/bundling-dependency-edges.test.js +0 -127
- package/tests/bundling-imports-unit.test.js +0 -267
- package/tests/client-launcher-contract.test.js +0 -211
- package/tests/client-update-flow-contract.test.js +0 -272
- package/tests/commands-component-crud.test.js +0 -102
- package/tests/commands-doctor.test.js +0 -80
- package/tests/commands-version-checker.test.js +0 -37
- package/tests/component-registry-parse.test.js +0 -34
- package/tests/dependency-analyzer.test.js +0 -24
- package/tests/e2e/bundles.spec.js +0 -91
- package/tests/e2e/dependency-scenarios.spec.js +0 -56
- package/tests/e2e/fixtures/components/Service/FetchManager/FetchManager.js +0 -136
- package/tests/e2e/fixtures/components/Service/IndexedDbManager/IndexedDbManager.js +0 -149
- package/tests/e2e/fixtures/components/Service/LocalStorageManager/LocalStorageManager.js +0 -45
- package/tests/e2e/fixtures/components/Visual/Button/Button.css +0 -106
- package/tests/e2e/fixtures/components/Visual/Button/Button.html +0 -5
- package/tests/e2e/fixtures/components/Visual/Button/Button.js +0 -158
- package/tests/e2e/fixtures/components/Visual/Link/Link.js +0 -33
- package/tests/e2e/fixtures/components/Visual/Loading/Loading.css +0 -56
- package/tests/e2e/fixtures/components/Visual/Loading/Loading.html +0 -83
- package/tests/e2e/fixtures/components/Visual/Loading/Loading.js +0 -164
- package/tests/e2e/fixtures/components/Visual/MultiRoute/MultiRoute.js +0 -167
- package/tests/e2e/fixtures/components/Visual/Navbar/Navbar.css +0 -116
- package/tests/e2e/fixtures/components/Visual/Navbar/Navbar.html +0 -44
- package/tests/e2e/fixtures/components/Visual/Navbar/Navbar.js +0 -180
- package/tests/e2e/fixtures/components/Visual/NotFound/NotFound.js +0 -20
- package/tests/e2e/fixtures/components/Visual/Route/Route.js +0 -181
- package/tests/e2e/fixtures/components/registry.json +0 -12
- package/tests/e2e/fixtures/vendor-components.mjs +0 -65
- package/tests/e2e/navigation.spec.js +0 -44
- package/tests/e2e/render.spec.js +0 -34
- package/tests/e2e/serve.mjs +0 -264
- package/tests/e2e/shared-deps.spec.js +0 -61
- package/tests/e2e/unminified.spec.js +0 -33
- package/tests/e2e-serve.test.js +0 -148
- package/tests/fixtures/components.js +0 -8
- package/tests/fixtures/sliceConfig.json +0 -74
- package/tests/getcomponent.test.js +0 -407
- package/tests/helpers/setup.js +0 -102
- package/tests/init-command-contract.test.js +0 -46
- package/tests/local-cli-delegation.test.js +0 -81
- package/tests/path-helper.test.js +0 -206
- package/tests/perf-budget.test.js +0 -86
- package/tests/postinstall-command.test.js +0 -72
- package/tests/types-breakage.test.js +0 -491
- package/tests/types-generator-errors.test.js +0 -361
- package/tests/types-generator.test.js +0 -346
- package/tests/update-manager-notifications.test.js +0 -88
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// commands/utils/PackageManager.js
|
|
2
|
+
//
|
|
3
|
+
// Package manager detection and command building (npm / pnpm / yarn).
|
|
4
|
+
// Resolution priority for an existing project:
|
|
5
|
+
// 1. "packageManager" field in the project package.json (corepack convention)
|
|
6
|
+
// 2. Lockfile present at the project root
|
|
7
|
+
// 3. npm_config_user_agent (set when the CLI runs via `npx` / `pnpm dlx` / a PM script)
|
|
8
|
+
// 4. The only PM binary available on PATH (if exactly one)
|
|
9
|
+
// When everything is ambiguous, detectPackageManager() returns null so callers
|
|
10
|
+
// can prompt the user (interactive init) or fall back to npm (non-interactive).
|
|
11
|
+
|
|
12
|
+
import fs from 'fs-extra'
|
|
13
|
+
import path from 'path'
|
|
14
|
+
import { spawnSync } from 'node:child_process'
|
|
15
|
+
|
|
16
|
+
export const SUPPORTED_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn']
|
|
17
|
+
|
|
18
|
+
const LOCKFILES = {
|
|
19
|
+
'pnpm-lock.yaml': 'pnpm',
|
|
20
|
+
'package-lock.json': 'npm',
|
|
21
|
+
'yarn.lock': 'yarn'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function parseUserAgent(userAgent = process.env.npm_config_user_agent) {
|
|
25
|
+
if (!userAgent) return null
|
|
26
|
+
const match = userAgent.match(/^(npm|pnpm|yarn)\/(\S+)/)
|
|
27
|
+
if (!match) return null
|
|
28
|
+
return { name: match[1], version: match[2], source: 'user-agent' }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function fromPackageManagerField(projectRoot) {
|
|
32
|
+
try {
|
|
33
|
+
const pkgPath = path.join(projectRoot, 'package.json')
|
|
34
|
+
if (!fs.pathExistsSync(pkgPath)) return null
|
|
35
|
+
const pkg = fs.readJsonSync(pkgPath)
|
|
36
|
+
if (typeof pkg.packageManager !== 'string') return null
|
|
37
|
+
const match = pkg.packageManager.match(/^(npm|pnpm|yarn)@(\S+)/)
|
|
38
|
+
if (!match) return null
|
|
39
|
+
return { name: match[1], version: match[2], source: 'package-manager-field' }
|
|
40
|
+
} catch {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function fromLockfile(projectRoot) {
|
|
46
|
+
for (const [lockfile, name] of Object.entries(LOCKFILES)) {
|
|
47
|
+
if (fs.pathExistsSync(path.join(projectRoot, lockfile))) {
|
|
48
|
+
return { name, version: null, source: `lockfile (${lockfile})` }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function runPmBinary(name, args) {
|
|
55
|
+
// On Windows the PM entry points are .cmd shims, which require shell resolution.
|
|
56
|
+
const isWindows = process.platform === 'win32'
|
|
57
|
+
return spawnSync(name, args, {
|
|
58
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
59
|
+
shell: isWindows,
|
|
60
|
+
encoding: 'utf-8'
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function isPackageManagerAvailable(name) {
|
|
65
|
+
try {
|
|
66
|
+
const result = runPmBinary(name, ['--version'])
|
|
67
|
+
return result.status === 0
|
|
68
|
+
} catch {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getPackageManagerVersion(name) {
|
|
74
|
+
try {
|
|
75
|
+
const result = runPmBinary(name, ['--version'])
|
|
76
|
+
if (result.status !== 0) return null
|
|
77
|
+
return (result.stdout || '').toString().trim() || null
|
|
78
|
+
} catch {
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function getAvailablePackageManagers() {
|
|
84
|
+
return SUPPORTED_PACKAGE_MANAGERS.filter(isPackageManagerAvailable)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Detect the package manager for a project.
|
|
89
|
+
* Returns { name, version, source } or null when genuinely ambiguous.
|
|
90
|
+
*/
|
|
91
|
+
export function detectPackageManager(projectRoot, { userAgent = process.env.npm_config_user_agent } = {}) {
|
|
92
|
+
if (projectRoot) {
|
|
93
|
+
const fromField = fromPackageManagerField(projectRoot)
|
|
94
|
+
if (fromField) return fromField
|
|
95
|
+
|
|
96
|
+
const fromLock = fromLockfile(projectRoot)
|
|
97
|
+
if (fromLock) return fromLock
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const fromUa = parseUserAgent(userAgent)
|
|
101
|
+
if (fromUa) return fromUa
|
|
102
|
+
|
|
103
|
+
const available = getAvailablePackageManagers()
|
|
104
|
+
if (available.length === 1) {
|
|
105
|
+
return { name: available[0], version: null, source: 'only available binary' }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Non-interactive resolution: detection first, then npm if available,
|
|
113
|
+
* then whatever binary exists. Never returns null so update/doctor flows
|
|
114
|
+
* always have a usable PM name (commands fail later with a clear error
|
|
115
|
+
* if no PM is actually installed).
|
|
116
|
+
*/
|
|
117
|
+
export function resolvePackageManager(projectRoot, options = {}) {
|
|
118
|
+
const detected = detectPackageManager(projectRoot, options)
|
|
119
|
+
if (detected) return detected
|
|
120
|
+
|
|
121
|
+
const available = getAvailablePackageManagers()
|
|
122
|
+
if (available.includes('npm')) return { name: 'npm', version: null, source: 'fallback' }
|
|
123
|
+
if (available.length > 0) return { name: available[0], version: null, source: 'fallback' }
|
|
124
|
+
return { name: 'npm', version: null, source: 'fallback (none detected)' }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function installCommand(pmName, packages, { dev = false, global: isGlobal = false } = {}) {
|
|
128
|
+
const pkgs = Array.isArray(packages) ? packages.join(' ') : packages
|
|
129
|
+
const flags = [isGlobal ? '-g' : '', dev ? '-D' : ''].filter(Boolean).join(' ')
|
|
130
|
+
const flagSuffix = flags ? ` ${flags}` : ''
|
|
131
|
+
if (pmName === 'pnpm' || pmName === 'yarn') {
|
|
132
|
+
return `${pmName} add${flagSuffix} ${pkgs}`
|
|
133
|
+
}
|
|
134
|
+
return `npm install${flagSuffix} ${pkgs}`
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function uninstallCommand(pmName, packages, { global: isGlobal = false } = {}) {
|
|
138
|
+
const pkgs = Array.isArray(packages) ? packages.join(' ') : packages
|
|
139
|
+
const flagSuffix = isGlobal ? ' -g' : ''
|
|
140
|
+
if (pmName === 'pnpm' || pmName === 'yarn') {
|
|
141
|
+
return `${pmName} remove${flagSuffix} ${pkgs}`
|
|
142
|
+
}
|
|
143
|
+
return `npm uninstall${flagSuffix} ${pkgs}`
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function runScriptCommand(pmName, script) {
|
|
147
|
+
return `${pmName} run ${script}`
|
|
148
|
+
}
|
|
@@ -5,6 +5,7 @@ import path from "path";
|
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import Print from "../Print.js";
|
|
7
7
|
import { getProjectRoot, getPath } from "../utils/PathHelper.js";
|
|
8
|
+
import { resolvePackageManager } from "../utils/PackageManager.js";
|
|
8
9
|
|
|
9
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
|
|
@@ -110,17 +111,18 @@ class VersionChecker {
|
|
|
110
111
|
const frameworkStatus = this.compareVersions(current.framework, latest.framework);
|
|
111
112
|
|
|
112
113
|
if (!silent && (cliStatus === 'outdated' || frameworkStatus === 'outdated')) {
|
|
114
|
+
const pm = resolvePackageManager(getProjectRoot(import.meta.url)).name;
|
|
113
115
|
console.log(''); // Line break
|
|
114
116
|
Print.warning('📦 Available Updates:');
|
|
115
|
-
|
|
117
|
+
|
|
116
118
|
if (cliStatus === 'outdated') {
|
|
117
119
|
console.log(` 🔧 CLI: ${current.cli} → ${latest.cli}`);
|
|
118
|
-
console.log(`
|
|
120
|
+
console.log(` ${pm} update slicejs-cli`);
|
|
119
121
|
}
|
|
120
|
-
|
|
122
|
+
|
|
121
123
|
if (frameworkStatus === 'outdated') {
|
|
122
124
|
console.log(` ⚡ Framework: ${current.framework} → ${latest.framework}`);
|
|
123
|
-
console.log(`
|
|
125
|
+
console.log(` ${pm} update slicejs-web-framework`);
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
console.log(' 📚 Changelog: https://github.com/VKneider/slice.js/releases');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// commands/utils/sliceScripts.js
|
|
2
|
+
//
|
|
3
|
+
// Single source of truth for the slice:* package scripts configured by the CLI.
|
|
4
|
+
// Used by post.js (the postinstall hook), the `slice postinstall` command in
|
|
5
|
+
// client.js, and `slice init` — so the three can never drift apart (they did:
|
|
6
|
+
// client.js was missing slice:types, and none of them had slice:build).
|
|
7
|
+
export const SLICE_SCRIPTS = {
|
|
8
|
+
'slice:init': 'slice init',
|
|
9
|
+
'slice:dev': 'slice dev',
|
|
10
|
+
'slice:build': 'slice build',
|
|
11
|
+
'slice:start': 'slice start',
|
|
12
|
+
'slice:create': 'slice component create',
|
|
13
|
+
'slice:list': 'slice component list',
|
|
14
|
+
'slice:delete': 'slice component delete',
|
|
15
|
+
'slice:get': 'slice get',
|
|
16
|
+
'slice:browse': 'slice browse',
|
|
17
|
+
'slice:sync': 'slice sync',
|
|
18
|
+
'slice:version': 'slice version',
|
|
19
|
+
'slice:update': 'slice update',
|
|
20
|
+
'slice:types': 'slice types generate',
|
|
21
|
+
};
|
|
@@ -7,6 +7,7 @@ import ora from "ora";
|
|
|
7
7
|
import Print from "../Print.js";
|
|
8
8
|
import versionChecker from "./VersionChecker.js";
|
|
9
9
|
import { getProjectRoot, getApiPath, getPath } from "../utils/PathHelper.js";
|
|
10
|
+
import { resolvePackageManager, installCommand } from "../utils/PackageManager.js";
|
|
10
11
|
import path from "path";
|
|
11
12
|
import { fileURLToPath } from "url";
|
|
12
13
|
import fs from "fs-extra";
|
|
@@ -18,28 +19,45 @@ export class UpdateManager {
|
|
|
18
19
|
this.packagesToUpdate = [];
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
getPackageManager() {
|
|
23
|
+
if (!this._packageManager) {
|
|
24
|
+
this._packageManager = resolvePackageManager(getProjectRoot(import.meta.url)).name;
|
|
25
|
+
}
|
|
26
|
+
return this._packageManager;
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
async detectCliInstall() {
|
|
22
30
|
try {
|
|
23
31
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
24
32
|
const cliRoot = path.join(moduleDir, '../../');
|
|
25
33
|
const projectRoot = getProjectRoot(import.meta.url);
|
|
34
|
+
const packageManager = this.getPackageManager();
|
|
35
|
+
const localNodeModules = path.join(projectRoot, 'node_modules');
|
|
36
|
+
|
|
37
|
+
if (cliRoot.startsWith(localNodeModules)) {
|
|
38
|
+
return { type: 'local', cliRoot, projectRoot, packageManager };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Global pnpm installs live under PNPM_HOME — `npm config get prefix`
|
|
42
|
+
// knows nothing about them (and npm may not even exist on the machine).
|
|
43
|
+
const pnpmHome = process.env.PNPM_HOME;
|
|
44
|
+
if (pnpmHome && cliRoot.startsWith(pnpmHome)) {
|
|
45
|
+
return { type: 'global', cliRoot, projectRoot, packageManager: 'pnpm' };
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
let globalPrefix = '';
|
|
27
49
|
try {
|
|
28
50
|
const { stdout } = await execAsync('npm config get prefix');
|
|
29
51
|
globalPrefix = stdout.toString().trim();
|
|
30
52
|
} catch {}
|
|
31
|
-
const localNodeModules = path.join(projectRoot, 'node_modules');
|
|
32
53
|
const globalNodeModules = globalPrefix ? path.join(globalPrefix, 'node_modules') : '';
|
|
33
|
-
|
|
34
|
-
if (cliRoot.startsWith(localNodeModules)) {
|
|
35
|
-
return { type: 'local', cliRoot, projectRoot, globalPrefix };
|
|
36
|
-
}
|
|
37
54
|
if (globalNodeModules && cliRoot.startsWith(globalNodeModules)) {
|
|
38
|
-
return { type: 'global', cliRoot, projectRoot,
|
|
55
|
+
return { type: 'global', cliRoot, projectRoot, packageManager: 'npm' };
|
|
39
56
|
}
|
|
40
|
-
|
|
57
|
+
|
|
58
|
+
return { type: 'unknown', cliRoot, projectRoot, packageManager };
|
|
41
59
|
} catch (error) {
|
|
42
|
-
return { type: 'unknown' };
|
|
60
|
+
return { type: 'unknown', packageManager: this.getPackageManager() };
|
|
43
61
|
}
|
|
44
62
|
}
|
|
45
63
|
|
|
@@ -180,17 +198,12 @@ export class UpdateManager {
|
|
|
180
198
|
async buildUpdatePlan(packages) {
|
|
181
199
|
const plan = [];
|
|
182
200
|
const info = await this.detectCliInstall();
|
|
201
|
+
const pm = info.packageManager || this.getPackageManager();
|
|
183
202
|
for (const pkg of packages) {
|
|
184
|
-
if (pkg === 'slicejs-cli') {
|
|
185
|
-
|
|
186
|
-
plan.push({ package: pkg, target: 'global', command: 'npm install -g slicejs-cli@latest' });
|
|
187
|
-
} else {
|
|
188
|
-
plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-cli@latest' });
|
|
189
|
-
}
|
|
190
|
-
} else if (pkg === 'slicejs-web-framework') {
|
|
191
|
-
plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-web-framework@latest' });
|
|
203
|
+
if (pkg === 'slicejs-cli' && info.type === 'global') {
|
|
204
|
+
plan.push({ package: pkg, target: 'global', command: installCommand(pm, 'slicejs-cli@latest', { global: true }) });
|
|
192
205
|
} else {
|
|
193
|
-
plan.push({ package: pkg, target: 'project', command:
|
|
206
|
+
plan.push({ package: pkg, target: 'project', command: installCommand(pm, `${pkg}@latest`) });
|
|
194
207
|
}
|
|
195
208
|
}
|
|
196
209
|
return plan;
|
|
@@ -201,15 +214,15 @@ export class UpdateManager {
|
|
|
201
214
|
*/
|
|
202
215
|
async updatePackage(packageName) {
|
|
203
216
|
try {
|
|
204
|
-
|
|
205
|
-
let
|
|
217
|
+
const pm = this.getPackageManager();
|
|
218
|
+
let installCmd = installCommand(pm, `${packageName}@latest`);
|
|
206
219
|
let options = {};
|
|
207
220
|
|
|
208
221
|
if (packageName === 'slicejs-cli') {
|
|
209
222
|
const info = await this.detectCliInstall();
|
|
210
223
|
if (info.type === 'global') {
|
|
211
|
-
|
|
212
|
-
|
|
224
|
+
const globalPm = info.packageManager || pm;
|
|
225
|
+
installCmd = installCommand(globalPm, 'slicejs-cli@latest', { global: true });
|
|
213
226
|
} else {
|
|
214
227
|
options.cwd = info.projectRoot || getProjectRoot(import.meta.url);
|
|
215
228
|
}
|
|
@@ -217,11 +230,9 @@ export class UpdateManager {
|
|
|
217
230
|
options.cwd = getProjectRoot(import.meta.url);
|
|
218
231
|
}
|
|
219
232
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
} catch {}
|
|
224
|
-
|
|
233
|
+
// Install directly — npm/pnpm upgrade in place. (We used to uninstall
|
|
234
|
+
// first, which left the project without the package whenever the
|
|
235
|
+
// subsequent install failed, e.g. offline or under a release-age policy.)
|
|
225
236
|
const { stdout, stderr } = await execAsync(installCmd, options);
|
|
226
237
|
|
|
227
238
|
return {
|
|
@@ -284,13 +295,12 @@ export class UpdateManager {
|
|
|
284
295
|
return false;
|
|
285
296
|
}
|
|
286
297
|
|
|
287
|
-
if (updateInfo.allCurrent) {
|
|
288
|
-
Print.success('✅ All components are up to date!');
|
|
289
|
-
return true;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (!updateInfo.hasUpdates) {
|
|
298
|
+
if (updateInfo.allCurrent || !updateInfo.hasUpdates) {
|
|
293
299
|
Print.success('✅ All components are up to date!');
|
|
300
|
+
// --update-api works even when no package update runs.
|
|
301
|
+
if (options.updateApi) {
|
|
302
|
+
await this.updateApiIndexIfNeeded(options);
|
|
303
|
+
}
|
|
294
304
|
return true;
|
|
295
305
|
}
|
|
296
306
|
|
|
@@ -341,7 +351,7 @@ export class UpdateManager {
|
|
|
341
351
|
}
|
|
342
352
|
} else {
|
|
343
353
|
Print.warning('Global CLI detected. It is recommended to update slicejs-cli globally to keep aligned with the framework.');
|
|
344
|
-
console.log(
|
|
354
|
+
console.log(` Suggestion: ${installCommand(cliInfo.packageManager || this.getPackageManager(), 'slicejs-cli@latest', { global: true })}`);
|
|
345
355
|
console.log('');
|
|
346
356
|
}
|
|
347
357
|
}
|
|
@@ -386,7 +396,7 @@ export class UpdateManager {
|
|
|
386
396
|
}
|
|
387
397
|
|
|
388
398
|
const frameworkUpdated = results.find(r => r.packageName === 'slicejs-web-framework' && r.success);
|
|
389
|
-
if (frameworkUpdated) {
|
|
399
|
+
if (frameworkUpdated || options.updateApi) {
|
|
390
400
|
await this.updateApiIndexIfNeeded(options);
|
|
391
401
|
}
|
|
392
402
|
|
|
@@ -417,7 +427,16 @@ export class UpdateManager {
|
|
|
417
427
|
|
|
418
428
|
Print.warning('⚠️ Detected changes in framework api/index.js.');
|
|
419
429
|
|
|
420
|
-
|
|
430
|
+
// Overwriting api/index.js is opt-in: `--update-api` is the only way
|
|
431
|
+
// to auto-confirm. `-y/--yes` deliberately does NOT imply it — the
|
|
432
|
+
// project file may carry local changes, so a blanket "yes to updates"
|
|
433
|
+
// must not silently replace it.
|
|
434
|
+
let confirmUpdate = options.updateApi === true;
|
|
435
|
+
if (!confirmUpdate && options.yes === true) {
|
|
436
|
+
Print.info('Skipping api/index.js update (not updated by default).');
|
|
437
|
+
Print.info('Run "slice update --update-api" to update it (a .bak backup is created).');
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
421
440
|
if (!confirmUpdate) {
|
|
422
441
|
const answers = await inquirer.prompt([
|
|
423
442
|
{
|
package/package.json
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slicejs-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Command client for developing web applications with Slice.js framework",
|
|
5
5
|
"main": "client.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"slice": "./client.js"
|
|
8
8
|
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20.0.0"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"client.js",
|
|
14
|
+
"post.js",
|
|
15
|
+
"commands",
|
|
16
|
+
"assets"
|
|
17
|
+
],
|
|
9
18
|
"repository": {
|
|
10
19
|
"type": "git",
|
|
11
20
|
"url": "https://github.com/vkneider/slicejs-cli.git"
|
|
@@ -14,6 +23,7 @@
|
|
|
14
23
|
"test": "node --test",
|
|
15
24
|
"postinstall": "node post.js",
|
|
16
25
|
"slice:dev": "slice dev",
|
|
26
|
+
"slice:build": "slice build",
|
|
17
27
|
"slice:start": "slice start",
|
|
18
28
|
"slice:create": "slice component create",
|
|
19
29
|
"slice:list": "slice component list",
|
|
@@ -38,6 +48,7 @@
|
|
|
38
48
|
],
|
|
39
49
|
"author": "vkneider",
|
|
40
50
|
"type": "module",
|
|
51
|
+
"packageManager": "pnpm@11.1.1",
|
|
41
52
|
"preferGlobal": false,
|
|
42
53
|
"license": "ISC",
|
|
43
54
|
"dependencies": {
|
package/post.js
CHANGED
|
@@ -2,35 +2,27 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { getProjectRoot, getPath } from './commands/utils/PathHelper.js';
|
|
5
|
+
import { SLICE_SCRIPTS } from './commands/utils/sliceScripts.js';
|
|
5
6
|
|
|
6
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
// npm sets npm_config_global; pnpm does not — for pnpm a global install lives
|
|
10
|
+
// under PNPM_HOME, so detect it by where this script is running from.
|
|
11
|
+
const pnpmHome = process.env.PNPM_HOME;
|
|
12
|
+
const isGlobal = process.env.npm_config_global === 'true'
|
|
13
|
+
|| (pnpmHome && __filename.startsWith(pnpmHome));
|
|
9
14
|
|
|
10
15
|
if (isGlobal) {
|
|
11
16
|
console.log('⚠️ Global installation of slicejs-cli detected.');
|
|
12
17
|
console.log(' We strongly recommend using a local installation to avoid version mismatches.');
|
|
13
|
-
console.log(
|
|
18
|
+
console.log(` Uninstall global: ${pnpmHome ? 'pnpm remove -g slicejs-cli' : 'npm uninstall -g slicejs-cli'}`);
|
|
14
19
|
process.exit(0);
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
const projectRoot = getProjectRoot(import.meta.url);
|
|
18
23
|
const pkgPath = getPath(import.meta.url, 'package.json');
|
|
19
24
|
|
|
20
|
-
const sliceScripts =
|
|
21
|
-
'slice:dev': 'slice dev',
|
|
22
|
-
'slice:start': 'slice start',
|
|
23
|
-
'slice:create': 'slice component create',
|
|
24
|
-
'slice:list': 'slice component list',
|
|
25
|
-
'slice:delete': 'slice component delete',
|
|
26
|
-
'slice:init': 'slice init',
|
|
27
|
-
'slice:get': 'slice get',
|
|
28
|
-
'slice:browse': 'slice browse',
|
|
29
|
-
'slice:sync': 'slice sync',
|
|
30
|
-
'slice:version': 'slice version',
|
|
31
|
-
'slice:update': 'slice update',
|
|
32
|
-
'slice:types': 'slice types generate',
|
|
33
|
-
};
|
|
25
|
+
const sliceScripts = SLICE_SCRIPTS;
|
|
34
26
|
|
|
35
27
|
try {
|
|
36
28
|
let pkg = {};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Bug Report
|
|
3
|
-
about: Report a bug in a component or the parser
|
|
4
|
-
title: ''
|
|
5
|
-
labels: bug
|
|
6
|
-
assignees: ''
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Description
|
|
10
|
-
A clear description of the bug.
|
|
11
|
-
|
|
12
|
-
## Reproduction
|
|
13
|
-
Steps to reproduce:
|
|
14
|
-
1. Go to '...'
|
|
15
|
-
2. Click on '...'
|
|
16
|
-
3. Error: '...'
|
|
17
|
-
|
|
18
|
-
## Expected behavior
|
|
19
|
-
What should have happened.
|
|
20
|
-
|
|
21
|
-
## Environment
|
|
22
|
-
- Browser/Node version:
|
|
23
|
-
- OS:
|
|
24
|
-
- slice.js_visual_library version:
|
|
25
|
-
|
|
26
|
-
## Screenshots / Console output
|
|
27
|
-
If applicable.
|
|
28
|
-
|
|
29
|
-
## Additional context
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Feature Request
|
|
3
|
-
about: Suggest a new component or improvement
|
|
4
|
-
title: ''
|
|
5
|
-
labels: enhancement
|
|
6
|
-
assignees: ''
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Problem
|
|
10
|
-
What problem does this solve? (e.g. "I need a component that...")
|
|
11
|
-
|
|
12
|
-
## Proposed solution
|
|
13
|
-
How should it work? Include props, behavior, and visual details if applicable.
|
|
14
|
-
|
|
15
|
-
## Alternatives considered
|
|
16
|
-
What other approaches have you considered?
|
|
17
|
-
|
|
18
|
-
## Example usage
|
|
19
|
-
```javascript
|
|
20
|
-
const component = await slice.build('ComponentName', {
|
|
21
|
-
// props here
|
|
22
|
-
});
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Additional context
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
## Summary
|
|
2
|
-
-
|
|
3
|
-
|
|
4
|
-
## Docs Scope
|
|
5
|
-
- [ ] Visual library docs pages (`src/markdown/` and generated outputs)
|
|
6
|
-
- [ ] Parser logic (`parser/`)
|
|
7
|
-
- [ ] Routes/index sync (`documentationRoutes.generated.js`, `docsIndex.js`, `components.js`)
|
|
8
|
-
|
|
9
|
-
## Verification
|
|
10
|
-
- [ ] `npm run docs:lint-md`
|
|
11
|
-
- [ ] `npm run docs:generate`
|
|
12
|
-
- [ ] `node --test parser/tests/index.test.js`
|
|
13
|
-
|
|
14
|
-
## Screenshots / UI Notes
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
## Breaking Changes
|
|
18
|
-
- [ ] None
|
|
19
|
-
- [ ] Yes (describe below)
|
|
20
|
-
|
|
21
|
-
## Additional Context
|
|
22
|
-
-
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [master, main]
|
|
6
|
-
pull_request:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
test:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
timeout-minutes: 20
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/checkout@v4
|
|
14
|
-
|
|
15
|
-
- uses: pnpm/action-setup@v4
|
|
16
|
-
with:
|
|
17
|
-
version: 11
|
|
18
|
-
|
|
19
|
-
- uses: actions/setup-node@v4
|
|
20
|
-
with:
|
|
21
|
-
node-version: 22
|
|
22
|
-
cache: pnpm
|
|
23
|
-
|
|
24
|
-
- name: Install dependencies
|
|
25
|
-
run: pnpm install --frozen-lockfile
|
|
26
|
-
|
|
27
|
-
- name: Install Playwright browser
|
|
28
|
-
run: pnpm exec playwright install --with-deps chromium
|
|
29
|
-
|
|
30
|
-
# Serialized to avoid resource contention between the build-heavy
|
|
31
|
-
# integration tests under parallel runners.
|
|
32
|
-
- name: Unit & integration tests
|
|
33
|
-
run: node --test --test-concurrency=1
|
|
34
|
-
|
|
35
|
-
- name: Browser E2E tests
|
|
36
|
-
run: pnpm exec playwright test
|
|
37
|
-
|
|
38
|
-
- uses: actions/upload-artifact@v4
|
|
39
|
-
if: ${{ !cancelled() }}
|
|
40
|
-
with:
|
|
41
|
-
name: playwright-report
|
|
42
|
-
path: playwright-report/
|
|
43
|
-
retention-days: 7
|