@gjsify/cli 0.4.28 → 0.4.30
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/dist/cli.gjs.mjs +132 -132
- package/lib/actions/barrels-generate.js +1 -5
- package/lib/actions/build.d.ts +3 -3
- package/lib/actions/build.js +56 -64
- package/lib/bundler-pick.d.ts +3 -3
- package/lib/bundler-pick.js +5 -6
- package/lib/commands/build.d.ts +1 -1
- package/lib/commands/build.js +37 -31
- package/lib/commands/check.js +3 -3
- package/lib/commands/create.d.ts +1 -1
- package/lib/commands/dlx.d.ts +1 -1
- package/lib/commands/fix.js +33 -23
- package/lib/commands/flatpak/build.js +6 -2
- package/lib/commands/flatpak/check.js +9 -3
- package/lib/commands/flatpak/ci.js +1 -2
- package/lib/commands/flatpak/deps.js +1 -2
- package/lib/commands/flatpak/diff.js +2 -6
- package/lib/commands/flatpak/init.js +19 -19
- package/lib/commands/flatpak/release.js +2 -2
- package/lib/commands/flatpak/scaffold.js +3 -11
- package/lib/commands/flatpak/sync-flathub.js +5 -9
- package/lib/commands/flatpak/utils.js +1 -6
- package/lib/commands/foreach.d.ts +1 -1
- package/lib/commands/foreach.js +5 -14
- package/lib/commands/format.js +54 -41
- package/lib/commands/generate-installer.d.ts +1 -1
- package/lib/commands/gettext.d.ts +1 -1
- package/lib/commands/gettext.js +8 -15
- package/lib/commands/gresource.d.ts +1 -1
- package/lib/commands/gresource.js +8 -13
- package/lib/commands/gsettings.d.ts +1 -1
- package/lib/commands/gsettings.js +7 -8
- package/lib/commands/info.d.ts +1 -1
- package/lib/commands/install.d.ts +1 -1
- package/lib/commands/install.js +45 -13
- package/lib/commands/lint.d.ts +1 -1
- package/lib/commands/lint.js +22 -22
- package/lib/commands/pack.d.ts +1 -1
- package/lib/commands/pack.js +29 -17
- package/lib/commands/publish.d.ts +1 -1
- package/lib/commands/publish.js +17 -18
- package/lib/commands/run.d.ts +1 -1
- package/lib/commands/run.js +2 -6
- package/lib/commands/self-update.d.ts +1 -1
- package/lib/commands/self-update.js +1 -3
- package/lib/commands/showcase.d.ts +1 -1
- package/lib/commands/showcase.js +1 -1
- package/lib/commands/system-check.d.ts +1 -1
- package/lib/commands/system-check.js +8 -11
- package/lib/commands/test.js +12 -8
- package/lib/commands/uninstall.d.ts +1 -1
- package/lib/commands/uninstall.js +1 -3
- package/lib/commands/upgrade.d.ts +1 -1
- package/lib/commands/upgrade.js +109 -120
- package/lib/commands/workspace.d.ts +1 -1
- package/lib/commands/workspace.js +1 -3
- package/lib/config.js +18 -13
- package/lib/index.js +3 -1
- package/lib/templates/install.mjs.tmpl +20 -14
- package/lib/templates/oxfmtrc.tmpl +54 -0
- package/lib/templates/oxlintrc.json.tmpl +35 -0
- package/lib/types/command.d.ts +1 -1
- package/lib/types/config-data.d.ts +23 -13
- package/lib/types/cosmiconfig-result.d.ts +1 -1
- package/lib/utils/check-system-deps.js +10 -4
- package/lib/utils/detect-native-packages.js +1 -1
- package/lib/utils/dlx-cache.js +2 -7
- package/lib/utils/install-backend-native.d.ts +2 -2
- package/lib/utils/install-backend-native.js +112 -58
- package/lib/utils/install-backend.js +2 -1
- package/lib/utils/install-global.js +1 -3
- package/lib/utils/normalize-bundler-options.js +52 -17
- package/lib/utils/oxc-resolve.d.ts +63 -0
- package/lib/utils/oxc-resolve.js +264 -0
- package/lib/utils/pkg-json-edit.js +1 -6
- package/lib/utils/run-gjs.js +1 -4
- package/lib/utils/run-lifecycle-script.js +3 -7
- package/lib/utils/workspace-root.js +3 -1
- package/package.json +17 -17
- package/lib/templates/biome.json.tmpl +0 -79
- package/lib/utils/biome-resolve.d.ts +0 -47
- package/lib/utils/biome-resolve.js +0 -204
|
@@ -3,8 +3,7 @@ export const systemCheckCommand = {
|
|
|
3
3
|
command: 'system-check',
|
|
4
4
|
description: 'Check that required system dependencies (GJS, GTK4, libsoup3, …) are installed. Optional dependencies are detected only when their @gjsify/* package is in your project. (Previously called `gjsify check`; the bare name now runs TypeScript checks across the workspace — see `gjsify check --help`.)',
|
|
5
5
|
builder: (yargs) => {
|
|
6
|
-
return yargs
|
|
7
|
-
.option('json', {
|
|
6
|
+
return yargs.option('json', {
|
|
8
7
|
description: 'Output results as JSON',
|
|
9
8
|
type: 'boolean',
|
|
10
9
|
default: false,
|
|
@@ -13,8 +12,8 @@ export const systemCheckCommand = {
|
|
|
13
12
|
handler: async (args) => {
|
|
14
13
|
const results = runAllChecks(process.cwd());
|
|
15
14
|
const pm = detectPackageManager();
|
|
16
|
-
const missingRequired = results.filter(r => !r.found && r.severity === 'required');
|
|
17
|
-
const missingOptional = results.filter(r => !r.found && r.severity === 'optional');
|
|
15
|
+
const missingRequired = results.filter((r) => !r.found && r.severity === 'required');
|
|
16
|
+
const missingOptional = results.filter((r) => !r.found && r.severity === 'optional');
|
|
18
17
|
const allMissing = [...missingRequired, ...missingOptional];
|
|
19
18
|
if (args.json) {
|
|
20
19
|
console.log(JSON.stringify({ packageManager: pm, deps: results }, null, 2));
|
|
@@ -23,8 +22,8 @@ export const systemCheckCommand = {
|
|
|
23
22
|
return;
|
|
24
23
|
}
|
|
25
24
|
console.log('System dependency check\n');
|
|
26
|
-
const required = results.filter(r => r.severity === 'required');
|
|
27
|
-
const optional = results.filter(r => r.severity === 'optional');
|
|
25
|
+
const required = results.filter((r) => r.severity === 'required');
|
|
26
|
+
const optional = results.filter((r) => r.severity === 'optional');
|
|
28
27
|
if (required.length > 0) {
|
|
29
28
|
console.log('Required:');
|
|
30
29
|
for (const dep of required) {
|
|
@@ -39,9 +38,7 @@ export const systemCheckCommand = {
|
|
|
39
38
|
// ⚠ for missing-but-needed-by-installed-packages, ○ for missing-but-not-needed (shouldn't appear in conditional mode)
|
|
40
39
|
const icon = dep.found ? '✓' : '⚠';
|
|
41
40
|
const ver = dep.version ? ` (${dep.version})` : '';
|
|
42
|
-
const requiredBy = dep.requiredBy && dep.requiredBy.length > 0
|
|
43
|
-
? ` — needed by ${dep.requiredBy.join(', ')}`
|
|
44
|
-
: '';
|
|
41
|
+
const requiredBy = dep.requiredBy && dep.requiredBy.length > 0 ? ` — needed by ${dep.requiredBy.join(', ')}` : '';
|
|
45
42
|
console.log(` ${icon} ${dep.name}${ver}${requiredBy}`);
|
|
46
43
|
}
|
|
47
44
|
}
|
|
@@ -51,10 +48,10 @@ export const systemCheckCommand = {
|
|
|
51
48
|
return;
|
|
52
49
|
}
|
|
53
50
|
if (missingRequired.length > 0) {
|
|
54
|
-
console.log(`\nMissing required: ${missingRequired.map(d => d.name).join(', ')}`);
|
|
51
|
+
console.log(`\nMissing required: ${missingRequired.map((d) => d.name).join(', ')}`);
|
|
55
52
|
}
|
|
56
53
|
if (missingOptional.length > 0) {
|
|
57
|
-
console.log(`Missing optional: ${missingOptional.map(d => d.name).join(', ')}`);
|
|
54
|
+
console.log(`Missing optional: ${missingOptional.map((d) => d.name).join(', ')}`);
|
|
58
55
|
}
|
|
59
56
|
const cmd = buildInstallCommand(pm, allMissing);
|
|
60
57
|
if (cmd) {
|
package/lib/commands/test.js
CHANGED
|
@@ -66,13 +66,15 @@ export const testCommand = {
|
|
|
66
66
|
? ['gjs']
|
|
67
67
|
: args.runtime === 'node'
|
|
68
68
|
? ['node']
|
|
69
|
-
:
|
|
69
|
+
: testCfg.runtimes && testCfg.runtimes.length > 0
|
|
70
|
+
? testCfg.runtimes
|
|
71
|
+
: ['gjs', 'node'];
|
|
70
72
|
const results = [];
|
|
71
73
|
for (const runtime of requested) {
|
|
72
74
|
const outfile = join(outdir, `test.${runtime}.mjs`);
|
|
73
75
|
// Build stage (skip if --no-build OR (not --rebuild AND outfile fresher than src)).
|
|
74
76
|
if (args.build !== false) {
|
|
75
|
-
const needsBuild = args.rebuild || !isFresh(outfile, entry
|
|
77
|
+
const needsBuild = args.rebuild || !isFresh(outfile, entry);
|
|
76
78
|
if (needsBuild) {
|
|
77
79
|
const buildStart = Date.now();
|
|
78
80
|
if (args.verbose) {
|
|
@@ -144,11 +146,11 @@ async function buildTestBundle(entry, outfile, runtime, verbose) {
|
|
|
144
146
|
// the merged config; we set it explicitly here so package.json#main /
|
|
145
147
|
// bundler.output.file from the surrounding project don't redirect the
|
|
146
148
|
// bundle elsewhere.
|
|
147
|
-
configData.library = { ...
|
|
149
|
+
configData.library = { ...configData.library };
|
|
148
150
|
configData.bundler = {
|
|
149
|
-
...
|
|
151
|
+
...configData.bundler,
|
|
150
152
|
input: [entry],
|
|
151
|
-
output: { ...
|
|
153
|
+
output: { ...configData.bundler?.output, file: outfile },
|
|
152
154
|
};
|
|
153
155
|
const action = new BuildAction(configData);
|
|
154
156
|
await action.start({ app: runtime, library: false });
|
|
@@ -171,7 +173,7 @@ async function runTestBundle(outfile, runtime) {
|
|
|
171
173
|
});
|
|
172
174
|
}
|
|
173
175
|
/** True when `outfile` exists and is newer than every `.ts`/`.mts` file under the entry's directory tree. */
|
|
174
|
-
function isFresh(outfile, entry
|
|
176
|
+
function isFresh(outfile, entry) {
|
|
175
177
|
if (!existsSync(outfile))
|
|
176
178
|
return false;
|
|
177
179
|
const outMtime = statSync(outfile).mtimeMs;
|
|
@@ -186,7 +188,6 @@ function isFresh(outfile, entry, cwd) {
|
|
|
186
188
|
// On any FS error, force rebuild to stay safe.
|
|
187
189
|
return false;
|
|
188
190
|
}
|
|
189
|
-
void cwd;
|
|
190
191
|
}
|
|
191
192
|
function newestMtimeUnder(path) {
|
|
192
193
|
const st = statSync(path);
|
|
@@ -194,7 +195,10 @@ function newestMtimeUnder(path) {
|
|
|
194
195
|
return st.mtimeMs;
|
|
195
196
|
let max = st.mtimeMs;
|
|
196
197
|
for (const entry of readdirSync(path, { withFileTypes: true })) {
|
|
197
|
-
if (entry.name === 'node_modules' ||
|
|
198
|
+
if (entry.name === 'node_modules' ||
|
|
199
|
+
entry.name === 'dist' ||
|
|
200
|
+
entry.name === 'lib' ||
|
|
201
|
+
entry.name.startsWith('.')) {
|
|
198
202
|
continue;
|
|
199
203
|
}
|
|
200
204
|
const child = join(path, entry.name);
|
|
@@ -134,9 +134,7 @@ function findBinShimsForPackage(binDir, pkgDir, verbose) {
|
|
|
134
134
|
// Find the `exec [gjs -m] '<target>' "$@"` line; the path may
|
|
135
135
|
// contain `:` from the optional prebuild preamble lines, which
|
|
136
136
|
// is why we anchor to `exec ` rather than the first quoted run.
|
|
137
|
-
const execLine = content
|
|
138
|
-
.split('\n')
|
|
139
|
-
.find((line) => /^exec (?:gjs -m )?'/.test(line));
|
|
137
|
+
const execLine = content.split('\n').find((line) => /^exec (?:gjs -m )?'/.test(line));
|
|
140
138
|
if (!execLine)
|
|
141
139
|
continue;
|
|
142
140
|
const m = execLine.match(/'([^']+)'/);
|
package/lib/commands/upgrade.js
CHANGED
|
@@ -12,104 +12,104 @@
|
|
|
12
12
|
// are skipped — those are the gjsify monorepo internal links and `gjsify
|
|
13
13
|
// install` resolves them locally. Only external npm specs get checked
|
|
14
14
|
// against the registry.
|
|
15
|
-
import { readFileSync, writeFileSync, existsSync } from
|
|
16
|
-
import { join, resolve } from
|
|
17
|
-
import { homedir } from
|
|
18
|
-
import { createInterface } from
|
|
19
|
-
import { parse } from
|
|
20
|
-
import { DEFAULT_REGISTRY, fetchPackument, parseNpmrc
|
|
15
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
16
|
+
import { join, resolve } from 'node:path';
|
|
17
|
+
import { homedir } from 'node:os';
|
|
18
|
+
import { createInterface } from 'node:readline/promises';
|
|
19
|
+
import { parse } from '@gjsify/semver';
|
|
20
|
+
import { DEFAULT_REGISTRY, fetchPackument, parseNpmrc } from '@gjsify/npm-registry';
|
|
21
21
|
export const upgradeCommand = {
|
|
22
|
-
command:
|
|
23
|
-
description:
|
|
22
|
+
command: 'upgrade',
|
|
23
|
+
description: 'Check the npm registry for newer versions of declared dependencies and update package.json. Interactive by default; `--latest` / `--minor` / `--patch` switch to non-interactive bulk-update mode.',
|
|
24
24
|
builder: (yargs) => {
|
|
25
25
|
return yargs
|
|
26
|
-
.option(
|
|
27
|
-
description:
|
|
28
|
-
type:
|
|
26
|
+
.option('latest', {
|
|
27
|
+
description: 'Non-interactive: bump every dependency to its latest version (allows major).',
|
|
28
|
+
type: 'boolean',
|
|
29
29
|
default: false,
|
|
30
30
|
})
|
|
31
|
-
.option(
|
|
32
|
-
description:
|
|
33
|
-
type:
|
|
31
|
+
.option('minor', {
|
|
32
|
+
description: 'Non-interactive: bump every dependency to the latest within the same major (semver-minor + semver-patch).',
|
|
33
|
+
type: 'boolean',
|
|
34
34
|
default: false,
|
|
35
35
|
})
|
|
36
|
-
.option(
|
|
37
|
-
description:
|
|
38
|
-
type:
|
|
36
|
+
.option('patch', {
|
|
37
|
+
description: 'Non-interactive: bump every dependency to the latest within the same minor (semver-patch only).',
|
|
38
|
+
type: 'boolean',
|
|
39
39
|
default: false,
|
|
40
40
|
})
|
|
41
|
-
.option(
|
|
42
|
-
description:
|
|
43
|
-
type:
|
|
41
|
+
.option('filter', {
|
|
42
|
+
description: 'Only consider packages whose name matches this substring (case-insensitive). Repeatable; comma-separated values are split.',
|
|
43
|
+
type: 'string',
|
|
44
44
|
})
|
|
45
|
-
.option(
|
|
46
|
-
description:
|
|
47
|
-
type:
|
|
45
|
+
.option('dry-run', {
|
|
46
|
+
description: 'Print the upgrade plan without writing package.json.',
|
|
47
|
+
type: 'boolean',
|
|
48
48
|
default: false,
|
|
49
49
|
})
|
|
50
|
-
.option(
|
|
51
|
-
description:
|
|
52
|
-
type:
|
|
50
|
+
.option('cwd', {
|
|
51
|
+
description: 'Project directory. Default: process.cwd().',
|
|
52
|
+
type: 'string',
|
|
53
53
|
})
|
|
54
|
-
.option(
|
|
55
|
-
alias:
|
|
56
|
-
description:
|
|
57
|
-
type:
|
|
54
|
+
.option('yes', {
|
|
55
|
+
alias: 'y',
|
|
56
|
+
description: 'Interactive mode: select all without prompting.',
|
|
57
|
+
type: 'boolean',
|
|
58
58
|
default: false,
|
|
59
59
|
})
|
|
60
|
-
.option(
|
|
61
|
-
description:
|
|
62
|
-
type:
|
|
60
|
+
.option('verbose', {
|
|
61
|
+
description: 'Print extra resolution details.',
|
|
62
|
+
type: 'boolean',
|
|
63
63
|
default: false,
|
|
64
64
|
});
|
|
65
65
|
},
|
|
66
66
|
handler: async (args) => {
|
|
67
67
|
const cwd = resolve(args.cwd ?? process.cwd());
|
|
68
|
-
const pkgJsonPath = join(cwd,
|
|
68
|
+
const pkgJsonPath = join(cwd, 'package.json');
|
|
69
69
|
if (!existsSync(pkgJsonPath)) {
|
|
70
70
|
throw new Error(`[gjsify upgrade] no package.json at ${pkgJsonPath}`);
|
|
71
71
|
}
|
|
72
|
-
const rawPkg = readFileSync(pkgJsonPath,
|
|
72
|
+
const rawPkg = readFileSync(pkgJsonPath, 'utf-8');
|
|
73
73
|
const pkg = JSON.parse(rawPkg);
|
|
74
74
|
const filters = args.filter
|
|
75
75
|
? args.filter
|
|
76
|
-
.split(
|
|
76
|
+
.split(',')
|
|
77
77
|
.map((s) => s.trim().toLowerCase())
|
|
78
78
|
.filter(Boolean)
|
|
79
79
|
: [];
|
|
80
80
|
const entries = collectExternalDeps(pkg, filters);
|
|
81
81
|
if (entries.length === 0) {
|
|
82
|
-
console.log(
|
|
82
|
+
console.log('[gjsify upgrade] no external npm dependencies to check.');
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
const npmrc = await loadNpmrcLight(cwd);
|
|
86
86
|
const mode = args.latest
|
|
87
|
-
?
|
|
87
|
+
? 'latest'
|
|
88
88
|
: args.minor
|
|
89
|
-
?
|
|
89
|
+
? 'minor'
|
|
90
90
|
: args.patch
|
|
91
|
-
?
|
|
92
|
-
:
|
|
91
|
+
? 'patch'
|
|
92
|
+
: 'interactive';
|
|
93
93
|
console.log(`[gjsify upgrade] checking ${entries.length} dependencies against ${npmrc.registry}…`);
|
|
94
94
|
const candidates = await resolveCandidates(entries, npmrc, args.verbose ?? false, mode);
|
|
95
95
|
if (candidates.length === 0) {
|
|
96
|
-
console.log(
|
|
96
|
+
console.log('✅ all dependencies are up to date');
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
99
|
printTable(candidates);
|
|
100
100
|
let selected;
|
|
101
|
-
if (mode ===
|
|
101
|
+
if (mode === 'interactive' && !args.yes) {
|
|
102
102
|
selected = await promptSelection(candidates);
|
|
103
103
|
}
|
|
104
|
-
else if (args.yes && mode ===
|
|
105
|
-
console.log(
|
|
104
|
+
else if (args.yes && mode === 'interactive') {
|
|
105
|
+
console.log('[gjsify upgrade] -y / --yes: selecting all');
|
|
106
106
|
selected = candidates;
|
|
107
107
|
}
|
|
108
108
|
else {
|
|
109
109
|
selected = candidates;
|
|
110
110
|
}
|
|
111
111
|
if (selected.length === 0) {
|
|
112
|
-
console.log(
|
|
112
|
+
console.log('[gjsify upgrade] nothing selected; package.json unchanged.');
|
|
113
113
|
return;
|
|
114
114
|
}
|
|
115
115
|
if (args.dryRun) {
|
|
@@ -121,34 +121,29 @@ export const upgradeCommand = {
|
|
|
121
121
|
},
|
|
122
122
|
};
|
|
123
123
|
// ─── Resolution ─────────────────────────────────────────────────────────
|
|
124
|
-
const DEP_FIELDS = [
|
|
125
|
-
"dependencies",
|
|
126
|
-
"devDependencies",
|
|
127
|
-
"optionalDependencies",
|
|
128
|
-
"peerDependencies",
|
|
129
|
-
];
|
|
124
|
+
const DEP_FIELDS = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];
|
|
130
125
|
function collectExternalDeps(pkg, filters) {
|
|
131
126
|
const out = [];
|
|
132
127
|
for (const field of DEP_FIELDS) {
|
|
133
128
|
const map = pkg[field];
|
|
134
|
-
if (!map || typeof map !==
|
|
129
|
+
if (!map || typeof map !== 'object')
|
|
135
130
|
continue;
|
|
136
131
|
for (const [name, raw] of Object.entries(map)) {
|
|
137
|
-
if (typeof raw !==
|
|
132
|
+
if (typeof raw !== 'string')
|
|
138
133
|
continue;
|
|
139
134
|
if (filters.length && !filters.some((f) => name.toLowerCase().includes(f))) {
|
|
140
135
|
continue;
|
|
141
136
|
}
|
|
142
137
|
// Skip workspace-protocol + file: + link: + git: + http(s): specs.
|
|
143
|
-
if (raw.startsWith(
|
|
144
|
-
raw.startsWith(
|
|
145
|
-
raw.startsWith(
|
|
146
|
-
raw.startsWith(
|
|
147
|
-
raw.startsWith(
|
|
148
|
-
raw.startsWith(
|
|
149
|
-
raw.startsWith(
|
|
150
|
-
raw ===
|
|
151
|
-
raw ===
|
|
138
|
+
if (raw.startsWith('workspace:') ||
|
|
139
|
+
raw.startsWith('file:') ||
|
|
140
|
+
raw.startsWith('link:') ||
|
|
141
|
+
raw.startsWith('git+') ||
|
|
142
|
+
raw.startsWith('git:') ||
|
|
143
|
+
raw.startsWith('http') ||
|
|
144
|
+
raw.startsWith('npm:') || // e.g. `foo: npm:@scope/foo@^1`
|
|
145
|
+
raw === '*' ||
|
|
146
|
+
raw === 'latest') {
|
|
152
147
|
continue;
|
|
153
148
|
}
|
|
154
149
|
const { prefix, version } = splitRange(raw);
|
|
@@ -171,8 +166,8 @@ function collectExternalDeps(pkg, filters) {
|
|
|
171
166
|
function splitRange(range) {
|
|
172
167
|
const m = range.match(/^(\^|~|>=|<=|>|<|=)?\s*([0-9].*)$/);
|
|
173
168
|
if (!m)
|
|
174
|
-
return { prefix:
|
|
175
|
-
const prefix = m[1] ??
|
|
169
|
+
return { prefix: '', version: null };
|
|
170
|
+
const prefix = m[1] ?? '';
|
|
176
171
|
const version = m[2]?.split(/\s|[|&,]/)[0] ?? null; // strip range modifiers (`||`, ` - `, etc.)
|
|
177
172
|
const parsed = version ? parse(version) : null;
|
|
178
173
|
return { prefix, version: parsed?.version ?? null };
|
|
@@ -190,7 +185,7 @@ async function resolveCandidates(entries, npmrc, verbose, mode) {
|
|
|
190
185
|
const entry = entries[i];
|
|
191
186
|
try {
|
|
192
187
|
const packument = await fetchPackument(entry.name, { npmrc });
|
|
193
|
-
const latest = packument[
|
|
188
|
+
const latest = packument['dist-tags']?.latest;
|
|
194
189
|
if (!latest) {
|
|
195
190
|
if (verbose)
|
|
196
191
|
console.warn(` ${entry.name}: no dist-tags.latest, skipping`);
|
|
@@ -202,11 +197,11 @@ async function resolveCandidates(entries, npmrc, verbose, mode) {
|
|
|
202
197
|
continue;
|
|
203
198
|
}
|
|
204
199
|
const diff = classifyDiff(entry.currentVersion, latest);
|
|
205
|
-
if (diff ===
|
|
200
|
+
if (diff === 'none')
|
|
206
201
|
continue;
|
|
207
|
-
if (mode ===
|
|
202
|
+
if (mode === 'minor' && diff === 'major')
|
|
208
203
|
continue;
|
|
209
|
-
if (mode ===
|
|
204
|
+
if (mode === 'patch' && (diff === 'major' || diff === 'minor'))
|
|
210
205
|
continue;
|
|
211
206
|
results.push({
|
|
212
207
|
...entry,
|
|
@@ -219,7 +214,6 @@ async function resolveCandidates(entries, npmrc, verbose, mode) {
|
|
|
219
214
|
console.warn(` ${entry.name}: fetch failed (${err.message})`);
|
|
220
215
|
}
|
|
221
216
|
}
|
|
222
|
-
void packumentToString;
|
|
223
217
|
}
|
|
224
218
|
await Promise.all(Array.from({ length: cap }, () => worker()));
|
|
225
219
|
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -229,39 +223,39 @@ function classifyDiff(current, latest) {
|
|
|
229
223
|
const c = parse(current);
|
|
230
224
|
const l = parse(latest);
|
|
231
225
|
if (!c || !l)
|
|
232
|
-
return
|
|
226
|
+
return 'none';
|
|
233
227
|
if (c.major !== l.major)
|
|
234
|
-
return l.major > c.major ?
|
|
228
|
+
return l.major > c.major ? 'major' : 'none';
|
|
235
229
|
if (c.minor !== l.minor)
|
|
236
|
-
return l.minor > c.minor ?
|
|
230
|
+
return l.minor > c.minor ? 'minor' : 'none';
|
|
237
231
|
if (c.patch !== l.patch)
|
|
238
|
-
return l.patch > c.patch ?
|
|
239
|
-
if ((c.prerelease ?? []).join(
|
|
240
|
-
return
|
|
241
|
-
return
|
|
232
|
+
return l.patch > c.patch ? 'patch' : 'none';
|
|
233
|
+
if ((c.prerelease ?? []).join('.') !== (l.prerelease ?? []).join('.'))
|
|
234
|
+
return 'prerelease';
|
|
235
|
+
return 'none';
|
|
242
236
|
}
|
|
243
237
|
// ─── Output / Interaction ──────────────────────────────────────────────
|
|
244
238
|
const ANSI = {
|
|
245
|
-
reset:
|
|
246
|
-
bold:
|
|
247
|
-
dim:
|
|
248
|
-
red:
|
|
249
|
-
yellow:
|
|
250
|
-
green:
|
|
251
|
-
cyan:
|
|
239
|
+
reset: '\x1b[0m',
|
|
240
|
+
bold: '\x1b[1m',
|
|
241
|
+
dim: '\x1b[2m',
|
|
242
|
+
red: '\x1b[31m',
|
|
243
|
+
yellow: '\x1b[33m',
|
|
244
|
+
green: '\x1b[32m',
|
|
245
|
+
cyan: '\x1b[36m',
|
|
252
246
|
};
|
|
253
247
|
function colorForDiff(diff) {
|
|
254
248
|
switch (diff) {
|
|
255
|
-
case
|
|
249
|
+
case 'major':
|
|
256
250
|
return ANSI.red;
|
|
257
|
-
case
|
|
251
|
+
case 'minor':
|
|
258
252
|
return ANSI.yellow;
|
|
259
|
-
case
|
|
253
|
+
case 'patch':
|
|
260
254
|
return ANSI.green;
|
|
261
|
-
case
|
|
255
|
+
case 'prerelease':
|
|
262
256
|
return ANSI.cyan;
|
|
263
257
|
default:
|
|
264
|
-
return
|
|
258
|
+
return '';
|
|
265
259
|
}
|
|
266
260
|
}
|
|
267
261
|
function printTable(candidates) {
|
|
@@ -269,33 +263,33 @@ function printTable(candidates) {
|
|
|
269
263
|
const curW = Math.max(...candidates.map((c) => c.currentRange.length), 7);
|
|
270
264
|
const newW = Math.max(...candidates.map((c) => c.latestVersion.length), 6);
|
|
271
265
|
const idxW = String(candidates.length).length + 2;
|
|
272
|
-
const head =
|
|
266
|
+
const head = ' '.repeat(idxW) +
|
|
273
267
|
ANSI.bold +
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
268
|
+
'name'.padEnd(nameW) +
|
|
269
|
+
' ' +
|
|
270
|
+
'current'.padEnd(curW) +
|
|
271
|
+
' ' +
|
|
272
|
+
'latest'.padEnd(newW) +
|
|
273
|
+
' ' +
|
|
274
|
+
'kind' +
|
|
281
275
|
ANSI.reset;
|
|
282
276
|
console.log(head);
|
|
283
|
-
console.log(
|
|
277
|
+
console.log(' '.repeat(idxW) + ANSI.dim + '─'.repeat(nameW + curW + newW + 12) + ANSI.reset);
|
|
284
278
|
for (let i = 0; i < candidates.length; i++) {
|
|
285
279
|
const c = candidates[i];
|
|
286
280
|
const idx = `${i + 1}.`.padEnd(idxW);
|
|
287
281
|
const color = colorForDiff(c.diff);
|
|
288
282
|
console.log(idx +
|
|
289
283
|
c.name.padEnd(nameW) +
|
|
290
|
-
|
|
284
|
+
' ' +
|
|
291
285
|
ANSI.dim +
|
|
292
286
|
c.currentRange.padEnd(curW) +
|
|
293
287
|
ANSI.reset +
|
|
294
|
-
|
|
288
|
+
' ' +
|
|
295
289
|
color +
|
|
296
290
|
c.latestVersion.padEnd(newW) +
|
|
297
291
|
ANSI.reset +
|
|
298
|
-
|
|
292
|
+
' ' +
|
|
299
293
|
color +
|
|
300
294
|
c.diff +
|
|
301
295
|
ANSI.reset);
|
|
@@ -303,28 +297,28 @@ function printTable(candidates) {
|
|
|
303
297
|
}
|
|
304
298
|
async function promptSelection(candidates) {
|
|
305
299
|
if (!process.stdin.isTTY) {
|
|
306
|
-
console.log(
|
|
300
|
+
console.log('[gjsify upgrade] non-TTY stdin: pass --latest / --minor / --patch (or --yes for interactive-all) to upgrade non-interactively.');
|
|
307
301
|
return [];
|
|
308
302
|
}
|
|
309
303
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
310
304
|
try {
|
|
311
|
-
console.log(
|
|
305
|
+
console.log('\nSelect upgrades: comma- or space-separated indices, ' +
|
|
312
306
|
ANSI.bold +
|
|
313
|
-
|
|
307
|
+
'a' +
|
|
314
308
|
ANSI.reset +
|
|
315
|
-
|
|
309
|
+
' for all, ranges like ' +
|
|
316
310
|
ANSI.bold +
|
|
317
|
-
|
|
311
|
+
'1-3' +
|
|
318
312
|
ANSI.reset +
|
|
319
|
-
|
|
313
|
+
', or ' +
|
|
320
314
|
ANSI.bold +
|
|
321
|
-
|
|
315
|
+
'ENTER' +
|
|
322
316
|
ANSI.reset +
|
|
323
|
-
|
|
324
|
-
const answer = (await rl.question(
|
|
317
|
+
' to skip:');
|
|
318
|
+
const answer = (await rl.question('> ')).trim();
|
|
325
319
|
if (!answer)
|
|
326
320
|
return [];
|
|
327
|
-
if (answer.toLowerCase() ===
|
|
321
|
+
if (answer.toLowerCase() === 'a' || answer.toLowerCase() === 'all')
|
|
328
322
|
return candidates;
|
|
329
323
|
const picked = new Set();
|
|
330
324
|
for (const token of answer.split(/[\s,]+/).filter(Boolean)) {
|
|
@@ -339,9 +333,7 @@ async function promptSelection(candidates) {
|
|
|
339
333
|
picked.add(Number(token) - 1);
|
|
340
334
|
}
|
|
341
335
|
}
|
|
342
|
-
return [...picked]
|
|
343
|
-
.filter((i) => i >= 0 && i < candidates.length)
|
|
344
|
-
.map((i) => candidates[i]);
|
|
336
|
+
return [...picked].filter((i) => i >= 0 && i < candidates.length).map((i) => candidates[i]);
|
|
345
337
|
}
|
|
346
338
|
finally {
|
|
347
339
|
rl.close();
|
|
@@ -357,7 +349,7 @@ function writePackageJson(path, rawText, parsed, selected) {
|
|
|
357
349
|
map[c.name] = c.prefix + c.latestVersion;
|
|
358
350
|
}
|
|
359
351
|
const indent = detectIndent(rawText);
|
|
360
|
-
writeFileSync(path, JSON.stringify(parsed, null, indent) + (rawText.endsWith(
|
|
352
|
+
writeFileSync(path, JSON.stringify(parsed, null, indent) + (rawText.endsWith('\n') ? '\n' : ''), 'utf-8');
|
|
361
353
|
}
|
|
362
354
|
function detectIndent(json) {
|
|
363
355
|
const m = json.match(/^\{\n( +)/);
|
|
@@ -377,11 +369,11 @@ async function loadNpmrcLight(cwd) {
|
|
|
377
369
|
// as install-backend-native, except env-var `npm_config_registry` wins
|
|
378
370
|
// over file values (matches npm's real semantics, lets the test harness
|
|
379
371
|
// point at a mock registry without touching `~/.npmrc`).
|
|
380
|
-
for (const candidate of [join(homedir(),
|
|
372
|
+
for (const candidate of [join(homedir(), '.npmrc'), join(cwd, '.npmrc')]) {
|
|
381
373
|
if (!existsSync(candidate))
|
|
382
374
|
continue;
|
|
383
375
|
try {
|
|
384
|
-
const proj = parseNpmrc(readFileSync(candidate,
|
|
376
|
+
const proj = parseNpmrc(readFileSync(candidate, 'utf-8'));
|
|
385
377
|
parsed = {
|
|
386
378
|
...parsed,
|
|
387
379
|
...proj,
|
|
@@ -397,6 +389,3 @@ async function loadNpmrcLight(cwd) {
|
|
|
397
389
|
}
|
|
398
390
|
return parsed;
|
|
399
391
|
}
|
|
400
|
-
function packumentToString(p) {
|
|
401
|
-
return `${p.name}@${p["dist-tags"]?.latest ?? "?"}`;
|
|
402
|
-
}
|
|
@@ -51,9 +51,7 @@ export const workspaceCommand = {
|
|
|
51
51
|
// on isTTY (chalk, picocolors, biome) drop colors when stdout is a
|
|
52
52
|
// pipe, including GitHub Actions where the log viewer renders ANSI
|
|
53
53
|
// fine.
|
|
54
|
-
const colorEnv = process.env.FORCE_COLOR !== undefined || process.env.NO_COLOR !== undefined
|
|
55
|
-
? {}
|
|
56
|
-
: { FORCE_COLOR: '1' };
|
|
54
|
+
const colorEnv = process.env.FORCE_COLOR !== undefined || process.env.NO_COLOR !== undefined ? {} : { FORCE_COLOR: '1' };
|
|
57
55
|
await new Promise((resolve, reject) => {
|
|
58
56
|
const child = spawn(runner, argv, {
|
|
59
57
|
cwd: target.location,
|