update-versions 7.1.3 → 7.2.1
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/CHANGELOG.md +13 -2
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/cli.js +800 -388
- package/package.json +22 -30
package/cli.js
CHANGED
|
@@ -3,33 +3,247 @@
|
|
|
3
3
|
// VARS
|
|
4
4
|
// -----------------------------------------------------------------------------
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import isOnline from "is-online";
|
|
6
|
+
import { promises, realpathSync } from "node:fs";
|
|
7
|
+
import { createRequire } from "node:module";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
11
10
|
import diff1 from "ansi-diff-stream";
|
|
11
|
+
import { glob } from "codsen-glob";
|
|
12
|
+
import { codsenCLI, isPlainObject } from "codsen-utils";
|
|
13
|
+
import { del, set } from "edit-package-json";
|
|
12
14
|
import objectPath from "object-path";
|
|
13
|
-
import write from "write-file-atomic";
|
|
14
|
-
import { createRequire } from "module";
|
|
15
|
-
import { isPlainObject } from "codsen-utils";
|
|
16
|
-
import { promises, readFileSync } from "fs";
|
|
17
|
-
import { set, del } from "edit-package-json";
|
|
18
|
-
import updateNotifier from "update-notifier";
|
|
19
15
|
import pProgress, { PProgress } from "p-progress";
|
|
16
|
+
import pReduce from "p-reduce";
|
|
17
|
+
import packageJson from "package-json";
|
|
18
|
+
import updateNotifier from "update-notifier";
|
|
20
19
|
|
|
21
20
|
const require1 = createRequire(import.meta.url);
|
|
22
21
|
const pkg = require1("./package.json");
|
|
23
22
|
|
|
24
23
|
const { readFile } = promises;
|
|
25
|
-
const diff = diff1();
|
|
26
24
|
|
|
27
25
|
const { log } = console;
|
|
28
26
|
const sparkles = "\u2728"; // https://emojipedia.org/sparkles/
|
|
29
27
|
const messagePrefix = `\u001b[${90}m${`${sparkles} update-versions: `}\u001b[${39}m`;
|
|
30
28
|
|
|
31
|
-
const
|
|
32
|
-
|
|
29
|
+
const defaultConfig = Object.freeze({
|
|
30
|
+
noMajorBumping: Object.freeze([]),
|
|
31
|
+
pin: Object.freeze({}),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function makeFailure(phase, filename, cause) {
|
|
35
|
+
let causeMessage = cause instanceof Error ? cause.message : String(cause);
|
|
36
|
+
let error = new Error(`${phase} failed for "${filename}": ${causeMessage}`);
|
|
37
|
+
error.name = "UpdateVersionsOperationError";
|
|
38
|
+
error.phase = phase;
|
|
39
|
+
error.path = filename;
|
|
40
|
+
error.cause = cause;
|
|
41
|
+
return error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class UpdateVersionsError extends AggregateError {
|
|
45
|
+
constructor(
|
|
46
|
+
errors,
|
|
47
|
+
{ updatedFiles = [], unchangedFiles = [], updatedPackages = {} } = {},
|
|
48
|
+
) {
|
|
49
|
+
let failureCount = errors.length;
|
|
50
|
+
let message = `update-versions failed with ${failureCount} ${
|
|
51
|
+
failureCount === 1 ? "error" : "errors"
|
|
52
|
+
}; ${updatedFiles.length} ${
|
|
53
|
+
updatedFiles.length === 1 ? "file was" : "files were"
|
|
54
|
+
} updated and ${unchangedFiles.length} ${
|
|
55
|
+
unchangedFiles.length === 1 ? "file was" : "files were"
|
|
56
|
+
} unchanged.`;
|
|
57
|
+
if (updatedFiles.length === 0) {
|
|
58
|
+
message += " Nothing was written.";
|
|
59
|
+
}
|
|
60
|
+
super(errors, message);
|
|
61
|
+
this.name = "UpdateVersionsError";
|
|
62
|
+
this.code = "UPDATE_VERSIONS_FAILED";
|
|
63
|
+
this.updatedFiles = [...updatedFiles];
|
|
64
|
+
this.unchangedFiles = [...unchangedFiles];
|
|
65
|
+
this.updatedPackages = { ...updatedPackages };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function parseConfig(configSource, configPath) {
|
|
70
|
+
let parsed;
|
|
71
|
+
try {
|
|
72
|
+
parsed = JSON.parse(configSource);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new TypeError(
|
|
75
|
+
`update-versions/updateVersions(): [THROW_ID_01] Could not parse "${configPath}" as JSON: ${error.message}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!isPlainObject(parsed)) {
|
|
80
|
+
throw new TypeError(
|
|
81
|
+
`update-versions/updateVersions(): [THROW_ID_02] "${configPath}" must contain a JSON object.`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let unknownKeys = Object.keys(parsed).filter(
|
|
86
|
+
(key) => !Object.hasOwn(defaultConfig, key),
|
|
87
|
+
);
|
|
88
|
+
if (unknownKeys.length > 0) {
|
|
89
|
+
throw new TypeError(
|
|
90
|
+
`update-versions/updateVersions(): [THROW_ID_03] "${configPath}" contains unsupported ${
|
|
91
|
+
unknownKeys.length === 1 ? "property" : "properties"
|
|
92
|
+
}: ${unknownKeys.sort().join(", ")}.`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (
|
|
97
|
+
parsed.noMajorBumping !== undefined &&
|
|
98
|
+
(!Array.isArray(parsed.noMajorBumping) ||
|
|
99
|
+
parsed.noMajorBumping.some(
|
|
100
|
+
(name) =>
|
|
101
|
+
typeof name !== "string" ||
|
|
102
|
+
name.trim().length === 0 ||
|
|
103
|
+
name !== name.trim(),
|
|
104
|
+
))
|
|
105
|
+
) {
|
|
106
|
+
throw new TypeError(
|
|
107
|
+
`update-versions/updateVersions(): [THROW_ID_04] "noMajorBumping" in "${configPath}" must be an array of trimmed, non-empty package-name strings.`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (parsed.pin !== undefined && !isPlainObject(parsed.pin)) {
|
|
112
|
+
throw new TypeError(
|
|
113
|
+
`update-versions/updateVersions(): [THROW_ID_05] "pin" in "${configPath}" must be a plain object.`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
parsed.pin !== undefined &&
|
|
119
|
+
Object.entries(parsed.pin).some(
|
|
120
|
+
([name, version]) =>
|
|
121
|
+
name.trim().length === 0 ||
|
|
122
|
+
name !== name.trim() ||
|
|
123
|
+
typeof version !== "string" ||
|
|
124
|
+
version.trim().length === 0 ||
|
|
125
|
+
version !== version.trim(),
|
|
126
|
+
)
|
|
127
|
+
) {
|
|
128
|
+
throw new TypeError(
|
|
129
|
+
`update-versions/updateVersions(): [THROW_ID_06] Every "pin" entry in "${configPath}" must map a trimmed, non-empty package name to a trimmed, non-empty string.`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
noMajorBumping: [
|
|
135
|
+
...new Set(parsed.noMajorBumping ?? defaultConfig.noMajorBumping),
|
|
136
|
+
],
|
|
137
|
+
pin: { ...(parsed.pin ?? defaultConfig.pin) },
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function loadConfig(configPath, readTextFile) {
|
|
142
|
+
let configSource;
|
|
143
|
+
try {
|
|
144
|
+
configSource = await readTextFile(configPath, "utf8");
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (error?.code === "ENOENT") {
|
|
147
|
+
return {
|
|
148
|
+
noMajorBumping: [...defaultConfig.noMajorBumping],
|
|
149
|
+
pin: { ...defaultConfig.pin },
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
throw makeFailure("config read", configPath, error);
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
return parseConfig(configSource, configPath);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
throw makeFailure("config validation", configPath, error);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function parseDependencySpec(dependencyName, currentSpec) {
|
|
162
|
+
if (typeof currentSpec !== "string") {
|
|
163
|
+
throw new TypeError(
|
|
164
|
+
`update-versions/updateVersions(): [THROW_ID_07] Dependency "${dependencyName}" must use a string version specifier; received ${typeof currentSpec}.`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (!currentSpec.startsWith("workspace:")) {
|
|
168
|
+
return {
|
|
169
|
+
dependencyName,
|
|
170
|
+
kind: "registry",
|
|
171
|
+
selector: currentSpec,
|
|
172
|
+
targetName: dependencyName,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let workspaceValue = currentSpec.slice("workspace:".length);
|
|
177
|
+
if (/^\.\.?\//.test(workspaceValue)) {
|
|
178
|
+
return {
|
|
179
|
+
dependencyName,
|
|
180
|
+
kind: "workspace-path",
|
|
181
|
+
path: workspaceValue,
|
|
182
|
+
selector: null,
|
|
183
|
+
targetName: null,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let aliasSeparator = workspaceValue.lastIndexOf("@");
|
|
188
|
+
if (aliasSeparator > 0) {
|
|
189
|
+
return {
|
|
190
|
+
dependencyName,
|
|
191
|
+
kind: "workspace-alias",
|
|
192
|
+
selector: workspaceValue.slice(aliasSeparator + 1),
|
|
193
|
+
targetName: workspaceValue.slice(0, aliasSeparator),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
dependencyName,
|
|
199
|
+
kind: "workspace-selector",
|
|
200
|
+
selector: workspaceValue,
|
|
201
|
+
targetName: dependencyName,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function workspaceSpecPrefix(parsedSpec) {
|
|
206
|
+
return parsedSpec.kind === "workspace-alias"
|
|
207
|
+
? `workspace:${parsedSpec.targetName}@`
|
|
208
|
+
: "workspace:";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function pinnedDependencySpec(parsedSpec, currentSpec, pinnedSpec) {
|
|
212
|
+
if (parsedSpec.kind === "registry") {
|
|
213
|
+
return pinnedSpec;
|
|
214
|
+
}
|
|
215
|
+
if (parsedSpec.kind === "workspace-path") {
|
|
216
|
+
return currentSpec;
|
|
217
|
+
}
|
|
218
|
+
let selector = pinnedSpec;
|
|
219
|
+
if (pinnedSpec.startsWith("workspace:")) {
|
|
220
|
+
let parsedPin = parseDependencySpec(parsedSpec.dependencyName, pinnedSpec);
|
|
221
|
+
selector = parsedPin.selector ?? parsedSpec.selector;
|
|
222
|
+
}
|
|
223
|
+
return `${workspaceSpecPrefix(parsedSpec)}${selector}`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function updatedDependencySpec(parsedSpec, currentSpec, version) {
|
|
227
|
+
if (parsedSpec.kind === "registry") {
|
|
228
|
+
return `^${version}`;
|
|
229
|
+
}
|
|
230
|
+
if (parsedSpec.kind === "workspace-path") {
|
|
231
|
+
return currentSpec;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let workspaceRange = parsedSpec.selector;
|
|
235
|
+
if (["*", "^", "~"].includes(workspaceRange)) {
|
|
236
|
+
return currentSpec;
|
|
237
|
+
}
|
|
238
|
+
let firstVersionDigit = workspaceRange.search(/\d/);
|
|
239
|
+
if (firstVersionDigit === -1) {
|
|
240
|
+
return currentSpec;
|
|
241
|
+
}
|
|
242
|
+
let rangePrefix = workspaceRange.slice(0, firstVersionDigit);
|
|
243
|
+
return `${workspaceSpecPrefix(parsedSpec)}${rangePrefix}${version}`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const helpText = `
|
|
33
247
|
Usage:
|
|
34
248
|
$ upd
|
|
35
249
|
$ or...
|
|
@@ -39,44 +253,70 @@ const cli = meow(
|
|
|
39
253
|
-m, --module Blacklist against bumping major any type=module packages
|
|
40
254
|
-h, --help Shows this help
|
|
41
255
|
-v, --version Shows the current installed version
|
|
42
|
-
`,
|
|
43
|
-
{
|
|
44
|
-
importMeta: import.meta,
|
|
45
|
-
},
|
|
46
|
-
);
|
|
47
|
-
updateNotifier({ pkg }).notify();
|
|
48
|
-
|
|
49
|
-
// Step #0. take care of -v and -h flags that are left out in meow.
|
|
50
|
-
// -----------------------------------------------------------------------------
|
|
51
256
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
257
|
+
Optional upd.config.json:
|
|
258
|
+
{
|
|
259
|
+
"noMajorBumping": ["package-name"],
|
|
260
|
+
"pin": { "package-name": "1.2.3" }
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
263
|
+
|
|
264
|
+
function parseCli(argv = process.argv.slice(2)) {
|
|
265
|
+
return codsenCLI(helpText, {
|
|
266
|
+
pkg,
|
|
267
|
+
argv,
|
|
268
|
+
flags: {
|
|
269
|
+
module: { type: "boolean", shortFlag: "m" },
|
|
270
|
+
help: { type: "boolean", shortFlag: "h" },
|
|
271
|
+
version: { type: "boolean", shortFlag: "v" },
|
|
272
|
+
},
|
|
273
|
+
});
|
|
58
274
|
}
|
|
59
275
|
|
|
60
|
-
//
|
|
61
|
-
//
|
|
276
|
+
// stands in for `write-file-atomic`: the file is written under a temporary
|
|
277
|
+
// name and moved into place, so an interrupted run never leaves a package.json
|
|
278
|
+
// half-written. `rename` within one directory is atomic on POSIX and on
|
|
279
|
+
// Windows, and the existing mode is carried over.
|
|
280
|
+
async function writeFileAtomically(filename, contents) {
|
|
281
|
+
const temporaryFilename = `${filename}.${process.pid}.${Date.now()}.tmp`;
|
|
282
|
+
|
|
283
|
+
let mode;
|
|
284
|
+
try {
|
|
285
|
+
({ mode } = await promises.stat(filename));
|
|
286
|
+
} catch {
|
|
287
|
+
// a file that does not exist yet keeps the default mode
|
|
288
|
+
}
|
|
62
289
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// the flags position does not matter, they don't affect the keywords that follow.
|
|
68
|
-
if (cli.flags) {
|
|
69
|
-
Object.keys(cli.flags).forEach((flag) => {
|
|
70
|
-
if (typeof cli.flags[flag] === "string") {
|
|
71
|
-
input = input.concat(cli.flags[flag]);
|
|
290
|
+
await promises.writeFile(temporaryFilename, contents);
|
|
291
|
+
try {
|
|
292
|
+
if (mode !== undefined) {
|
|
293
|
+
await promises.chmod(temporaryFilename, mode);
|
|
72
294
|
}
|
|
73
|
-
|
|
295
|
+
await promises.rename(temporaryFilename, filename);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
await promises.rm(temporaryFilename, { force: true });
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
74
300
|
}
|
|
75
301
|
|
|
76
|
-
// Step #
|
|
302
|
+
// Step #1. the main function
|
|
77
303
|
// -----------------------------------------------------------------------------
|
|
78
304
|
|
|
79
|
-
|
|
305
|
+
export async function updateVersions({
|
|
306
|
+
cwd = process.cwd(),
|
|
307
|
+
effects = {},
|
|
308
|
+
fetchPackage = packageJson,
|
|
309
|
+
moduleMode = false,
|
|
310
|
+
reportProgress = false,
|
|
311
|
+
} = {}) {
|
|
312
|
+
let {
|
|
313
|
+
deleteJsonValue = del,
|
|
314
|
+
findPackageJsons = glob,
|
|
315
|
+
readTextFile = readFile,
|
|
316
|
+
setJsonValue = set,
|
|
317
|
+
writeTextFile = writeFileAtomically,
|
|
318
|
+
} = effects;
|
|
319
|
+
|
|
80
320
|
// we'll use the object below to distil all unique package updates
|
|
81
321
|
let updatedPackages = {};
|
|
82
322
|
function printUpdated() {
|
|
@@ -86,68 +326,158 @@ if (cli.flags) {
|
|
|
86
326
|
.join("\n");
|
|
87
327
|
}
|
|
88
328
|
function major(versNum) {
|
|
89
|
-
if (typeof versNum === "string"
|
|
90
|
-
return
|
|
329
|
+
if (typeof versNum === "string") {
|
|
330
|
+
return (
|
|
331
|
+
versNum.match(/^(?:workspace:)?[^\d]*(\d+)(?:\.|$)/)?.[1] ?? versNum
|
|
332
|
+
);
|
|
91
333
|
}
|
|
92
334
|
return versNum;
|
|
93
335
|
}
|
|
94
336
|
|
|
95
|
-
let
|
|
96
|
-
let newConfig
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
let online = await isOnline();
|
|
102
|
-
if (!online) {
|
|
103
|
-
console.error(
|
|
104
|
-
`\n${messagePrefix}${`\u001b[${31}m${"Please check your internet connection."}\u001b[${39}m`}\n`,
|
|
105
|
-
);
|
|
106
|
-
process.exit(1);
|
|
337
|
+
let configPath = path.join(cwd, "upd.config.json");
|
|
338
|
+
let newConfig;
|
|
339
|
+
try {
|
|
340
|
+
newConfig = await loadConfig(configPath, readTextFile);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
throw new UpdateVersionsError([error]);
|
|
107
343
|
}
|
|
108
344
|
|
|
109
|
-
|
|
345
|
+
let packagePaths;
|
|
110
346
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
`\n${messagePrefix}${`\u001b[${90}m${"No config found, moving on."}\u001b[${39}m`}\n`,
|
|
347
|
+
packagePaths = await findPackageJsons(
|
|
348
|
+
["**/package.json", "!**/node_modules/**", "!**/test/**"],
|
|
349
|
+
{ cwd },
|
|
115
350
|
);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
throw new UpdateVersionsError([
|
|
353
|
+
makeFailure("package discovery", cwd, error),
|
|
354
|
+
]);
|
|
116
355
|
}
|
|
117
356
|
|
|
118
|
-
let
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
357
|
+
let inventoryFailures = [];
|
|
358
|
+
let pathsPromise = await pReduce(
|
|
359
|
+
packagePaths,
|
|
360
|
+
async (mapReceived, currentPath) => {
|
|
361
|
+
let packagePath = path.join(cwd, currentPath);
|
|
362
|
+
let packContentsStr;
|
|
363
|
+
try {
|
|
364
|
+
packContentsStr = await readTextFile(packagePath, "utf8");
|
|
365
|
+
} catch (error) {
|
|
366
|
+
inventoryFailures.push(makeFailure("package read", currentPath, error));
|
|
367
|
+
return mapReceived;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
let parsedContents;
|
|
371
|
+
try {
|
|
372
|
+
parsedContents = JSON.parse(packContentsStr);
|
|
373
|
+
if (!isPlainObject(parsedContents)) {
|
|
374
|
+
throw new TypeError(
|
|
375
|
+
"update-versions/updateVersions(): [THROW_ID_08] package.json must contain a JSON object.",
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
} catch (error) {
|
|
379
|
+
inventoryFailures.push(
|
|
380
|
+
makeFailure("package parse", currentPath, error),
|
|
381
|
+
);
|
|
382
|
+
return mapReceived;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
mapReceived.namesList.push(parsedContents.name);
|
|
386
|
+
mapReceived.pathsList.push(currentPath);
|
|
387
|
+
mapReceived.pathsByName[parsedContents.name] = currentPath;
|
|
388
|
+
mapReceived.contentsStr[currentPath] = packContentsStr;
|
|
389
|
+
mapReceived.contentsObj[currentPath] = parsedContents;
|
|
390
|
+
return mapReceived;
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
namesList: [],
|
|
394
|
+
pathsList: [],
|
|
395
|
+
pathsByName: {},
|
|
396
|
+
contentsObj: {},
|
|
397
|
+
contentsStr: {},
|
|
398
|
+
},
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
if (inventoryFailures.length > 0) {
|
|
402
|
+
throw new UpdateVersionsError(inventoryFailures, {
|
|
403
|
+
unchangedFiles: pathsPromise.pathsList,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Resolve the complete registry view before touching any package.json. This
|
|
408
|
+
// makes a failed registry run atomic from the caller's point of view and also
|
|
409
|
+
// deduplicates lookups shared by packages in a monorepo.
|
|
410
|
+
let externalNames = new Set();
|
|
411
|
+
for (let oneOfPaths of pathsPromise.pathsList) {
|
|
412
|
+
let parsedContents = pathsPromise.contentsObj[oneOfPaths];
|
|
413
|
+
for (let dependencyKey of ["dependencies", "devDependencies"]) {
|
|
414
|
+
if (isPlainObject(parsedContents[dependencyKey])) {
|
|
415
|
+
for (let [name, spec] of Object.entries(
|
|
416
|
+
parsedContents[dependencyKey],
|
|
417
|
+
)) {
|
|
418
|
+
if (
|
|
419
|
+
typeof spec === "string" &&
|
|
420
|
+
!spec.startsWith("file:") &&
|
|
421
|
+
!Object.hasOwn(newConfig.pin, name)
|
|
422
|
+
) {
|
|
423
|
+
let parsedSpec = parseDependencySpec(name, spec);
|
|
424
|
+
if (
|
|
425
|
+
parsedSpec.targetName &&
|
|
426
|
+
!pathsPromise.namesList.includes(parsedSpec.targetName)
|
|
427
|
+
) {
|
|
428
|
+
externalNames.add(parsedSpec.targetName);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
let registryFailures = [];
|
|
437
|
+
let registryMetadata = new Map();
|
|
438
|
+
let registryResults = await Promise.all(
|
|
439
|
+
[...externalNames].map(async (name) => {
|
|
440
|
+
try {
|
|
441
|
+
let metadata = await fetchPackage(name, { fullMetadata: true });
|
|
442
|
+
if (
|
|
443
|
+
!metadata ||
|
|
444
|
+
typeof metadata.version !== "string" ||
|
|
445
|
+
metadata.version.length === 0
|
|
446
|
+
) {
|
|
447
|
+
throw new TypeError(`${name} returned no version`);
|
|
448
|
+
}
|
|
449
|
+
return { metadata, name };
|
|
450
|
+
} catch (error) {
|
|
451
|
+
return { error, name };
|
|
452
|
+
}
|
|
453
|
+
}),
|
|
150
454
|
);
|
|
455
|
+
for (let result of registryResults) {
|
|
456
|
+
if (result.error) {
|
|
457
|
+
registryFailures.push(
|
|
458
|
+
makeFailure("registry lookup", result.name, result.error),
|
|
459
|
+
);
|
|
460
|
+
} else {
|
|
461
|
+
registryMetadata.set(result.name, result.metadata);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (registryFailures.length > 0) {
|
|
466
|
+
throw new UpdateVersionsError(registryFailures, {
|
|
467
|
+
unchangedFiles: pathsPromise.pathsList,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (moduleMode) {
|
|
472
|
+
for (let [name, metadata] of registryMetadata) {
|
|
473
|
+
if (
|
|
474
|
+
metadata?.type === "module" &&
|
|
475
|
+
!newConfig.noMajorBumping.includes(name)
|
|
476
|
+
) {
|
|
477
|
+
newConfig.noMajorBumping.push(name);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
151
481
|
|
|
152
482
|
let allProgressPromise = PProgress.all(
|
|
153
483
|
pathsPromise.pathsList.map((oneOfPaths) =>
|
|
@@ -157,329 +487,411 @@ if (cli.flags) {
|
|
|
157
487
|
let amended = false;
|
|
158
488
|
let finalContents = pathsPromise.contentsStr[oneOfPaths];
|
|
159
489
|
let parsedContents = pathsPromise.contentsObj[oneOfPaths];
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
490
|
+
let fileUpdates = {};
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
let totalDeps = (
|
|
494
|
+
isPlainObject(parsedContents.dependencies)
|
|
495
|
+
? Object.keys(parsedContents.dependencies)
|
|
496
|
+
: []
|
|
497
|
+
).concat(
|
|
498
|
+
isPlainObject(parsedContents.devDependencies)
|
|
499
|
+
? Object.keys(parsedContents.devDependencies)
|
|
500
|
+
: [],
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
//
|
|
504
|
+
//
|
|
505
|
+
//
|
|
506
|
+
//
|
|
507
|
+
//
|
|
508
|
+
//
|
|
509
|
+
//
|
|
510
|
+
// 1. LOOKUP OF ALL DEPS & DEV-DEPS ALL AT ONCE
|
|
511
|
+
//
|
|
512
|
+
//
|
|
513
|
+
//
|
|
514
|
+
//
|
|
515
|
+
//
|
|
516
|
+
//
|
|
517
|
+
//
|
|
518
|
+
|
|
519
|
+
// All external metadata was resolved before this processing phase, so
|
|
520
|
+
// no package can be written while another registry request is pending.
|
|
521
|
+
let compiledDepNameVersionPairs = {};
|
|
522
|
+
for (let singleDepName of totalDeps) {
|
|
523
|
+
let singleDepValue = Object.hasOwn(
|
|
524
|
+
parsedContents.dependencies ?? {},
|
|
525
|
+
singleDepName,
|
|
526
|
+
)
|
|
527
|
+
? parsedContents.dependencies[singleDepName]
|
|
528
|
+
: parsedContents.devDependencies[singleDepName];
|
|
529
|
+
let parsedSpec = parseDependencySpec(singleDepName, singleDepValue);
|
|
530
|
+
if (pathsPromise.namesList.includes(parsedSpec.targetName)) {
|
|
531
|
+
let localVersion =
|
|
199
532
|
pathsPromise.contentsObj[
|
|
200
|
-
pathsPromise.pathsByName[
|
|
533
|
+
pathsPromise.pathsByName[parsedSpec.targetName]
|
|
201
534
|
].version;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
.then((pkg1) => {
|
|
210
|
-
if (pkg1.version === null) {
|
|
211
|
-
throw new Error(
|
|
212
|
-
`${messagePrefix}${singleDepName} version from npm came as null, CLI will exit now, nothing was written.`,
|
|
213
|
-
);
|
|
214
|
-
} else {
|
|
215
|
-
compiledDepNameVersionPairs[singleDepName] = pkg1.version;
|
|
216
|
-
|
|
217
|
-
if (
|
|
218
|
-
(cli.flags.m || cli.flags.module) &&
|
|
219
|
-
pkg1.type === "module"
|
|
220
|
-
) {
|
|
221
|
-
newConfig.noMajorBumping.push(pkg1.name);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
} catch (e) {
|
|
226
|
-
// no response from npm
|
|
227
|
-
compiledDepNameVersionPairs[singleDepName] = null;
|
|
228
|
-
}
|
|
229
|
-
}),
|
|
230
|
-
);
|
|
231
|
-
allProgressPromise2.onProgress((val) => {
|
|
232
|
-
// console.log(
|
|
233
|
-
// `197 ${`\u001b[${32}m${`CALL PROGRESS():`} ${val *
|
|
234
|
-
// 0.75}\u001b[${39}m`}`
|
|
235
|
-
// );
|
|
236
|
-
progress(val * 0.75);
|
|
237
|
-
});
|
|
238
|
-
await allProgressPromise2;
|
|
239
|
-
|
|
240
|
-
// Now we need to simultaneously query all the deps, dev and normal ones.
|
|
241
|
-
// We rely on pacote's caching mechanism.
|
|
242
|
-
|
|
243
|
-
// The plan is to query all the deps at once, then await the result,
|
|
244
|
-
// then process received result, picking values we need from it.
|
|
245
|
-
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
// 2. DEPS
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
if (isPlainObject(parsedContents.dependencies)) {
|
|
263
|
-
let keys = Object.keys(parsedContents.dependencies);
|
|
264
|
-
for (let y = 0, len2 = keys.length; y < len2; y++) {
|
|
265
|
-
// delete this dependency from lect.various.devDependencies if present
|
|
266
|
-
// ---------------------
|
|
267
|
-
if (
|
|
268
|
-
objectPath.has(parsedContents, "lect.various.devDependencies") &&
|
|
269
|
-
Array.isArray(parsedContents.lect.various.devDependencies) &&
|
|
270
|
-
parsedContents.lect.various.devDependencies.includes(keys[y])
|
|
271
|
-
) {
|
|
272
|
-
let foundIdx;
|
|
273
|
-
let newVal = parsedContents.lect.various.devDependencies.filter(
|
|
274
|
-
(dep, z) => {
|
|
275
|
-
if (dep === keys[y]) {
|
|
276
|
-
foundIdx = z;
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
return true;
|
|
280
|
-
},
|
|
281
|
-
);
|
|
282
|
-
parsedContents.lect.various.devDependencies = newVal;
|
|
283
|
-
finalContents = del(
|
|
284
|
-
finalContents,
|
|
285
|
-
`lect.various.devDependencies.${foundIdx}`,
|
|
286
|
-
);
|
|
535
|
+
compiledDepNameVersionPairs[singleDepName] =
|
|
536
|
+
typeof localVersion === "string" && localVersion.length > 0
|
|
537
|
+
? localVersion
|
|
538
|
+
: null;
|
|
539
|
+
} else {
|
|
540
|
+
compiledDepNameVersionPairs[singleDepName] =
|
|
541
|
+
registryMetadata.get(parsedSpec.targetName)?.version ?? null;
|
|
287
542
|
}
|
|
543
|
+
}
|
|
544
|
+
progress(0.75);
|
|
545
|
+
|
|
546
|
+
//
|
|
547
|
+
//
|
|
548
|
+
//
|
|
549
|
+
//
|
|
550
|
+
//
|
|
551
|
+
//
|
|
552
|
+
//
|
|
553
|
+
// 2. DEPS
|
|
554
|
+
//
|
|
555
|
+
//
|
|
556
|
+
//
|
|
557
|
+
//
|
|
558
|
+
//
|
|
559
|
+
//
|
|
560
|
+
//
|
|
288
561
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (singleDepValue.startsWith("file:")) {
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
let workspacePrefix = singleDepValue.startsWith("workspace:")
|
|
298
|
-
? "workspace:"
|
|
299
|
-
: "";
|
|
300
|
-
|
|
301
|
-
if (Array.isArray(newConfig?.pin) && newConfig.pin[singleDepName]) {
|
|
302
|
-
finalContents = set(
|
|
303
|
-
finalContents,
|
|
304
|
-
`dependencies.${singleDepName}`,
|
|
305
|
-
newConfig.pin[singleDepName],
|
|
306
|
-
);
|
|
307
|
-
amended = true;
|
|
562
|
+
if (isPlainObject(parsedContents.dependencies)) {
|
|
563
|
+
let keys = Object.keys(parsedContents.dependencies);
|
|
564
|
+
for (let y = 0, len2 = keys.length; y < len2; y++) {
|
|
565
|
+
// delete this dependency from lect.various.devDependencies if present
|
|
566
|
+
// ---------------------
|
|
308
567
|
if (
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
)
|
|
568
|
+
objectPath.has(
|
|
569
|
+
parsedContents,
|
|
570
|
+
"lect.various.devDependencies",
|
|
571
|
+
) &&
|
|
572
|
+
Array.isArray(parsedContents.lect.various.devDependencies) &&
|
|
573
|
+
parsedContents.lect.various.devDependencies.includes(keys[y])
|
|
313
574
|
) {
|
|
314
|
-
|
|
575
|
+
let foundIdx;
|
|
576
|
+
let newVal = parsedContents.lect.various.devDependencies.filter(
|
|
577
|
+
(dep, z) => {
|
|
578
|
+
if (dep === keys[y]) {
|
|
579
|
+
foundIdx = z;
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
return true;
|
|
583
|
+
},
|
|
584
|
+
);
|
|
585
|
+
parsedContents.lect.various.devDependencies = newVal;
|
|
586
|
+
finalContents = deleteJsonValue(
|
|
587
|
+
finalContents,
|
|
588
|
+
`lect.various.devDependencies.${foundIdx}`,
|
|
589
|
+
);
|
|
590
|
+
amended = true;
|
|
315
591
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
`dependencies.${singleDepName}`,
|
|
329
|
-
`${workspacePrefix}^${compiledDepNameVersionPairs[singleDepName]}`,
|
|
592
|
+
|
|
593
|
+
// tackle the deps list:
|
|
594
|
+
// ---------------------
|
|
595
|
+
|
|
596
|
+
let singleDepName = keys[y];
|
|
597
|
+
let singleDepValue = parsedContents.dependencies[keys[y]];
|
|
598
|
+
if (singleDepValue.startsWith("file:")) {
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
let parsedSpec = parseDependencySpec(
|
|
602
|
+
singleDepName,
|
|
603
|
+
singleDepValue,
|
|
330
604
|
);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
singleDepName,
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
605
|
+
if (Object.hasOwn(newConfig.pin, singleDepName)) {
|
|
606
|
+
let nextSpec = pinnedDependencySpec(
|
|
607
|
+
parsedSpec,
|
|
608
|
+
singleDepValue,
|
|
609
|
+
newConfig.pin[singleDepName],
|
|
610
|
+
);
|
|
611
|
+
if (singleDepValue !== nextSpec) {
|
|
612
|
+
finalContents = setJsonValue(
|
|
613
|
+
finalContents,
|
|
614
|
+
`dependencies.${singleDepName}`,
|
|
615
|
+
nextSpec,
|
|
616
|
+
);
|
|
617
|
+
amended = true;
|
|
618
|
+
fileUpdates[singleDepName] = nextSpec;
|
|
619
|
+
}
|
|
620
|
+
} else if (compiledDepNameVersionPairs[singleDepName] !== null) {
|
|
621
|
+
let nextSpec = updatedDependencySpec(
|
|
622
|
+
parsedSpec,
|
|
623
|
+
singleDepValue,
|
|
624
|
+
compiledDepNameVersionPairs[singleDepName],
|
|
625
|
+
);
|
|
626
|
+
if (
|
|
627
|
+
singleDepValue !== nextSpec &&
|
|
628
|
+
// either dependency is not blacklisted (so we don't care)
|
|
629
|
+
(!newConfig.noMajorBumping.some((name) =>
|
|
630
|
+
[singleDepName, parsedSpec.targetName].includes(name),
|
|
631
|
+
) ||
|
|
632
|
+
// or it is blacklisted but the bump is within the same major semver digit
|
|
633
|
+
major(compiledDepNameVersionPairs[singleDepName]) ===
|
|
634
|
+
major(parsedSpec.selector))
|
|
635
|
+
) {
|
|
636
|
+
finalContents = setJsonValue(
|
|
637
|
+
finalContents,
|
|
638
|
+
`dependencies.${singleDepName}`,
|
|
639
|
+
nextSpec,
|
|
640
|
+
);
|
|
641
|
+
amended = true;
|
|
642
|
+
fileUpdates[singleDepName] =
|
|
643
|
+
compiledDepNameVersionPairs[singleDepName];
|
|
644
|
+
}
|
|
340
645
|
}
|
|
341
|
-
}
|
|
342
646
|
|
|
343
|
-
|
|
344
|
-
|
|
647
|
+
// report progress
|
|
648
|
+
// ---------------------
|
|
345
649
|
|
|
346
|
-
|
|
347
|
-
|
|
650
|
+
// total: totalDeps, current chunk total: len2
|
|
651
|
+
progress(0.75 + 0.24 * (y / totalDeps.length));
|
|
652
|
+
}
|
|
348
653
|
}
|
|
349
|
-
}
|
|
350
654
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
for (let y = 0, len2 = keys.length; y < len2; y++) {
|
|
388
|
-
let singleDepName = keys[y];
|
|
389
|
-
let singleDepValue = parsedContents.devDependencies[keys[y]];
|
|
390
|
-
if (singleDepValue.startsWith("file:")) {
|
|
391
|
-
continue;
|
|
655
|
+
//
|
|
656
|
+
//
|
|
657
|
+
//
|
|
658
|
+
//
|
|
659
|
+
//
|
|
660
|
+
//
|
|
661
|
+
//
|
|
662
|
+
// 3. DEV-DEPS
|
|
663
|
+
//
|
|
664
|
+
//
|
|
665
|
+
//
|
|
666
|
+
//
|
|
667
|
+
//
|
|
668
|
+
//
|
|
669
|
+
//
|
|
670
|
+
|
|
671
|
+
if (isPlainObject(parsedContents.devDependencies)) {
|
|
672
|
+
let keys = Object.keys(parsedContents.devDependencies);
|
|
673
|
+
// 1. first, remove deps which if they are in normal dependencies in
|
|
674
|
+
// package.json, that's our value parsedContents.dependencies
|
|
675
|
+
if (isPlainObject(parsedContents.dependencies)) {
|
|
676
|
+
Object.keys(parsedContents.dependencies).forEach((depName) => {
|
|
677
|
+
if (keys.includes(depName)) {
|
|
678
|
+
// 1. delete dev-dep entry on JSON string
|
|
679
|
+
finalContents = deleteJsonValue(
|
|
680
|
+
finalContents,
|
|
681
|
+
`devDependencies.${depName}`,
|
|
682
|
+
);
|
|
683
|
+
// 2. delete the dev-dep from parsedContents.devDependencies
|
|
684
|
+
// key array which will be used to traverse in the loop later
|
|
685
|
+
keys = keys.filter((val) => val !== depName);
|
|
686
|
+
// 3. set the flag to activate the file write operation later
|
|
687
|
+
amended = true;
|
|
688
|
+
}
|
|
689
|
+
});
|
|
392
690
|
}
|
|
393
|
-
let
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
finalContents = set(
|
|
399
|
-
finalContents,
|
|
400
|
-
`dependencies.${singleDepName}`,
|
|
401
|
-
newConfig.pin[singleDepName],
|
|
402
|
-
);
|
|
403
|
-
amended = true;
|
|
404
|
-
if (
|
|
405
|
-
!Object.prototype.hasOwnProperty.call(
|
|
406
|
-
updatedPackages,
|
|
407
|
-
singleDepName,
|
|
408
|
-
)
|
|
409
|
-
) {
|
|
410
|
-
updatedPackages[singleDepName] = newConfig.pin[singleDepName];
|
|
691
|
+
for (let y = 0, len2 = keys.length; y < len2; y++) {
|
|
692
|
+
let singleDepName = keys[y];
|
|
693
|
+
let singleDepValue = parsedContents.devDependencies[keys[y]];
|
|
694
|
+
if (singleDepValue.startsWith("file:")) {
|
|
695
|
+
continue;
|
|
411
696
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
`${workspacePrefix}^${compiledDepNameVersionPairs[singleDepName]}` &&
|
|
416
|
-
// either dependency is not blacklisted (so we don't care)
|
|
417
|
-
(!newConfig.noMajorBumping.includes(singleDepName) ||
|
|
418
|
-
// or it is blacklisted but the bump is within the same major semver digit
|
|
419
|
-
major(compiledDepNameVersionPairs[singleDepName]) ===
|
|
420
|
-
major(singleDepValue))
|
|
421
|
-
) {
|
|
422
|
-
finalContents = set(
|
|
423
|
-
finalContents,
|
|
424
|
-
`devDependencies.${singleDepName}`,
|
|
425
|
-
`${workspacePrefix}^${compiledDepNameVersionPairs[singleDepName]}`,
|
|
697
|
+
let parsedSpec = parseDependencySpec(
|
|
698
|
+
singleDepName,
|
|
699
|
+
singleDepValue,
|
|
426
700
|
);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
701
|
+
if (Object.hasOwn(newConfig.pin, singleDepName)) {
|
|
702
|
+
let nextSpec = pinnedDependencySpec(
|
|
703
|
+
parsedSpec,
|
|
704
|
+
singleDepValue,
|
|
705
|
+
newConfig.pin[singleDepName],
|
|
706
|
+
);
|
|
707
|
+
if (singleDepValue !== nextSpec) {
|
|
708
|
+
finalContents = setJsonValue(
|
|
709
|
+
finalContents,
|
|
710
|
+
`devDependencies.${singleDepName}`,
|
|
711
|
+
nextSpec,
|
|
712
|
+
);
|
|
713
|
+
amended = true;
|
|
714
|
+
fileUpdates[singleDepName] = nextSpec;
|
|
715
|
+
}
|
|
716
|
+
} else if (compiledDepNameVersionPairs[singleDepName] !== null) {
|
|
717
|
+
let nextSpec = updatedDependencySpec(
|
|
718
|
+
parsedSpec,
|
|
719
|
+
singleDepValue,
|
|
720
|
+
compiledDepNameVersionPairs[singleDepName],
|
|
721
|
+
);
|
|
722
|
+
if (
|
|
723
|
+
singleDepValue !== nextSpec &&
|
|
724
|
+
// either dependency is not blacklisted (so we don't care)
|
|
725
|
+
(!newConfig.noMajorBumping.some((name) =>
|
|
726
|
+
[singleDepName, parsedSpec.targetName].includes(name),
|
|
727
|
+
) ||
|
|
728
|
+
// or it is blacklisted but the bump is within the same major semver digit
|
|
729
|
+
major(compiledDepNameVersionPairs[singleDepName]) ===
|
|
730
|
+
major(parsedSpec.selector))
|
|
731
|
+
) {
|
|
732
|
+
finalContents = setJsonValue(
|
|
733
|
+
finalContents,
|
|
734
|
+
`devDependencies.${singleDepName}`,
|
|
735
|
+
nextSpec,
|
|
736
|
+
);
|
|
737
|
+
amended = true;
|
|
738
|
+
fileUpdates[singleDepName] =
|
|
739
|
+
compiledDepNameVersionPairs[singleDepName];
|
|
740
|
+
}
|
|
438
741
|
}
|
|
439
|
-
}
|
|
440
742
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
743
|
+
progress(
|
|
744
|
+
0.75 +
|
|
745
|
+
0.24 * ((totalDeps.length - len2 + y) / totalDeps.length),
|
|
746
|
+
);
|
|
747
|
+
}
|
|
444
748
|
}
|
|
445
|
-
}
|
|
446
749
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
750
|
+
if (Object.hasOwn(parsedContents, "gitHead")) {
|
|
751
|
+
finalContents = deleteJsonValue(finalContents, "gitHead");
|
|
752
|
+
amended = true;
|
|
753
|
+
}
|
|
754
|
+
} catch (error) {
|
|
755
|
+
progress(1);
|
|
756
|
+
return {
|
|
757
|
+
error: makeFailure("package transform", oneOfPaths, error),
|
|
758
|
+
path: oneOfPaths,
|
|
759
|
+
};
|
|
452
760
|
}
|
|
453
761
|
|
|
454
762
|
if (amended) {
|
|
455
763
|
try {
|
|
456
|
-
await
|
|
457
|
-
} catch (
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
764
|
+
await writeTextFile(path.join(cwd, oneOfPaths), finalContents);
|
|
765
|
+
} catch (error) {
|
|
766
|
+
progress(1);
|
|
767
|
+
return {
|
|
768
|
+
error: makeFailure("package write", oneOfPaths, error),
|
|
769
|
+
path: oneOfPaths,
|
|
770
|
+
};
|
|
461
771
|
}
|
|
772
|
+
progress(1);
|
|
773
|
+
return { path: oneOfPaths, status: "updated", updates: fileUpdates };
|
|
462
774
|
}
|
|
775
|
+
|
|
776
|
+
progress(1);
|
|
777
|
+
return { path: oneOfPaths, status: "unchanged", updates: fileUpdates };
|
|
463
778
|
}),
|
|
464
779
|
),
|
|
465
780
|
);
|
|
466
781
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
782
|
+
let diff;
|
|
783
|
+
if (reportProgress) {
|
|
784
|
+
diff = diff1();
|
|
785
|
+
allProgressPromise.onProgress((val) => {
|
|
786
|
+
if (val < 1) {
|
|
787
|
+
diff.write(`${messagePrefix}${Math.floor(val * 100)}% done`);
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
diff.pipe(process.stdout);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
let processingResults = await allProgressPromise;
|
|
794
|
+
let processingFailures = [];
|
|
795
|
+
let unchangedFiles = [];
|
|
796
|
+
let updatedFiles = [];
|
|
797
|
+
|
|
798
|
+
for (let result of processingResults) {
|
|
799
|
+
if (result.error) {
|
|
800
|
+
processingFailures.push(result.error);
|
|
801
|
+
} else if (result.status === "updated") {
|
|
802
|
+
updatedFiles.push(result.path);
|
|
803
|
+
for (let [name, version] of Object.entries(result.updates)) {
|
|
804
|
+
if (!Object.hasOwn(updatedPackages, name)) {
|
|
805
|
+
updatedPackages[name] = version;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
} else {
|
|
809
|
+
unchangedFiles.push(result.path);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (diff) {
|
|
814
|
+
if (processingFailures.length > 0) {
|
|
815
|
+
diff.write(
|
|
816
|
+
`${messagePrefix}completed with ${processingFailures.length} ${
|
|
817
|
+
processingFailures.length === 1 ? "failure" : "failures"
|
|
818
|
+
}; ${updatedFiles.length} updated, ${unchangedFiles.length} unchanged${
|
|
819
|
+
Object.keys(updatedPackages).length ? `:\n${printUpdated()}` : ""
|
|
820
|
+
}`,
|
|
821
|
+
);
|
|
822
|
+
} else {
|
|
823
|
+
diff.write(
|
|
824
|
+
`${messagePrefix}${
|
|
825
|
+
updatedFiles.length > 0 && Object.keys(updatedPackages).length
|
|
826
|
+
? `all updated:\n${printUpdated()}`
|
|
827
|
+
: updatedFiles.length > 0
|
|
828
|
+
? `${updatedFiles.length} package.json ${
|
|
829
|
+
updatedFiles.length === 1 ? "file" : "files"
|
|
830
|
+
} updated (metadata cleanup only)`
|
|
473
831
|
: "everything was already up-to-date"
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
832
|
+
}`,
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
diff.end();
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
if (processingFailures.length > 0) {
|
|
839
|
+
throw new UpdateVersionsError(processingFailures, {
|
|
840
|
+
unchangedFiles,
|
|
841
|
+
updatedFiles,
|
|
842
|
+
updatedPackages,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
return updatedPackages;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
async function runCli() {
|
|
850
|
+
const cli = parseCli();
|
|
851
|
+
|
|
852
|
+
// Honour help/version even when another argument is also present. codsenCLI
|
|
853
|
+
// handles either flag automatically when it is the sole argument.
|
|
854
|
+
if (cli.flags.version) {
|
|
855
|
+
log(pkg.version);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (cli.flags.help) {
|
|
859
|
+
log(cli.help);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
483
862
|
|
|
484
|
-
await
|
|
485
|
-
|
|
863
|
+
await updateVersions({
|
|
864
|
+
moduleMode: Boolean(cli.flags.module),
|
|
865
|
+
reportProgress: true,
|
|
866
|
+
});
|
|
867
|
+
updateNotifier({ pkg }).notify();
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
function isDirectExecution() {
|
|
871
|
+
if (!process.argv[1]) {
|
|
872
|
+
return false;
|
|
873
|
+
}
|
|
874
|
+
try {
|
|
875
|
+
return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
876
|
+
} catch (_e) {
|
|
877
|
+
return false;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (isDirectExecution()) {
|
|
882
|
+
runCli().catch((error) => {
|
|
883
|
+
let details =
|
|
884
|
+
error instanceof AggregateError
|
|
885
|
+
? error.errors
|
|
886
|
+
.map(
|
|
887
|
+
(failure) =>
|
|
888
|
+
`\n- [${failure.phase ?? "unknown"}] ${failure.path ?? "unknown"}: ${failure.cause?.message ?? failure.message}`,
|
|
889
|
+
)
|
|
890
|
+
.join("")
|
|
891
|
+
: "";
|
|
892
|
+
console.error(
|
|
893
|
+
`\n${messagePrefix}${`\u001b[${31}m${error.message}${details}\u001b[${39}m`}\n`,
|
|
894
|
+
);
|
|
895
|
+
process.exitCode = 1;
|
|
896
|
+
});
|
|
897
|
+
}
|