@reliverse/dler 1.7.82 → 1.7.83

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.
@@ -64,9 +64,20 @@ declare const _default: import("@reliverse/rempts").Command<{
64
64
  type: "array";
65
65
  description: string;
66
66
  };
67
- "update-catalogs": {
67
+ "all-workspaces": {
68
68
  type: "boolean";
69
69
  description: string;
70
70
  };
71
+ "save-prefix": {
72
+ type: "string";
73
+ description: string;
74
+ allowed: string[];
75
+ default: string;
76
+ };
77
+ "allow-major": {
78
+ type: "boolean";
79
+ description: string;
80
+ default: true;
81
+ };
71
82
  }>;
72
83
  export default _default;
@@ -7,16 +7,25 @@ import { lookpath } from "lookpath";
7
7
  import pMap from "p-map";
8
8
  import { readPackageJSON } from "pkg-types";
9
9
  import semver from "semver";
10
+ import { glob } from "tinyglobby";
10
11
  import { getConfigBunfig } from "../../libs/sdk/sdk-impl/config/load.js";
11
12
  import { updateCatalogs, isCatalogSupported } from "../../libs/sdk/sdk-impl/utils/pm/pm-catalog.js";
12
13
  import { detectPackageManager } from "../../libs/sdk/sdk-impl/utils/pm/pm-detect.js";
13
14
  import { latestVersion } from "../../libs/sdk/sdk-impl/utils/pm/pm-meta.js";
15
+ const versionCache = /* @__PURE__ */ new Map();
16
+ const CACHE_TTL = 5 * 60 * 1e3;
14
17
  function isNpmAlias(versionSpec) {
15
18
  return versionSpec.startsWith("npm:");
16
19
  }
17
20
  function isWorkspaceDependency(versionSpec) {
18
21
  return versionSpec.startsWith("workspace:");
19
22
  }
23
+ function isCatalogReference(versionSpec) {
24
+ return versionSpec.startsWith("catalog:");
25
+ }
26
+ function isNonSemverSpecifier(versionSpec) {
27
+ return isNpmAlias(versionSpec) || isWorkspaceDependency(versionSpec) || isCatalogReference(versionSpec) || versionSpec.startsWith("git+") || versionSpec.startsWith("file:") || versionSpec.startsWith("link:") || versionSpec.startsWith("http:") || versionSpec.startsWith("https:");
28
+ }
20
29
  function isSemverCompatible(currentVersionRange, latestVersion2) {
21
30
  try {
22
31
  if (isNpmAlias(currentVersionRange)) {
@@ -33,6 +42,157 @@ function isSemverCompatible(currentVersionRange, latestVersion2) {
33
42
  return false;
34
43
  }
35
44
  }
45
+ function collectTargetDependencies(pkg, args) {
46
+ const map = {};
47
+ const dependencies = pkg.dependencies || {};
48
+ const devDependencies = pkg.devDependencies || {};
49
+ const peerDependencies = pkg.peerDependencies || {};
50
+ const optionalDependencies = pkg.optionalDependencies || {};
51
+ const includeDeps = !args["dev-only"] && !args["peer-only"] && !args["optional-only"] && !args["catalogs-only"];
52
+ const includeCatalogs = !args["dev-only"] && !args["peer-only"] && !args["optional-only"] && !args["prod-only"];
53
+ if (args["prod-only"] || includeDeps) {
54
+ for (const dep of Object.keys(dependencies)) {
55
+ const version = dependencies[dep];
56
+ if (!version) continue;
57
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
58
+ map[dep].versionSpec = version;
59
+ map[dep].locations.add("dependencies");
60
+ }
61
+ }
62
+ if (args["dev-only"] || includeDeps) {
63
+ for (const dep of Object.keys(devDependencies)) {
64
+ const version = devDependencies[dep];
65
+ if (!version) continue;
66
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
67
+ map[dep].versionSpec = version;
68
+ map[dep].locations.add("devDependencies");
69
+ }
70
+ }
71
+ if (args["peer-only"] || includeDeps) {
72
+ for (const dep of Object.keys(peerDependencies)) {
73
+ const version = peerDependencies[dep];
74
+ if (!version) continue;
75
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
76
+ map[dep].versionSpec = version;
77
+ map[dep].locations.add("peerDependencies");
78
+ }
79
+ }
80
+ if (args["optional-only"] || includeDeps) {
81
+ for (const dep of Object.keys(optionalDependencies)) {
82
+ const version = optionalDependencies[dep];
83
+ if (!version) continue;
84
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
85
+ map[dep].versionSpec = version;
86
+ map[dep].locations.add("optionalDependencies");
87
+ }
88
+ }
89
+ if (args["catalogs-only"] || includeCatalogs) {
90
+ const workspacesCatalog = pkg.workspaces?.catalog || {};
91
+ for (const dep of Object.keys(workspacesCatalog)) {
92
+ const version = workspacesCatalog[dep];
93
+ if (!version) continue;
94
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
95
+ map[dep].versionSpec = version;
96
+ map[dep].locations.add("catalog");
97
+ }
98
+ const workspacesCatalogs = pkg.workspaces?.catalogs || {};
99
+ for (const catalogName of Object.keys(workspacesCatalogs)) {
100
+ const catalog = workspacesCatalogs[catalogName] || {};
101
+ for (const dep of Object.keys(catalog)) {
102
+ const version = catalog[dep];
103
+ if (!version) continue;
104
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
105
+ map[dep].versionSpec = version;
106
+ map[dep].locations.add(`catalogs.${catalogName}`);
107
+ }
108
+ }
109
+ const topLevelCatalog = pkg.catalog || {};
110
+ for (const dep of Object.keys(topLevelCatalog)) {
111
+ const version = topLevelCatalog[dep];
112
+ if (!version) continue;
113
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
114
+ map[dep].versionSpec = version;
115
+ map[dep].locations.add("catalog");
116
+ }
117
+ const topLevelCatalogs = pkg.catalogs || {};
118
+ for (const catalogName of Object.keys(topLevelCatalogs)) {
119
+ const catalog = topLevelCatalogs[catalogName] || {};
120
+ for (const dep of Object.keys(catalog)) {
121
+ const version = catalog[dep];
122
+ if (!version) continue;
123
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
124
+ map[dep].versionSpec = version;
125
+ map[dep].locations.add(`catalogs.${catalogName}`);
126
+ }
127
+ }
128
+ }
129
+ return { map };
130
+ }
131
+ function applyVersionUpdate(pkg, depName, newVersion, locations) {
132
+ if (locations.has("dependencies")) {
133
+ if (!pkg.dependencies) pkg.dependencies = {};
134
+ pkg.dependencies[depName] = newVersion;
135
+ }
136
+ if (locations.has("devDependencies")) {
137
+ if (!pkg.devDependencies) pkg.devDependencies = {};
138
+ pkg.devDependencies[depName] = newVersion;
139
+ }
140
+ if (locations.has("peerDependencies")) {
141
+ if (!pkg.peerDependencies) pkg.peerDependencies = {};
142
+ pkg.peerDependencies[depName] = newVersion;
143
+ }
144
+ if (locations.has("optionalDependencies")) {
145
+ if (!pkg.optionalDependencies) pkg.optionalDependencies = {};
146
+ pkg.optionalDependencies[depName] = newVersion;
147
+ }
148
+ const ensureWorkspaces = () => {
149
+ if (!pkg.workspaces) pkg.workspaces = {};
150
+ };
151
+ if (locations.has("catalog")) {
152
+ ensureWorkspaces();
153
+ if (!pkg.workspaces.catalog) pkg.workspaces.catalog = {};
154
+ pkg.workspaces.catalog[depName] = newVersion;
155
+ if (pkg.catalog) pkg.catalog[depName] = newVersion;
156
+ }
157
+ for (const loc of locations) {
158
+ const match = /^catalogs\.(.+)$/.exec(loc);
159
+ if (match) {
160
+ const catalogName = match[1] ?? "";
161
+ if (!catalogName) continue;
162
+ ensureWorkspaces();
163
+ if (!pkg.workspaces.catalogs) pkg.workspaces.catalogs = {};
164
+ if (!pkg.workspaces.catalogs[catalogName])
165
+ pkg.workspaces.catalogs[catalogName] = {};
166
+ pkg.workspaces.catalogs[catalogName][depName] = newVersion;
167
+ if (pkg.catalogs && pkg.catalogs[catalogName]) {
168
+ pkg.catalogs[catalogName][depName] = newVersion;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ async function findWorkspacePackageJsons(cwd) {
174
+ const root = await readPackageJSON(cwd);
175
+ const ws = root.workspaces;
176
+ let patterns = [];
177
+ if (Array.isArray(ws)) {
178
+ patterns = ws;
179
+ } else if (ws && Array.isArray(ws.packages)) {
180
+ patterns = ws.packages;
181
+ }
182
+ if (!patterns.length) return [];
183
+ const dirs = await glob(patterns, {
184
+ cwd,
185
+ onlyDirectories: true,
186
+ absolute: true,
187
+ ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"]
188
+ });
189
+ const pkgJsonPaths = [];
190
+ for (const dir of dirs) {
191
+ const pj = path.join(dir, "package.json");
192
+ if (await fs.pathExists(pj)) pkgJsonPaths.push(pj);
193
+ }
194
+ return pkgJsonPaths;
195
+ }
36
196
  async function fetchVersionFromRegistry(packageName) {
37
197
  const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
38
198
  if (!response.ok) {
@@ -42,12 +202,21 @@ async function fetchVersionFromRegistry(packageName) {
42
202
  return data.version;
43
203
  }
44
204
  async function getLatestVersion(packageName) {
205
+ const cached = versionCache.get(packageName);
206
+ const now = Date.now();
207
+ if (cached && now - cached.timestamp < CACHE_TTL) {
208
+ return cached.version;
209
+ }
45
210
  try {
46
- return await latestVersion(packageName);
211
+ const version = await latestVersion(packageName);
212
+ versionCache.set(packageName, { version, timestamp: now });
213
+ return version;
47
214
  } catch (error) {
48
215
  const errorMessage = error instanceof Error ? error.message : String(error);
49
216
  try {
50
- return await fetchVersionFromRegistry(packageName);
217
+ const version = await fetchVersionFromRegistry(packageName);
218
+ versionCache.set(packageName, { version, timestamp: now });
219
+ return version;
51
220
  } catch (fallbackError) {
52
221
  throw new Error(
53
222
  `Latest version main check and npm registry fallback failed. Main check error: ${errorMessage}. Registry error: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`
@@ -55,6 +224,158 @@ async function getLatestVersion(packageName) {
55
224
  }
56
225
  }
57
226
  }
227
+ async function checkPackageUpdate(packageName, versionSpec, locations, options) {
228
+ try {
229
+ const latest = await getLatestVersion(packageName);
230
+ const cleanCurrent = versionSpec.replace(/^[\^~]/, "");
231
+ let isCompatible = isSemverCompatible(versionSpec, latest);
232
+ const isExact = !versionSpec.startsWith("^") && !versionSpec.startsWith("~");
233
+ if (isExact || !isCompatible && options.allowMajor) {
234
+ isCompatible = true;
235
+ }
236
+ return {
237
+ package: packageName,
238
+ currentVersion: cleanCurrent,
239
+ latestVersion: latest,
240
+ updated: latest !== cleanCurrent && isCompatible,
241
+ semverCompatible: isCompatible,
242
+ location: Array.from(locations).join(", ")
243
+ };
244
+ } catch (error) {
245
+ return {
246
+ package: packageName,
247
+ currentVersion: versionSpec,
248
+ latestVersion: versionSpec,
249
+ updated: false,
250
+ error: error instanceof Error ? error.message : String(error),
251
+ semverCompatible: false,
252
+ location: Array.from(locations).join(", ")
253
+ };
254
+ }
255
+ }
256
+ function prepareDependenciesForUpdate(allDepsMap, args) {
257
+ const depsToUpdate = Object.keys(allDepsMap);
258
+ let filteredDeps = [];
259
+ if (args.name && args.name.length > 0) {
260
+ filteredDeps = args.name.filter((dep) => dep in allDepsMap);
261
+ const notFound = args.name.filter((dep) => !(dep in allDepsMap));
262
+ if (notFound.length > 0) {
263
+ relinka("warn", `Dependencies not found: ${notFound.join(", ")}`);
264
+ }
265
+ } else {
266
+ const ignoreList = args.ignore || [];
267
+ filteredDeps = depsToUpdate.filter((dep) => !ignoreList.includes(dep));
268
+ }
269
+ return filteredDeps.filter((dep) => {
270
+ const versionSpec = allDepsMap[dep]?.versionSpec ?? "";
271
+ if (!versionSpec) return false;
272
+ if (isNonSemverSpecifier(versionSpec)) return false;
273
+ return true;
274
+ });
275
+ }
276
+ async function updatePackageJsonFile(packageJsonPath, dependencies, updatesToApply, savePrefix) {
277
+ if (updatesToApply.length === 0) return 0;
278
+ try {
279
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
280
+ const updatedPackageJson = { ...packageJson };
281
+ for (const update of updatesToApply) {
282
+ const prefix = savePrefix === "none" ? "" : savePrefix;
283
+ const newVersion = `${prefix}${update.latestVersion}`;
284
+ const locations = dependencies[update.package]?.locations || /* @__PURE__ */ new Set();
285
+ applyVersionUpdate(updatedPackageJson, update.package, newVersion, locations);
286
+ }
287
+ await fs.writeFile(packageJsonPath, JSON.stringify(updatedPackageJson, null, 2) + "\n", "utf8");
288
+ return updatesToApply.length;
289
+ } catch (error) {
290
+ relinka(
291
+ "warn",
292
+ `Failed to update ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`
293
+ );
294
+ return 0;
295
+ }
296
+ }
297
+ async function updateWorkspacePackages(workspacePaths, args, options) {
298
+ if (workspacePaths.length === 0) return 0;
299
+ relinka("info", `Scanning ${workspacePaths.length} workspace packages...`);
300
+ let totalWorkspaceUpdated = 0;
301
+ for (const packageJsonPath of workspacePaths) {
302
+ try {
303
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
304
+ const { map } = collectTargetDependencies(packageJson, args);
305
+ const candidates = prepareDependenciesForUpdate(map, args);
306
+ if (candidates.length === 0) continue;
307
+ const results = await pMap(
308
+ candidates,
309
+ (dep) => {
310
+ const depInfo = map[dep];
311
+ if (!depInfo?.versionSpec) {
312
+ return Promise.resolve({
313
+ package: dep,
314
+ currentVersion: "unknown",
315
+ latestVersion: "unknown",
316
+ updated: false,
317
+ error: "Current version not found",
318
+ semverCompatible: false,
319
+ location: Array.from(depInfo?.locations || ["unknown"]).join(", ")
320
+ });
321
+ }
322
+ return checkPackageUpdate(dep, depInfo.versionSpec, depInfo.locations, options);
323
+ },
324
+ { concurrency: options.concurrency }
325
+ );
326
+ const toUpdate = results.filter((r) => r.updated && !r.error);
327
+ const updated = await updatePackageJsonFile(
328
+ packageJsonPath,
329
+ map,
330
+ toUpdate,
331
+ options.savePrefix
332
+ );
333
+ if (updated > 0) {
334
+ totalWorkspaceUpdated += updated;
335
+ relinka("log", `Updated ${updated} deps in ${packageJsonPath}`);
336
+ }
337
+ } catch (error) {
338
+ relinka(
339
+ "warn",
340
+ `Skipping ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`
341
+ );
342
+ }
343
+ }
344
+ return totalWorkspaceUpdated;
345
+ }
346
+ function displayUpdateResults(results) {
347
+ const toUpdate = results.filter((r) => r.updated && !r.error);
348
+ const errors = results.filter((r) => r.error);
349
+ const upToDate = results.filter((r) => !r.updated && !r.error && r.semverCompatible);
350
+ if (errors.length > 0) {
351
+ relinka("warn", `Failed to check ${errors.length} dependencies:`);
352
+ for (const error of errors) {
353
+ relinka("warn", ` ${error.package} (${error.location}): ${error.error}`);
354
+ }
355
+ }
356
+ if (upToDate.length > 0) {
357
+ relinka("success", `${upToDate.length} dependencies are up to date`);
358
+ }
359
+ if (toUpdate.length === 0) {
360
+ relinka("success", `All ${upToDate.length} deps are already up to date`);
361
+ return;
362
+ }
363
+ relinka("info", `${toUpdate.length} dependencies can be updated:`);
364
+ const byLocation = /* @__PURE__ */ new Map();
365
+ for (const update of toUpdate) {
366
+ const location = update.location || "unknown";
367
+ if (!byLocation.has(location)) {
368
+ byLocation.set(location, []);
369
+ }
370
+ byLocation.get(location).push(update);
371
+ }
372
+ for (const [location, updates] of byLocation.entries()) {
373
+ relinka("log", ` ${location}:`);
374
+ for (const update of updates) {
375
+ relinka("log", ` ${update.package}: ${update.currentVersion} \u2192 ${update.latestVersion}`);
376
+ }
377
+ }
378
+ }
58
379
  async function getGlobalPackages(packageManager) {
59
380
  try {
60
381
  let result;
@@ -335,16 +656,16 @@ async function handleGlobalUpdates(args) {
335
656
  export default defineCommand({
336
657
  meta: {
337
658
  name: "update",
338
- description: "Update dependencies to the latest version"
659
+ description: "Update all dependencies and catalogs to their latest available versions"
339
660
  },
340
661
  args: defineArgs({
341
662
  name: {
342
663
  type: "array",
343
- description: "The names of the dependencies to update (leave empty to update all)"
664
+ description: "Specific dependencies to update (default: all dependencies)"
344
665
  },
345
666
  ignore: {
346
667
  type: "array",
347
- description: "The names of the dependencies to ignore when --name is not provided"
668
+ description: "Dependencies to exclude from updates"
348
669
  },
349
670
  "dev-only": {
350
671
  type: "boolean",
@@ -364,11 +685,11 @@ export default defineCommand({
364
685
  },
365
686
  "catalogs-only": {
366
687
  type: "boolean",
367
- description: "Update only catalog dependencies"
688
+ description: "Update ONLY catalog dependencies (catalogs are included by default)"
368
689
  },
369
690
  "dry-run": {
370
691
  type: "boolean",
371
- description: "Show what would be updated without making changes"
692
+ description: "Preview updates without making changes"
372
693
  },
373
694
  concurrency: {
374
695
  type: "number",
@@ -377,43 +698,68 @@ export default defineCommand({
377
698
  },
378
699
  "with-check-script": {
379
700
  type: "boolean",
380
- description: "Run `bun check` after updating (exclusive for bun environment at the moment)"
701
+ description: "Run `bun check` after updating (Bun only)"
381
702
  },
382
703
  linker: {
383
704
  type: "string",
384
- description: "Linker strategy (pro tip: use 'isolated' in a monorepo project, 'hoisted' (default) in a project where you have only one package.json). When this option is explicitly set, it takes precedence over bunfig.toml install.linker setting.",
705
+ description: "Linker strategy: 'isolated' for monorepos, 'hoisted' for single packages",
385
706
  allowed: ["isolated", "hoisted"],
386
707
  default: "hoisted"
387
708
  },
388
709
  "with-install": {
389
710
  type: "boolean",
390
- description: "Run the install step after updating dependencies",
711
+ description: "Run install after updating",
391
712
  alias: "with-i"
392
713
  },
393
714
  global: {
394
715
  type: "boolean",
395
- description: "Update global packages instead of local dependencies",
716
+ description: "Update global packages",
396
717
  alias: "g"
397
718
  },
398
719
  interactive: {
399
720
  type: "boolean",
400
- description: "Interactively select which dependencies to update"
721
+ description: "Interactively select dependencies to update"
401
722
  },
402
723
  filter: {
403
724
  type: "array",
404
- description: "Filter workspaces to operate on (e.g., 'pkg-*', '!pkg-c', './packages/pkg-*')"
725
+ description: "Filter workspaces (e.g., 'pkg-*', '!pkg-c')"
405
726
  },
406
- "update-catalogs": {
727
+ "all-workspaces": {
407
728
  type: "boolean",
408
- description: "Update catalog dependencies to latest versions"
729
+ description: "Update dependencies across all workspace packages"
730
+ },
731
+ "save-prefix": {
732
+ type: "string",
733
+ description: "Version prefix: '^', '~', or 'none' for exact",
734
+ allowed: ["^", "~", "none"],
735
+ default: "^"
736
+ },
737
+ "allow-major": {
738
+ type: "boolean",
739
+ description: "Allow major version updates to latest available (disable with --no-allow-major)",
740
+ default: true
409
741
  }
410
742
  }),
411
743
  async run({ args }) {
412
744
  try {
745
+ const exclusiveFlags = [
746
+ args["dev-only"],
747
+ args["prod-only"],
748
+ args["peer-only"],
749
+ args["optional-only"],
750
+ args["catalogs-only"]
751
+ ];
752
+ if (exclusiveFlags.filter(Boolean).length > 1) {
753
+ relinka(
754
+ "error",
755
+ "Cannot specify multiple exclusive flags (--dev-only, --prod-only, --peer-only, --optional-only, --catalogs-only)"
756
+ );
757
+ return process.exit(1);
758
+ }
413
759
  if (args.global) {
414
760
  return await handleGlobalUpdates(args);
415
761
  }
416
- if (args["update-catalogs"]) {
762
+ if (args["catalogs-only"]) {
417
763
  const packageManager2 = await detectPackageManager(process.cwd());
418
764
  if (!packageManager2) {
419
765
  relinka("error", "Could not detect package manager");
@@ -438,146 +784,34 @@ export default defineCommand({
438
784
  let linkerSource = "CLI default";
439
785
  if (typeof Bun !== "undefined") {
440
786
  const bunfigConfig = await getConfigBunfig();
441
- if (bunfigConfig?.install?.linker) {
442
- const bunfigLinker = bunfigConfig.install.linker;
443
- if ((bunfigLinker === "isolated" || bunfigLinker === "hoisted") && args.linker === "hoisted") {
444
- effectiveLinker = bunfigLinker;
445
- linkerSource = bunfigLinker === "hoisted" ? "bunfig.toml (same as default)" : "bunfig.toml";
446
- }
787
+ const bunfigLinker = bunfigConfig?.install?.linker;
788
+ if (bunfigLinker && ["isolated", "hoisted"].includes(bunfigLinker) && args.linker === "hoisted") {
789
+ effectiveLinker = bunfigLinker;
790
+ linkerSource = bunfigLinker === "hoisted" ? "bunfig.toml (same as default)" : "bunfig.toml";
447
791
  }
448
792
  }
449
793
  if (args.linker !== "hoisted") {
450
794
  effectiveLinker = args.linker;
451
- linkerSource = "CLI argument (explicit override)";
795
+ linkerSource = "CLI override";
452
796
  }
453
797
  relinka("verbose", `Using linker strategy: ${effectiveLinker} (from ${linkerSource})`);
454
798
  const packageJson = await readPackageJSON();
455
- const dependencies = packageJson.dependencies || {};
456
- const devDependencies = packageJson.devDependencies || {};
457
- const peerDependencies = packageJson.peerDependencies || {};
458
- const optionalDependencies = packageJson.optionalDependencies || {};
459
- const workspaces = packageJson.workspaces || {};
460
- const catalog = workspaces.catalog || packageJson.catalog || {};
461
- const catalogs = workspaces.catalogs || packageJson.catalogs || {};
462
- let targetDeps = {};
463
- const depSources = {};
464
- const exclusiveFlags = [
465
- args["dev-only"],
466
- args["prod-only"],
467
- args["peer-only"],
468
- args["optional-only"],
469
- args["catalogs-only"]
470
- ].filter(Boolean);
471
- if (exclusiveFlags.length > 1) {
472
- relinka(
473
- "error",
474
- "Cannot specify multiple exclusive flags (--dev-only, --prod-only, --peer-only, --optional-only, --catalogs-only)"
475
- );
476
- return process.exit(1);
477
- }
478
- if (args["dev-only"]) {
479
- targetDeps = { ...devDependencies };
480
- Object.keys(devDependencies).forEach((dep) => {
481
- depSources[dep] = "devDependencies";
482
- });
483
- } else if (args["prod-only"]) {
484
- targetDeps = { ...dependencies };
485
- Object.keys(dependencies).forEach((dep) => {
486
- depSources[dep] = "dependencies";
487
- });
488
- } else if (args["peer-only"]) {
489
- targetDeps = { ...peerDependencies };
490
- Object.keys(peerDependencies).forEach((dep) => {
491
- depSources[dep] = "peerDependencies";
492
- });
493
- } else if (args["optional-only"]) {
494
- targetDeps = { ...optionalDependencies };
495
- Object.keys(optionalDependencies).forEach((dep) => {
496
- depSources[dep] = "optionalDependencies";
497
- });
498
- } else if (args["catalogs-only"]) {
499
- Object.keys(catalog).forEach((dep) => {
500
- targetDeps[dep] = catalog[dep];
501
- depSources[dep] = "catalog";
502
- });
503
- Object.keys(catalogs).forEach((catalogName) => {
504
- Object.keys(catalogs[catalogName]).forEach((dep) => {
505
- targetDeps[dep] = catalogs[catalogName][dep];
506
- depSources[dep] = `catalogs.${catalogName}`;
507
- });
508
- });
509
- } else {
510
- const allDeps = {};
511
- const allDepSources = {};
512
- Object.keys(dependencies).forEach((dep) => {
513
- const version = dependencies[dep];
514
- if (version) {
515
- allDeps[dep] = version;
516
- allDepSources[dep] = "dependencies";
517
- }
518
- });
519
- Object.keys(devDependencies).forEach((dep) => {
520
- const version = devDependencies[dep];
521
- if (version) {
522
- allDeps[dep] = version;
523
- allDepSources[dep] = "devDependencies";
524
- }
525
- });
526
- Object.keys(peerDependencies).forEach((dep) => {
527
- const version = peerDependencies[dep];
528
- if (version) {
529
- allDeps[dep] = version;
530
- allDepSources[dep] = "peerDependencies";
531
- }
532
- });
533
- Object.keys(optionalDependencies).forEach((dep) => {
534
- const version = optionalDependencies[dep];
535
- if (version) {
536
- allDeps[dep] = version;
537
- allDepSources[dep] = "optionalDependencies";
538
- }
539
- });
540
- Object.keys(catalog).forEach((dep) => {
541
- allDeps[dep] = catalog[dep];
542
- allDepSources[dep] = "catalog";
543
- });
544
- Object.keys(catalogs).forEach((catalogName) => {
545
- Object.keys(catalogs[catalogName]).forEach((dep) => {
546
- allDeps[dep] = catalogs[catalogName][dep];
547
- allDepSources[dep] = `catalogs.${catalogName}`;
548
- });
549
- });
550
- targetDeps = allDeps;
551
- Object.assign(depSources, allDepSources);
552
- }
553
- const depsToUpdate = Object.keys(targetDeps);
554
- let filteredDeps = [];
555
- if (args.name && args.name.length > 0) {
556
- filteredDeps = args.name.filter((dep) => dep in targetDeps);
557
- const notFound = args.name.filter((dep) => !(dep in targetDeps));
558
- if (notFound.length > 0) {
559
- relinka("warn", `Dependencies not found: ${notFound.join(", ")}`);
560
- }
561
- } else {
562
- const ignoreList = args.ignore || [];
563
- filteredDeps = depsToUpdate.filter((dep) => !ignoreList.includes(dep));
564
- }
565
- const semverDeps = filteredDeps.filter((dep) => {
566
- const versionSpec = targetDeps[dep];
567
- return versionSpec && (versionSpec.startsWith("^") || versionSpec.startsWith("~"));
568
- });
569
- if (semverDeps.length === 0) {
570
- relinka(
571
- "warn",
572
- "No dependencies to update (only semver-compatible dependencies with ^ or ~ prefixes are supported)"
573
- );
799
+ const { map: allDepsMap } = collectTargetDependencies(packageJson, args);
800
+ const candidates = prepareDependenciesForUpdate(allDepsMap, args);
801
+ if (candidates.length === 0) {
802
+ relinka("warn", "No dependencies to update based on provided filters");
574
803
  return;
575
804
  }
805
+ const options = {
806
+ allowMajor: !!args["allow-major"],
807
+ savePrefix: args["save-prefix"],
808
+ concurrency: args.concurrency
809
+ };
576
810
  const results = await pMap(
577
- semverDeps,
811
+ candidates,
578
812
  async (dep) => {
579
- const currentVersion = targetDeps[dep];
580
- if (!currentVersion) {
813
+ const depInfo = allDepsMap[dep];
814
+ if (!depInfo?.versionSpec) {
581
815
  return {
582
816
  package: dep,
583
817
  currentVersion: "unknown",
@@ -585,63 +819,21 @@ export default defineCommand({
585
819
  updated: false,
586
820
  error: "Current version not found",
587
821
  semverCompatible: false,
588
- location: depSources[dep]
589
- };
590
- }
591
- try {
592
- const latest = await getLatestVersion(dep);
593
- const cleanCurrent = currentVersion.replace(/^[\^~]/, "");
594
- const isCompatible = isSemverCompatible(currentVersion, latest);
595
- return {
596
- package: dep,
597
- currentVersion: cleanCurrent,
598
- latestVersion: latest,
599
- updated: latest !== cleanCurrent && isCompatible,
600
- semverCompatible: isCompatible,
601
- location: depSources[dep]
602
- };
603
- } catch (error) {
604
- return {
605
- package: dep,
606
- currentVersion,
607
- latestVersion: currentVersion,
608
- updated: false,
609
- error: error instanceof Error ? error.message : String(error),
610
- semverCompatible: false,
611
- location: depSources[dep]
822
+ location: Array.from(depInfo?.locations || ["unknown"]).join(", ")
612
823
  };
613
824
  }
825
+ return checkPackageUpdate(dep, depInfo.versionSpec, depInfo.locations, options);
614
826
  },
615
827
  { concurrency: args.concurrency }
616
828
  );
829
+ displayUpdateResults(results);
617
830
  let toUpdate = results.filter((r) => r.updated && !r.error);
618
- const errors = results.filter((r) => r.error);
619
- const upToDate = results.filter((r) => !r.updated && !r.error && r.semverCompatible);
620
- if (errors.length > 0) {
621
- relinka("warn", `Failed to check ${errors.length} dependencies:`);
622
- for (const error of errors) {
623
- relinka("warn", ` ${error.package} (${error.location}): ${error.error}`);
624
- }
625
- }
626
- if (toUpdate.length === 0) {
627
- relinka("success", `All ${upToDate.length} deps are already up to date`);
628
- return;
629
- }
630
- if (upToDate.length > 0) {
631
- relinka("success", `${upToDate.length} dependencies are up to date`);
632
- }
633
831
  if (toUpdate.length === 0) {
634
- relinka("success", `All ${upToDate.length} deps are already up to date`);
635
832
  return;
636
833
  }
637
- relinka("info", `${toUpdate.length} dependencies can be updated:`);
638
- for (const update of toUpdate) {
639
- relinka(
640
- "log",
641
- ` ${update.package} (${update.location}): ${update.currentVersion} \u2192 ${update.latestVersion}`
642
- );
643
- }
644
834
  if (args.interactive) {
835
+ const errors = results.filter((r) => r.error);
836
+ const upToDate = results.filter((r) => !r.updated && !r.error && r.semverCompatible);
645
837
  const allPackages = [
646
838
  ...toUpdate.map((pkg) => ({
647
839
  ...pkg,
@@ -691,68 +883,28 @@ export default defineCommand({
691
883
  relinka("info", "Dry run mode - no changes were made");
692
884
  return;
693
885
  }
694
- const updatedPackageJson = { ...packageJson };
695
- for (const update of toUpdate) {
696
- const dep = update.package;
697
- const newVersion = `^${update.latestVersion}`;
698
- if (dependencies[dep]) {
699
- if (!updatedPackageJson.dependencies) updatedPackageJson.dependencies = {};
700
- updatedPackageJson.dependencies[dep] = newVersion;
701
- }
702
- if (devDependencies[dep]) {
703
- if (!updatedPackageJson.devDependencies) updatedPackageJson.devDependencies = {};
704
- updatedPackageJson.devDependencies[dep] = newVersion;
705
- }
706
- if (peerDependencies[dep]) {
707
- if (!updatedPackageJson.peerDependencies) updatedPackageJson.peerDependencies = {};
708
- updatedPackageJson.peerDependencies[dep] = newVersion;
709
- }
710
- if (optionalDependencies[dep]) {
711
- if (!updatedPackageJson.optionalDependencies)
712
- updatedPackageJson.optionalDependencies = {};
713
- updatedPackageJson.optionalDependencies[dep] = newVersion;
714
- }
715
- if (catalog[dep]) {
716
- if (!updatedPackageJson.workspaces) updatedPackageJson.workspaces = {};
717
- if (!updatedPackageJson.workspaces.catalog)
718
- updatedPackageJson.workspaces.catalog = {};
719
- updatedPackageJson.workspaces.catalog[dep] = newVersion;
720
- if (updatedPackageJson.catalog) {
721
- updatedPackageJson.catalog[dep] = newVersion;
722
- }
723
- }
724
- Object.keys(catalogs).forEach((catalogName) => {
725
- if (catalogs[catalogName][dep]) {
726
- if (!updatedPackageJson.workspaces)
727
- updatedPackageJson.workspaces = {};
728
- if (!updatedPackageJson.workspaces.catalogs)
729
- updatedPackageJson.workspaces.catalogs = {};
730
- if (!updatedPackageJson.workspaces.catalogs[catalogName]) {
731
- updatedPackageJson.workspaces.catalogs[catalogName] = {};
732
- }
733
- updatedPackageJson.workspaces.catalogs[catalogName][dep] = newVersion;
734
- if (updatedPackageJson.catalogs && updatedPackageJson.catalogs[catalogName]) {
735
- updatedPackageJson.catalogs[catalogName][dep] = newVersion;
736
- }
737
- }
738
- });
739
- }
740
- await fs.writeFile(
886
+ const rootUpdated = await updatePackageJsonFile(
741
887
  packageJsonPath,
742
- JSON.stringify(updatedPackageJson, null, 2) + "\n",
743
- "utf8"
888
+ allDepsMap,
889
+ toUpdate,
890
+ args["save-prefix"]
744
891
  );
745
- relinka("success", `Updated ${toUpdate.length} dependencies in package.json`);
746
- if (args["with-install"] !== true) {
747
- const packageManager2 = await detectPackageManager(process.cwd());
748
- const installCommand = packageManager2 ? `${packageManager2.command} install` : "your package manager's install command";
892
+ let totalUpdated = rootUpdated;
893
+ if (args["all-workspaces"]) {
894
+ const workspacePkgJsons = await findWorkspacePackageJsons(process.cwd());
895
+ const workspaceUpdated = await updateWorkspacePackages(workspacePkgJsons, args, options);
896
+ totalUpdated += workspaceUpdated;
897
+ }
898
+ relinka("success", `Updated ${totalUpdated} dependencies across workspace`);
899
+ const packageManager = await detectPackageManager(process.cwd());
900
+ if (!args["with-install"]) {
901
+ const installCommand = packageManager?.command || "your package manager";
749
902
  relinka(
750
903
  "info",
751
- `Skipped install step. Use --with-install flag to run '${installCommand}' after updating.`
904
+ `Skipped install step. Use --with-install to run '${installCommand} install'.`
752
905
  );
753
906
  return;
754
907
  }
755
- const packageManager = await detectPackageManager(process.cwd());
756
908
  if (packageManager) {
757
909
  try {
758
910
  if (args.filter && args.filter.length > 0) {
@@ -1,5 +1,5 @@
1
1
  import { endPrompt, startPrompt } from "@reliverse/rempts";
2
- const version = "1.7.82";
2
+ const version = "1.7.83";
3
3
  export async function showStartPrompt(isDev) {
4
4
  await startPrompt({
5
5
  titleColor: "inverse",
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "bun-plugin-tailwind": "^0.0.15",
18
18
  "cssnano": "^7.1.0",
19
19
  "defu": "^6.1.4",
20
- "esbuild": "^0.25.8",
20
+ "esbuild": "^0.25.9",
21
21
  "execa": "^9.6.0",
22
22
  "file-type": "^21.0.0",
23
23
  "fix-dts-default-cjs-exports": "^1.0.1",
@@ -33,7 +33,7 @@
33
33
  "pkg-types": "^2.2.0",
34
34
  "postcss": "^8.5.6",
35
35
  "postcss-nested": "^7.0.2",
36
- "pretty-bytes": "^7.0.0",
36
+ "pretty-bytes": "^7.0.1",
37
37
  "pretty-ms": "^9.2.0",
38
38
  "registry-auth-token": "^5.1.0",
39
39
  "registry-url": "^7.2.0",
@@ -52,7 +52,7 @@
52
52
  "license": "MIT",
53
53
  "name": "@reliverse/dler",
54
54
  "type": "module",
55
- "version": "1.7.82",
55
+ "version": "1.7.83",
56
56
  "keywords": [
57
57
  "reliverse",
58
58
  "cli",