@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.
Files changed (82) hide show
  1. package/dist/cli.gjs.mjs +132 -132
  2. package/lib/actions/barrels-generate.js +1 -5
  3. package/lib/actions/build.d.ts +3 -3
  4. package/lib/actions/build.js +56 -64
  5. package/lib/bundler-pick.d.ts +3 -3
  6. package/lib/bundler-pick.js +5 -6
  7. package/lib/commands/build.d.ts +1 -1
  8. package/lib/commands/build.js +37 -31
  9. package/lib/commands/check.js +3 -3
  10. package/lib/commands/create.d.ts +1 -1
  11. package/lib/commands/dlx.d.ts +1 -1
  12. package/lib/commands/fix.js +33 -23
  13. package/lib/commands/flatpak/build.js +6 -2
  14. package/lib/commands/flatpak/check.js +9 -3
  15. package/lib/commands/flatpak/ci.js +1 -2
  16. package/lib/commands/flatpak/deps.js +1 -2
  17. package/lib/commands/flatpak/diff.js +2 -6
  18. package/lib/commands/flatpak/init.js +19 -19
  19. package/lib/commands/flatpak/release.js +2 -2
  20. package/lib/commands/flatpak/scaffold.js +3 -11
  21. package/lib/commands/flatpak/sync-flathub.js +5 -9
  22. package/lib/commands/flatpak/utils.js +1 -6
  23. package/lib/commands/foreach.d.ts +1 -1
  24. package/lib/commands/foreach.js +5 -14
  25. package/lib/commands/format.js +54 -41
  26. package/lib/commands/generate-installer.d.ts +1 -1
  27. package/lib/commands/gettext.d.ts +1 -1
  28. package/lib/commands/gettext.js +8 -15
  29. package/lib/commands/gresource.d.ts +1 -1
  30. package/lib/commands/gresource.js +8 -13
  31. package/lib/commands/gsettings.d.ts +1 -1
  32. package/lib/commands/gsettings.js +7 -8
  33. package/lib/commands/info.d.ts +1 -1
  34. package/lib/commands/install.d.ts +1 -1
  35. package/lib/commands/install.js +45 -13
  36. package/lib/commands/lint.d.ts +1 -1
  37. package/lib/commands/lint.js +22 -22
  38. package/lib/commands/pack.d.ts +1 -1
  39. package/lib/commands/pack.js +29 -17
  40. package/lib/commands/publish.d.ts +1 -1
  41. package/lib/commands/publish.js +17 -18
  42. package/lib/commands/run.d.ts +1 -1
  43. package/lib/commands/run.js +2 -6
  44. package/lib/commands/self-update.d.ts +1 -1
  45. package/lib/commands/self-update.js +1 -3
  46. package/lib/commands/showcase.d.ts +1 -1
  47. package/lib/commands/showcase.js +1 -1
  48. package/lib/commands/system-check.d.ts +1 -1
  49. package/lib/commands/system-check.js +8 -11
  50. package/lib/commands/test.js +12 -8
  51. package/lib/commands/uninstall.d.ts +1 -1
  52. package/lib/commands/uninstall.js +1 -3
  53. package/lib/commands/upgrade.d.ts +1 -1
  54. package/lib/commands/upgrade.js +109 -120
  55. package/lib/commands/workspace.d.ts +1 -1
  56. package/lib/commands/workspace.js +1 -3
  57. package/lib/config.js +18 -13
  58. package/lib/index.js +3 -1
  59. package/lib/templates/install.mjs.tmpl +20 -14
  60. package/lib/templates/oxfmtrc.tmpl +54 -0
  61. package/lib/templates/oxlintrc.json.tmpl +35 -0
  62. package/lib/types/command.d.ts +1 -1
  63. package/lib/types/config-data.d.ts +23 -13
  64. package/lib/types/cosmiconfig-result.d.ts +1 -1
  65. package/lib/utils/check-system-deps.js +10 -4
  66. package/lib/utils/detect-native-packages.js +1 -1
  67. package/lib/utils/dlx-cache.js +2 -7
  68. package/lib/utils/install-backend-native.d.ts +2 -2
  69. package/lib/utils/install-backend-native.js +112 -58
  70. package/lib/utils/install-backend.js +2 -1
  71. package/lib/utils/install-global.js +1 -3
  72. package/lib/utils/normalize-bundler-options.js +52 -17
  73. package/lib/utils/oxc-resolve.d.ts +63 -0
  74. package/lib/utils/oxc-resolve.js +264 -0
  75. package/lib/utils/pkg-json-edit.js +1 -6
  76. package/lib/utils/run-gjs.js +1 -4
  77. package/lib/utils/run-lifecycle-script.js +3 -7
  78. package/lib/utils/workspace-root.js +3 -1
  79. package/package.json +17 -17
  80. package/lib/templates/biome.json.tmpl +0 -79
  81. package/lib/utils/biome-resolve.d.ts +0 -47
  82. 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) {
@@ -66,13 +66,15 @@ export const testCommand = {
66
66
  ? ['gjs']
67
67
  : args.runtime === 'node'
68
68
  ? ['node']
69
- : (testCfg.runtimes && testCfg.runtimes.length > 0 ? testCfg.runtimes : ['gjs', 'node']);
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, cwd);
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 = { ...(configData.library ?? {}) };
149
+ configData.library = { ...configData.library };
148
150
  configData.bundler = {
149
- ...(configData.bundler ?? {}),
151
+ ...configData.bundler,
150
152
  input: [entry],
151
- output: { ...(configData.bundler?.output ?? {}), file: outfile },
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, cwd) {
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' || entry.name === 'dist' || entry.name === 'lib' || entry.name.startsWith('.')) {
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);
@@ -5,5 +5,5 @@ interface UninstallOptions {
5
5
  'dry-run'?: boolean;
6
6
  verbose?: boolean;
7
7
  }
8
- export declare const uninstallCommand: Command<any, UninstallOptions>;
8
+ export declare const uninstallCommand: Command<unknown, UninstallOptions>;
9
9
  export {};
@@ -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(/'([^']+)'/);
@@ -1,4 +1,4 @@
1
- import type { Command } from "../types/index.js";
1
+ import type { Command } from '../types/index.js';
2
2
  interface UpgradeOptions {
3
3
  latest?: boolean;
4
4
  minor?: boolean;
@@ -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 "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";
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: "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.",
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("latest", {
27
- description: "Non-interactive: bump every dependency to its latest version (allows major).",
28
- type: "boolean",
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("minor", {
32
- description: "Non-interactive: bump every dependency to the latest within the same major (semver-minor + semver-patch).",
33
- type: "boolean",
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("patch", {
37
- description: "Non-interactive: bump every dependency to the latest within the same minor (semver-patch only).",
38
- type: "boolean",
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("filter", {
42
- description: "Only consider packages whose name matches this substring (case-insensitive). Repeatable; comma-separated values are split.",
43
- type: "string",
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("dry-run", {
46
- description: "Print the upgrade plan without writing package.json.",
47
- type: "boolean",
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("cwd", {
51
- description: "Project directory. Default: process.cwd().",
52
- type: "string",
50
+ .option('cwd', {
51
+ description: 'Project directory. Default: process.cwd().',
52
+ type: 'string',
53
53
  })
54
- .option("yes", {
55
- alias: "y",
56
- description: "Interactive mode: select all without prompting.",
57
- type: "boolean",
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("verbose", {
61
- description: "Print extra resolution details.",
62
- type: "boolean",
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, "package.json");
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, "utf-8");
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("[gjsify upgrade] no external npm dependencies to check.");
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
- ? "latest"
87
+ ? 'latest'
88
88
  : args.minor
89
- ? "minor"
89
+ ? 'minor'
90
90
  : args.patch
91
- ? "patch"
92
- : "interactive";
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("✅ all dependencies are up to date");
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 === "interactive" && !args.yes) {
101
+ if (mode === 'interactive' && !args.yes) {
102
102
  selected = await promptSelection(candidates);
103
103
  }
104
- else if (args.yes && mode === "interactive") {
105
- console.log("[gjsify upgrade] -y / --yes: selecting all");
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("[gjsify upgrade] nothing selected; package.json unchanged.");
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 !== "object")
129
+ if (!map || typeof map !== 'object')
135
130
  continue;
136
131
  for (const [name, raw] of Object.entries(map)) {
137
- if (typeof raw !== "string")
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("workspace:") ||
144
- raw.startsWith("file:") ||
145
- raw.startsWith("link:") ||
146
- raw.startsWith("git+") ||
147
- raw.startsWith("git:") ||
148
- raw.startsWith("http") ||
149
- raw.startsWith("npm:") || // e.g. `foo: npm:@scope/foo@^1`
150
- raw === "*" ||
151
- raw === "latest") {
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: "", version: null };
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["dist-tags"]?.latest;
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 === "none")
200
+ if (diff === 'none')
206
201
  continue;
207
- if (mode === "minor" && diff === "major")
202
+ if (mode === 'minor' && diff === 'major')
208
203
  continue;
209
- if (mode === "patch" && (diff === "major" || diff === "minor"))
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 "none";
226
+ return 'none';
233
227
  if (c.major !== l.major)
234
- return l.major > c.major ? "major" : "none";
228
+ return l.major > c.major ? 'major' : 'none';
235
229
  if (c.minor !== l.minor)
236
- return l.minor > c.minor ? "minor" : "none";
230
+ return l.minor > c.minor ? 'minor' : 'none';
237
231
  if (c.patch !== l.patch)
238
- return l.patch > c.patch ? "patch" : "none";
239
- if ((c.prerelease ?? []).join(".") !== (l.prerelease ?? []).join("."))
240
- return "prerelease";
241
- return "none";
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: "\x1b[0m",
246
- bold: "\x1b[1m",
247
- dim: "\x1b[2m",
248
- red: "\x1b[31m",
249
- yellow: "\x1b[33m",
250
- green: "\x1b[32m",
251
- cyan: "\x1b[36m",
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 "major":
249
+ case 'major':
256
250
  return ANSI.red;
257
- case "minor":
251
+ case 'minor':
258
252
  return ANSI.yellow;
259
- case "patch":
253
+ case 'patch':
260
254
  return ANSI.green;
261
- case "prerelease":
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 = " ".repeat(idxW) +
266
+ const head = ' '.repeat(idxW) +
273
267
  ANSI.bold +
274
- "name".padEnd(nameW) +
275
- " " +
276
- "current".padEnd(curW) +
277
- " " +
278
- "latest".padEnd(newW) +
279
- " " +
280
- "kind" +
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(" ".repeat(idxW) + ANSI.dim + "".repeat(nameW + curW + newW + 12) + ANSI.reset);
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("[gjsify upgrade] non-TTY stdin: pass --latest / --minor / --patch (or --yes for interactive-all) to upgrade non-interactively.");
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("\nSelect upgrades: comma- or space-separated indices, " +
305
+ console.log('\nSelect upgrades: comma- or space-separated indices, ' +
312
306
  ANSI.bold +
313
- "a" +
307
+ 'a' +
314
308
  ANSI.reset +
315
- " for all, ranges like " +
309
+ ' for all, ranges like ' +
316
310
  ANSI.bold +
317
- "1-3" +
311
+ '1-3' +
318
312
  ANSI.reset +
319
- ", or " +
313
+ ', or ' +
320
314
  ANSI.bold +
321
- "ENTER" +
315
+ 'ENTER' +
322
316
  ANSI.reset +
323
- " to skip:");
324
- const answer = (await rl.question("> ")).trim();
317
+ ' to skip:');
318
+ const answer = (await rl.question('> ')).trim();
325
319
  if (!answer)
326
320
  return [];
327
- if (answer.toLowerCase() === "a" || answer.toLowerCase() === "all")
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("\n") ? "\n" : ""), "utf-8");
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(), ".npmrc"), join(cwd, ".npmrc")]) {
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, "utf-8"));
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
- }
@@ -4,5 +4,5 @@ interface WorkspaceCmdOptions {
4
4
  script: string;
5
5
  args?: string[];
6
6
  }
7
- export declare const workspaceCommand: Command<any, WorkspaceCmdOptions>;
7
+ export declare const workspaceCommand: Command<unknown, WorkspaceCmdOptions>;
8
8
  export {};
@@ -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,