@yarnpkg/plugin-essentials 4.0.0-rc.5 → 4.0.0-rc.50
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/lib/commands/add.d.ts +1 -1
- package/lib/commands/add.js +34 -25
- package/lib/commands/bin.d.ts +1 -1
- package/lib/commands/bin.js +1 -1
- package/lib/commands/cache/clean.d.ts +1 -1
- package/lib/commands/cache/clean.js +1 -1
- package/lib/commands/config/get.d.ts +1 -1
- package/lib/commands/config/get.js +1 -1
- package/lib/commands/config/set.d.ts +1 -1
- package/lib/commands/config/set.js +1 -1
- package/lib/commands/config/unset.d.ts +1 -1
- package/lib/commands/config/unset.js +1 -1
- package/lib/commands/config.d.ts +1 -1
- package/lib/commands/config.js +1 -1
- package/lib/commands/dedupe.d.ts +1 -1
- package/lib/commands/dedupe.js +7 -8
- package/lib/commands/entries/clipanion.js +1 -1
- package/lib/commands/entries/help.js +1 -1
- package/lib/commands/entries/version.js +1 -1
- package/lib/commands/exec.js +1 -1
- package/lib/commands/explain/peerRequirements.d.ts +2 -2
- package/lib/commands/explain/peerRequirements.js +4 -6
- package/lib/commands/explain.js +1 -1
- package/lib/commands/info.js +8 -12
- package/lib/commands/install.d.ts +1 -1
- package/lib/commands/install.js +188 -107
- package/lib/commands/link.d.ts +2 -2
- package/lib/commands/link.js +36 -32
- package/lib/commands/node.js +1 -1
- package/lib/commands/plugin/check.d.ts +8 -0
- package/lib/commands/plugin/check.js +61 -0
- package/lib/commands/plugin/import/sources.d.ts +3 -3
- package/lib/commands/plugin/import/sources.js +5 -5
- package/lib/commands/plugin/import.d.ts +5 -4
- package/lib/commands/plugin/import.js +15 -28
- package/lib/commands/plugin/list.d.ts +2 -2
- package/lib/commands/plugin/list.js +5 -6
- package/lib/commands/plugin/remove.d.ts +1 -1
- package/lib/commands/plugin/remove.js +14 -13
- package/lib/commands/plugin/runtime.d.ts +2 -2
- package/lib/commands/plugin/runtime.js +4 -4
- package/lib/commands/rebuild.d.ts +2 -2
- package/lib/commands/rebuild.js +10 -10
- package/lib/commands/remove.d.ts +1 -1
- package/lib/commands/remove.js +7 -8
- package/lib/commands/run.js +1 -1
- package/lib/commands/runIndex.d.ts +2 -2
- package/lib/commands/runIndex.js +3 -3
- package/lib/commands/set/resolution.d.ts +1 -1
- package/lib/commands/set/resolution.js +4 -6
- package/lib/commands/set/version/sources.d.ts +3 -2
- package/lib/commands/set/version/sources.js +21 -12
- package/lib/commands/set/version.d.ts +2 -3
- package/lib/commands/set/version.js +20 -16
- package/lib/commands/unlink.d.ts +1 -1
- package/lib/commands/unlink.js +7 -8
- package/lib/commands/up.d.ts +3 -3
- package/lib/commands/up.js +19 -17
- package/lib/commands/why.js +5 -13
- package/lib/commands/workspace.js +2 -5
- package/lib/commands/workspaces/list.d.ts +2 -1
- package/lib/commands/workspaces/list.js +8 -1
- package/lib/dedupeUtils.d.ts +3 -3
- package/lib/dedupeUtils.js +3 -5
- package/lib/index.d.ts +76 -1
- package/lib/index.js +40 -1
- package/lib/suggestUtils.d.ts +4 -4
- package/lib/suggestUtils.js +10 -10
- package/package.json +23 -17
package/lib/commands/install.js
CHANGED
|
@@ -7,7 +7,21 @@ const fslib_1 = require("@yarnpkg/fslib");
|
|
|
7
7
|
const parsers_1 = require("@yarnpkg/parsers");
|
|
8
8
|
const ci_info_1 = tslib_1.__importDefault(require("ci-info"));
|
|
9
9
|
const clipanion_1 = require("clipanion");
|
|
10
|
+
const semver_1 = tslib_1.__importDefault(require("semver"));
|
|
10
11
|
const t = tslib_1.__importStar(require("typanion"));
|
|
12
|
+
const LOCKFILE_MIGRATION_RULES = [{
|
|
13
|
+
selector: v => v === -1,
|
|
14
|
+
name: `nodeLinker`,
|
|
15
|
+
value: `node-modules`,
|
|
16
|
+
}, {
|
|
17
|
+
selector: v => v !== -1 && v < 8,
|
|
18
|
+
name: `enableGlobalCache`,
|
|
19
|
+
value: false,
|
|
20
|
+
}, {
|
|
21
|
+
selector: v => v !== -1 && v < 8,
|
|
22
|
+
name: `compressionLevel`,
|
|
23
|
+
value: `mixed`,
|
|
24
|
+
}];
|
|
11
25
|
// eslint-disable-next-line arca/no-default-export
|
|
12
26
|
class YarnCommand extends cli_1.BaseCommand {
|
|
13
27
|
constructor() {
|
|
@@ -49,7 +63,6 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
49
63
|
this.networkTimeout = clipanion_1.Option.String(`--network-timeout`, { hidden: true });
|
|
50
64
|
}
|
|
51
65
|
async execute() {
|
|
52
|
-
var _a, _b, _c;
|
|
53
66
|
const configuration = await core_1.Configuration.find(this.context.cwd, this.context.plugins);
|
|
54
67
|
if (typeof this.inlineBuilds !== `undefined`)
|
|
55
68
|
configuration.useWithSource(`<cli>`, { enableInlineBuilds: this.inlineBuilds }, configuration.startingCwd, { overwrite: true });
|
|
@@ -163,7 +176,7 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
163
176
|
const updateMode = this.mode === core_1.InstallMode.UpdateLockfile;
|
|
164
177
|
if (updateMode && (this.immutable || this.immutableCache))
|
|
165
178
|
throw new clipanion_1.UsageError(`${core_1.formatUtils.pretty(configuration, `--immutable`, core_1.formatUtils.Type.CODE)} and ${core_1.formatUtils.pretty(configuration, `--immutable-cache`, core_1.formatUtils.Type.CODE)} cannot be used with ${core_1.formatUtils.pretty(configuration, `--mode=update-lockfile`, core_1.formatUtils.Type.CODE)}`);
|
|
166
|
-
const immutable = (
|
|
179
|
+
const immutable = (this.immutable ?? configuration.get(`enableImmutableInstalls`)) && !updateMode;
|
|
167
180
|
const immutableCache = this.immutableCache && !updateMode;
|
|
168
181
|
if (configuration.projectCwd !== null) {
|
|
169
182
|
const fixReport = await core_1.StreamReport.start({
|
|
@@ -172,8 +185,16 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
172
185
|
stdout: this.context.stdout,
|
|
173
186
|
includeFooter: false,
|
|
174
187
|
}, async (report) => {
|
|
188
|
+
let changed = false;
|
|
189
|
+
if (await autofixLegacyPlugins(configuration, immutable)) {
|
|
190
|
+
report.reportInfo(core_1.MessageName.AUTOMERGE_SUCCESS, `Automatically removed core plugins that are now builtins 👍`);
|
|
191
|
+
changed = true;
|
|
192
|
+
}
|
|
175
193
|
if (await autofixMergeConflicts(configuration, immutable)) {
|
|
176
194
|
report.reportInfo(core_1.MessageName.AUTOMERGE_SUCCESS, `Automatically fixed merge conflicts 👍`);
|
|
195
|
+
changed = true;
|
|
196
|
+
}
|
|
197
|
+
if (changed) {
|
|
177
198
|
report.reportSeparator();
|
|
178
199
|
}
|
|
179
200
|
});
|
|
@@ -181,34 +202,6 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
181
202
|
return fixReport.exitCode();
|
|
182
203
|
}
|
|
183
204
|
}
|
|
184
|
-
if (configuration.projectCwd !== null && typeof configuration.sources.get(`nodeLinker`) === `undefined`) {
|
|
185
|
-
const projectCwd = configuration.projectCwd;
|
|
186
|
-
let content;
|
|
187
|
-
try {
|
|
188
|
-
content = await fslib_1.xfs.readFilePromise(fslib_1.ppath.join(projectCwd, fslib_1.Filename.lockfile), `utf8`);
|
|
189
|
-
}
|
|
190
|
-
catch { }
|
|
191
|
-
// If migrating from a v1 install, we automatically enable the node-modules linker,
|
|
192
|
-
// since that's likely what the author intended to do.
|
|
193
|
-
if (content === null || content === void 0 ? void 0 : content.includes(`yarn lockfile v1`)) {
|
|
194
|
-
const nmReport = await core_1.StreamReport.start({
|
|
195
|
-
configuration,
|
|
196
|
-
json: this.json,
|
|
197
|
-
stdout: this.context.stdout,
|
|
198
|
-
includeFooter: false,
|
|
199
|
-
}, async (report) => {
|
|
200
|
-
report.reportInfo(core_1.MessageName.AUTO_NM_SUCCESS, `Migrating from Yarn 1; automatically enabling the compatibility node-modules linker 👍`);
|
|
201
|
-
report.reportSeparator();
|
|
202
|
-
configuration.use(`<compat>`, { nodeLinker: `node-modules` }, projectCwd, { overwrite: true });
|
|
203
|
-
await core_1.Configuration.updateConfiguration(projectCwd, {
|
|
204
|
-
nodeLinker: `node-modules`,
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
if (nmReport.hasErrors()) {
|
|
208
|
-
return nmReport.exitCode();
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
205
|
if (configuration.projectCwd !== null) {
|
|
213
206
|
const telemetryReport = await core_1.StreamReport.start({
|
|
214
207
|
configuration,
|
|
@@ -216,18 +209,72 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
216
209
|
stdout: this.context.stdout,
|
|
217
210
|
includeFooter: false,
|
|
218
211
|
}, async (report) => {
|
|
219
|
-
|
|
220
|
-
|
|
212
|
+
if (core_1.Configuration.telemetry?.isNew) {
|
|
213
|
+
core_1.Configuration.telemetry.commitTips();
|
|
221
214
|
report.reportInfo(core_1.MessageName.TELEMETRY_NOTICE, `Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry`);
|
|
222
215
|
report.reportInfo(core_1.MessageName.TELEMETRY_NOTICE, `Run ${core_1.formatUtils.pretty(configuration, `yarn config set --home enableTelemetry 0`, core_1.formatUtils.Type.CODE)} to disable`);
|
|
223
216
|
report.reportSeparator();
|
|
224
217
|
}
|
|
218
|
+
else if (core_1.Configuration.telemetry?.shouldShowTips) {
|
|
219
|
+
const data = await core_1.httpUtils.get(`https://repo.yarnpkg.com/tags`, { configuration, jsonResponse: true }).catch(() => null);
|
|
220
|
+
if (data !== null) {
|
|
221
|
+
let newVersion = null;
|
|
222
|
+
if (core_1.YarnVersion !== null) {
|
|
223
|
+
const isRcBinary = semver_1.default.prerelease(core_1.YarnVersion);
|
|
224
|
+
const releaseType = isRcBinary ? `canary` : `stable`;
|
|
225
|
+
const candidate = data.latest[releaseType];
|
|
226
|
+
if (semver_1.default.gt(candidate, core_1.YarnVersion)) {
|
|
227
|
+
newVersion = [releaseType, candidate];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (newVersion) {
|
|
231
|
+
core_1.Configuration.telemetry.commitTips();
|
|
232
|
+
report.reportInfo(core_1.MessageName.VERSION_NOTICE, `${core_1.formatUtils.applyStyle(configuration, `A new ${newVersion[0]} version of Yarn is available:`, core_1.formatUtils.Style.BOLD)} ${core_1.structUtils.prettyReference(configuration, newVersion[1])}!`);
|
|
233
|
+
report.reportInfo(core_1.MessageName.VERSION_NOTICE, `Upgrade now by running ${core_1.formatUtils.pretty(configuration, `yarn set version ${newVersion[1]}`, core_1.formatUtils.Type.CODE)}`);
|
|
234
|
+
report.reportSeparator();
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
const tip = core_1.Configuration.telemetry.selectTip(data.tips);
|
|
238
|
+
if (tip) {
|
|
239
|
+
report.reportInfo(core_1.MessageName.TIPS_NOTICE, core_1.formatUtils.pretty(configuration, tip.message, core_1.formatUtils.Type.MARKDOWN_INLINE));
|
|
240
|
+
if (tip.url)
|
|
241
|
+
report.reportInfo(core_1.MessageName.TIPS_NOTICE, `Learn more at ${tip.url}`);
|
|
242
|
+
report.reportSeparator();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
225
247
|
});
|
|
226
248
|
if (telemetryReport.hasErrors()) {
|
|
227
249
|
return telemetryReport.exitCode();
|
|
228
250
|
}
|
|
229
251
|
}
|
|
230
252
|
const { project, workspace } = await core_1.Project.find(configuration, this.context.cwd);
|
|
253
|
+
const lockfileLastVersion = project.lockfileLastVersion;
|
|
254
|
+
if (lockfileLastVersion !== null) {
|
|
255
|
+
const compatReport = await core_1.StreamReport.start({
|
|
256
|
+
configuration,
|
|
257
|
+
json: this.json,
|
|
258
|
+
stdout: this.context.stdout,
|
|
259
|
+
includeFooter: false,
|
|
260
|
+
}, async (report) => {
|
|
261
|
+
const newSettings = {};
|
|
262
|
+
for (const rule of LOCKFILE_MIGRATION_RULES) {
|
|
263
|
+
if (rule.selector(lockfileLastVersion) && typeof configuration.sources.get(rule.name) === `undefined`) {
|
|
264
|
+
configuration.use(`<compat>`, { [rule.name]: rule.value }, project.cwd, { overwrite: true });
|
|
265
|
+
newSettings[rule.name] = rule.value;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (Object.keys(newSettings).length > 0) {
|
|
269
|
+
await core_1.Configuration.updateConfiguration(project.cwd, newSettings);
|
|
270
|
+
report.reportInfo(core_1.MessageName.MIGRATION_SUCCESS, `Migrated your project to the latest Yarn version 🚀`);
|
|
271
|
+
report.reportSeparator();
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
if (compatReport.hasErrors()) {
|
|
275
|
+
return compatReport.exitCode();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
231
278
|
const cache = await core_1.Cache.find(configuration, { immutable: immutableCache, check: this.checkCache });
|
|
232
279
|
if (!workspace)
|
|
233
280
|
throw new cli_1.WorkspaceRequiredError(project.cwd, this.context.cwd);
|
|
@@ -235,9 +282,9 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
235
282
|
restoreResolutions: false,
|
|
236
283
|
});
|
|
237
284
|
const enableHardenedMode = configuration.get(`enableHardenedMode`);
|
|
238
|
-
if (
|
|
285
|
+
if (this.refreshLockfile ?? enableHardenedMode)
|
|
239
286
|
project.lockfileNeedsRefresh = true;
|
|
240
|
-
const checkResolutions =
|
|
287
|
+
const checkResolutions = this.checkResolutions ?? enableHardenedMode;
|
|
241
288
|
// Important: Because other commands also need to run installs, if you
|
|
242
289
|
// get in a situation where you need to change this file in order to
|
|
243
290
|
// customize the install it's very likely you're doing something wrong.
|
|
@@ -245,18 +292,17 @@ class YarnCommand extends cli_1.BaseCommand {
|
|
|
245
292
|
// install logic should be implemented elsewhere (probably in either of
|
|
246
293
|
// the Configuration and Install classes). Feel free to open an issue
|
|
247
294
|
// in order to ask for design feedback before writing features.
|
|
248
|
-
|
|
249
|
-
configuration,
|
|
295
|
+
return await project.installWithNewReport({
|
|
250
296
|
json: this.json,
|
|
251
297
|
stdout: this.context.stdout,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
298
|
+
}, {
|
|
299
|
+
cache,
|
|
300
|
+
immutable,
|
|
301
|
+
checkResolutions,
|
|
302
|
+
mode: this.mode,
|
|
255
303
|
});
|
|
256
|
-
return report.exitCode();
|
|
257
304
|
}
|
|
258
305
|
}
|
|
259
|
-
exports.default = YarnCommand;
|
|
260
306
|
YarnCommand.paths = [
|
|
261
307
|
[`install`],
|
|
262
308
|
clipanion_1.Command.Default,
|
|
@@ -288,7 +334,7 @@ YarnCommand.usage = clipanion_1.Command.Usage({
|
|
|
288
334
|
|
|
289
335
|
If the \`--mode=<mode>\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:
|
|
290
336
|
|
|
291
|
-
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the
|
|
337
|
+
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.
|
|
292
338
|
|
|
293
339
|
- \`update-lockfile\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.
|
|
294
340
|
`,
|
|
@@ -303,14 +349,12 @@ YarnCommand.usage = clipanion_1.Command.Usage({
|
|
|
303
349
|
`$0 install --immutable --immutable-cache --check-cache`,
|
|
304
350
|
]],
|
|
305
351
|
});
|
|
306
|
-
|
|
307
|
-
const MERGE_CONFLICT_END = `>>>>>>>`;
|
|
308
|
-
const MERGE_CONFLICT_SEP = `=======`;
|
|
352
|
+
exports.default = YarnCommand;
|
|
309
353
|
const MERGE_CONFLICT_START = `<<<<<<<`;
|
|
310
354
|
async function autofixMergeConflicts(configuration, immutable) {
|
|
311
355
|
if (!configuration.projectCwd)
|
|
312
356
|
return false;
|
|
313
|
-
const lockfilePath = fslib_1.ppath.join(configuration.projectCwd,
|
|
357
|
+
const lockfilePath = fslib_1.ppath.join(configuration.projectCwd, fslib_1.Filename.lockfile);
|
|
314
358
|
if (!await fslib_1.xfs.existsPromise(lockfilePath))
|
|
315
359
|
return false;
|
|
316
360
|
const file = await fslib_1.xfs.readFilePromise(lockfilePath, `utf8`);
|
|
@@ -318,22 +362,74 @@ async function autofixMergeConflicts(configuration, immutable) {
|
|
|
318
362
|
return false;
|
|
319
363
|
if (immutable)
|
|
320
364
|
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_IMMUTABLE, `Cannot autofix a lockfile when running an immutable install`);
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
365
|
+
let commits = await core_1.execUtils.execvp(`git`, [`rev-parse`, `MERGE_HEAD`, `HEAD`], {
|
|
366
|
+
cwd: configuration.projectCwd,
|
|
367
|
+
});
|
|
368
|
+
if (commits.code !== 0) {
|
|
369
|
+
commits = await core_1.execUtils.execvp(`git`, [`rev-parse`, `REBASE_HEAD`, `HEAD`], {
|
|
370
|
+
cwd: configuration.projectCwd,
|
|
371
|
+
});
|
|
327
372
|
}
|
|
328
|
-
|
|
329
|
-
|
|
373
|
+
if (commits.code !== 0) {
|
|
374
|
+
commits = await core_1.execUtils.execvp(`git`, [`rev-parse`, `CHERRY_PICK_HEAD`, `HEAD`], {
|
|
375
|
+
cwd: configuration.projectCwd,
|
|
376
|
+
});
|
|
330
377
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
378
|
+
if (commits.code !== 0)
|
|
379
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_GIT_ERROR, `Git returned an error when trying to find the commits pertaining to the conflict`);
|
|
380
|
+
let variants = await Promise.all(commits.stdout.trim().split(/\n/).map(async (hash) => {
|
|
381
|
+
const content = await core_1.execUtils.execvp(`git`, [`show`, `${hash}:./${fslib_1.Filename.lockfile}`], {
|
|
382
|
+
cwd: configuration.projectCwd,
|
|
383
|
+
});
|
|
384
|
+
if (content.code !== 0)
|
|
385
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_GIT_ERROR, `Git returned an error when trying to access the lockfile content in ${hash}`);
|
|
386
|
+
try {
|
|
387
|
+
return (0, parsers_1.parseSyml)(content.stdout);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_FAILED_TO_PARSE, `A variant of the conflicting lockfile failed to parse`);
|
|
391
|
+
}
|
|
392
|
+
}));
|
|
335
393
|
// Old-style lockfiles should be filtered out (for example when switching
|
|
336
|
-
// from a Yarn 2 branch to a Yarn 1 branch).
|
|
394
|
+
// from a Yarn 2 branch to a Yarn 1 branch).
|
|
395
|
+
variants = variants.filter(variant => {
|
|
396
|
+
return !!variant.__metadata;
|
|
397
|
+
});
|
|
398
|
+
for (const variant of variants) {
|
|
399
|
+
// Pre-lockfile v7, the entries weren't normalized (ie we had "foo@x.y.z"
|
|
400
|
+
// in the lockfile rather than "foo@npm:x.y.z")
|
|
401
|
+
if (variant.__metadata.version < 7) {
|
|
402
|
+
for (const key of Object.keys(variant)) {
|
|
403
|
+
if (key === `__metadata`)
|
|
404
|
+
continue;
|
|
405
|
+
const descriptor = core_1.structUtils.parseDescriptor(key, true);
|
|
406
|
+
const normalizedDescriptor = configuration.normalizeDependency(descriptor);
|
|
407
|
+
const newKey = core_1.structUtils.stringifyDescriptor(normalizedDescriptor);
|
|
408
|
+
if (newKey !== key) {
|
|
409
|
+
variant[newKey] = variant[key];
|
|
410
|
+
delete variant[key];
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
// We encode the cacheKeys inside the checksums so that the reconciliation
|
|
415
|
+
// can merge the data together
|
|
416
|
+
for (const key of Object.keys(variant)) {
|
|
417
|
+
if (key === `__metadata`)
|
|
418
|
+
continue;
|
|
419
|
+
const checksum = variant[key].checksum;
|
|
420
|
+
if (typeof checksum === `string` && checksum.includes(`/`))
|
|
421
|
+
continue;
|
|
422
|
+
variant[key].checksum = `${variant.__metadata.cacheKey}/${checksum}`;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const merged = Object.assign({}, ...variants);
|
|
426
|
+
// We must keep the lockfile version as small as necessary to force Yarn to
|
|
427
|
+
// refresh the merged-in lockfile metadata that may be missing.
|
|
428
|
+
merged.__metadata.version = `${Math.min(...variants.map(variant => {
|
|
429
|
+
return parseInt(variant.__metadata.version ?? 0);
|
|
430
|
+
}))}`;
|
|
431
|
+
// It shouldn't matter, since the cacheKey have been embed within the checksums
|
|
432
|
+
merged.__metadata.cacheKey = `merged`;
|
|
337
433
|
// parse as valid YAML except that the objects become strings. We can use
|
|
338
434
|
// that to detect them. Damn, it's really ugly though.
|
|
339
435
|
for (const [key, value] of Object.entries(merged))
|
|
@@ -344,52 +440,37 @@ async function autofixMergeConflicts(configuration, immutable) {
|
|
|
344
440
|
});
|
|
345
441
|
return true;
|
|
346
442
|
}
|
|
347
|
-
function
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
variants[1].push(conflictLine);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
variants[0].push(line);
|
|
388
|
-
variants[1].push(line);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return [
|
|
392
|
-
variants[0].join(`\n`),
|
|
393
|
-
variants[1].join(`\n`),
|
|
394
|
-
];
|
|
443
|
+
async function autofixLegacyPlugins(configuration, immutable) {
|
|
444
|
+
if (!configuration.projectCwd)
|
|
445
|
+
return false;
|
|
446
|
+
const legacyPlugins = [];
|
|
447
|
+
const yarnPluginDir = fslib_1.ppath.join(configuration.projectCwd, `.yarn/plugins/@yarnpkg`);
|
|
448
|
+
const changed = await core_1.Configuration.updateConfiguration(configuration.projectCwd, {
|
|
449
|
+
plugins: plugins => {
|
|
450
|
+
if (!Array.isArray(plugins))
|
|
451
|
+
return plugins;
|
|
452
|
+
const filteredPlugins = plugins.filter((plugin) => {
|
|
453
|
+
if (!plugin.path)
|
|
454
|
+
return true;
|
|
455
|
+
const resolvedPath = fslib_1.ppath.resolve(configuration.projectCwd, plugin.path);
|
|
456
|
+
const isLegacy = core_1.LEGACY_PLUGINS.has(plugin.spec) && fslib_1.ppath.contains(yarnPluginDir, resolvedPath);
|
|
457
|
+
if (isLegacy)
|
|
458
|
+
legacyPlugins.push(resolvedPath);
|
|
459
|
+
return !isLegacy;
|
|
460
|
+
});
|
|
461
|
+
if (filteredPlugins.length === 0)
|
|
462
|
+
return core_1.Configuration.deleteProperty;
|
|
463
|
+
if (filteredPlugins.length === plugins.length)
|
|
464
|
+
return plugins;
|
|
465
|
+
return filteredPlugins;
|
|
466
|
+
},
|
|
467
|
+
}, {
|
|
468
|
+
immutable,
|
|
469
|
+
});
|
|
470
|
+
if (!changed)
|
|
471
|
+
return false;
|
|
472
|
+
await Promise.all(legacyPlugins.map(async (pluginPath) => {
|
|
473
|
+
await fslib_1.xfs.removePromise(pluginPath);
|
|
474
|
+
}));
|
|
475
|
+
return true;
|
|
395
476
|
}
|
package/lib/commands/link.d.ts
CHANGED
package/lib/commands/link.js
CHANGED
|
@@ -9,15 +9,15 @@ class LinkCommand extends cli_1.BaseCommand {
|
|
|
9
9
|
constructor() {
|
|
10
10
|
super(...arguments);
|
|
11
11
|
this.all = clipanion_1.Option.Boolean(`-A,--all`, false, {
|
|
12
|
-
description: `Link all workspaces belonging to the target
|
|
12
|
+
description: `Link all workspaces belonging to the target projects to the current one`,
|
|
13
13
|
});
|
|
14
14
|
this.private = clipanion_1.Option.Boolean(`-p,--private`, false, {
|
|
15
|
-
description: `Also link private workspaces belonging to the target
|
|
15
|
+
description: `Also link private workspaces belonging to the target projects to the current one`,
|
|
16
16
|
});
|
|
17
17
|
this.relative = clipanion_1.Option.Boolean(`-r,--relative`, false, {
|
|
18
18
|
description: `Link workspaces using relative paths instead of absolute paths`,
|
|
19
19
|
});
|
|
20
|
-
this.
|
|
20
|
+
this.destinations = clipanion_1.Option.Rest();
|
|
21
21
|
}
|
|
22
22
|
async execute() {
|
|
23
23
|
const configuration = await core_1.Configuration.find(this.context.cwd, this.context.plugins);
|
|
@@ -28,32 +28,38 @@ class LinkCommand extends cli_1.BaseCommand {
|
|
|
28
28
|
await project.restoreInstallState({
|
|
29
29
|
restoreResolutions: false,
|
|
30
30
|
});
|
|
31
|
-
const absoluteDestination = fslib_1.ppath.resolve(this.context.cwd, fslib_1.npath.toPortablePath(this.destination));
|
|
32
|
-
const configuration2 = await core_1.Configuration.find(absoluteDestination, this.context.plugins, { useRc: false, strict: false });
|
|
33
|
-
const { project: project2, workspace: workspace2 } = await core_1.Project.find(configuration2, absoluteDestination);
|
|
34
|
-
if (project.cwd === project2.cwd)
|
|
35
|
-
throw new clipanion_1.UsageError(`Invalid destination; Can't link the project to itself`);
|
|
36
|
-
if (!workspace2)
|
|
37
|
-
throw new cli_1.WorkspaceRequiredError(project2.cwd, absoluteDestination);
|
|
38
31
|
const topLevelWorkspace = project.topLevelWorkspace;
|
|
39
32
|
const linkedWorkspaces = [];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
throw new clipanion_1.UsageError(`
|
|
33
|
+
for (const destination of this.destinations) {
|
|
34
|
+
const absoluteDestination = fslib_1.ppath.resolve(this.context.cwd, fslib_1.npath.toPortablePath(destination));
|
|
35
|
+
const configuration2 = await core_1.Configuration.find(absoluteDestination, this.context.plugins, { useRc: false, strict: false });
|
|
36
|
+
const { project: project2, workspace: workspace2 } = await core_1.Project.find(configuration2, absoluteDestination);
|
|
37
|
+
if (project.cwd === project2.cwd)
|
|
38
|
+
throw new clipanion_1.UsageError(`Invalid destination '${destination}'; Can't link the project to itself`);
|
|
39
|
+
if (!workspace2)
|
|
40
|
+
throw new cli_1.WorkspaceRequiredError(project2.cwd, absoluteDestination);
|
|
41
|
+
if (this.all) {
|
|
42
|
+
let found = false;
|
|
43
|
+
for (const workspace of project2.workspaces) {
|
|
44
|
+
if (workspace.manifest.name && (!workspace.manifest.private || this.private)) {
|
|
45
|
+
linkedWorkspaces.push(workspace);
|
|
46
|
+
found = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (!found) {
|
|
50
|
+
throw new clipanion_1.UsageError(`No workspace found to be linked in the target project: ${destination}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
if (!workspace2.manifest.name)
|
|
55
|
+
throw new clipanion_1.UsageError(`The target workspace at '${destination}' doesn't have a name and thus cannot be linked`);
|
|
56
|
+
if (workspace2.manifest.private && !this.private)
|
|
57
|
+
throw new clipanion_1.UsageError(`The target workspace at '${destination}' is marked private - use the --private flag to link it anyway`);
|
|
58
|
+
linkedWorkspaces.push(workspace2);
|
|
46
59
|
}
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
if (!workspace2.manifest.name)
|
|
50
|
-
throw new clipanion_1.UsageError(`The target workspace doesn't have a name and thus cannot be linked`);
|
|
51
|
-
if (workspace2.manifest.private && !this.private)
|
|
52
|
-
throw new clipanion_1.UsageError(`The target workspace is marked private - use the --private flag to link it anyway`);
|
|
53
|
-
linkedWorkspaces.push(workspace2);
|
|
54
60
|
}
|
|
55
61
|
for (const workspace of linkedWorkspaces) {
|
|
56
|
-
const fullName = core_1.structUtils.stringifyIdent(workspace.
|
|
62
|
+
const fullName = core_1.structUtils.stringifyIdent(workspace.anchoredLocator);
|
|
57
63
|
const target = this.relative
|
|
58
64
|
? fslib_1.ppath.relative(project.cwd, workspace.cwd)
|
|
59
65
|
: workspace.cwd;
|
|
@@ -62,16 +68,13 @@ class LinkCommand extends cli_1.BaseCommand {
|
|
|
62
68
|
reference: `portal:${target}`,
|
|
63
69
|
});
|
|
64
70
|
}
|
|
65
|
-
|
|
66
|
-
configuration,
|
|
71
|
+
return await project.installWithNewReport({
|
|
67
72
|
stdout: this.context.stdout,
|
|
68
|
-
},
|
|
69
|
-
|
|
73
|
+
}, {
|
|
74
|
+
cache,
|
|
70
75
|
});
|
|
71
|
-
return report.exitCode();
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
|
-
exports.default = LinkCommand;
|
|
75
78
|
LinkCommand.paths = [
|
|
76
79
|
[`link`],
|
|
77
80
|
];
|
|
@@ -81,10 +84,11 @@ LinkCommand.usage = clipanion_1.Command.Usage({
|
|
|
81
84
|
This command will set a new \`resolutions\` field in the project-level manifest and point it to the workspace at the specified location (even if part of another project).
|
|
82
85
|
`,
|
|
83
86
|
examples: [[
|
|
84
|
-
`Register
|
|
85
|
-
`$0 link ~/ts-loader`,
|
|
87
|
+
`Register one or more remote workspaces for use in the current project`,
|
|
88
|
+
`$0 link ~/ts-loader ~/jest`,
|
|
86
89
|
], [
|
|
87
90
|
`Register all workspaces from a remote project for use in the current project`,
|
|
88
91
|
`$0 link ~/jest --all`,
|
|
89
92
|
]],
|
|
90
93
|
});
|
|
94
|
+
exports.default = LinkCommand;
|
package/lib/commands/node.js
CHANGED
|
@@ -12,7 +12,6 @@ class NodeCommand extends cli_1.BaseCommand {
|
|
|
12
12
|
return this.cli.run([`exec`, `node`, ...this.args]);
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
exports.default = NodeCommand;
|
|
16
15
|
NodeCommand.paths = [
|
|
17
16
|
[`node`],
|
|
18
17
|
];
|
|
@@ -28,3 +27,4 @@ NodeCommand.usage = clipanion_1.Command.Usage({
|
|
|
28
27
|
`$0 node ./my-script.js`,
|
|
29
28
|
]],
|
|
30
29
|
});
|
|
30
|
+
exports.default = NodeCommand;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const cli_1 = require("@yarnpkg/cli");
|
|
4
|
+
const core_1 = require("@yarnpkg/core");
|
|
5
|
+
const clipanion_1 = require("clipanion");
|
|
6
|
+
// eslint-disable-next-line arca/no-default-export
|
|
7
|
+
class PluginCheckCommand extends cli_1.BaseCommand {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.json = clipanion_1.Option.Boolean(`--json`, false, {
|
|
11
|
+
description: `Format the output as an NDJSON stream`,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async execute() {
|
|
15
|
+
const configuration = await core_1.Configuration.find(this.context.cwd, this.context.plugins);
|
|
16
|
+
const rcFiles = await core_1.Configuration.findRcFiles(this.context.cwd);
|
|
17
|
+
const report = await core_1.StreamReport.start({
|
|
18
|
+
configuration,
|
|
19
|
+
json: this.json,
|
|
20
|
+
stdout: this.context.stdout,
|
|
21
|
+
}, async (report) => {
|
|
22
|
+
for (const rcFile of rcFiles) {
|
|
23
|
+
if (!rcFile.data?.plugins)
|
|
24
|
+
continue;
|
|
25
|
+
for (const plugin of rcFile.data.plugins) {
|
|
26
|
+
if (!plugin.checksum)
|
|
27
|
+
continue;
|
|
28
|
+
if (!plugin.spec.match(/^https?:/))
|
|
29
|
+
continue;
|
|
30
|
+
const newBuffer = await core_1.httpUtils.get(plugin.spec, { configuration });
|
|
31
|
+
const newChecksum = core_1.hashUtils.makeHash(newBuffer);
|
|
32
|
+
if (plugin.checksum === newChecksum)
|
|
33
|
+
continue;
|
|
34
|
+
const prettyPath = core_1.formatUtils.pretty(configuration, plugin.path, core_1.formatUtils.Type.PATH);
|
|
35
|
+
const prettySpec = core_1.formatUtils.pretty(configuration, plugin.spec, core_1.formatUtils.Type.URL);
|
|
36
|
+
const prettyMessage = `${prettyPath} is different from the file provided by ${prettySpec}`;
|
|
37
|
+
report.reportJson({ ...plugin, newChecksum });
|
|
38
|
+
report.reportError(core_1.MessageName.UNNAMED, prettyMessage);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return report.exitCode();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
PluginCheckCommand.paths = [
|
|
46
|
+
[`plugin`, `check`],
|
|
47
|
+
];
|
|
48
|
+
PluginCheckCommand.usage = clipanion_1.Command.Usage({
|
|
49
|
+
category: `Plugin-related commands`,
|
|
50
|
+
description: `find all third-party plugins that differ from their own spec`,
|
|
51
|
+
details: `
|
|
52
|
+
Check only the plugins from https.
|
|
53
|
+
|
|
54
|
+
If this command detects any plugin differences in the CI environment, it will throw an error.
|
|
55
|
+
`,
|
|
56
|
+
examples: [[
|
|
57
|
+
`find all third-party plugins that differ from their own spec`,
|
|
58
|
+
`$0 plugin check`,
|
|
59
|
+
]],
|
|
60
|
+
});
|
|
61
|
+
exports.default = PluginCheckCommand;
|
|
@@ -3,7 +3,7 @@ import { Report, CommandContext } from '@yarnpkg/core';
|
|
|
3
3
|
import { Project } from '@yarnpkg/core';
|
|
4
4
|
import { PortablePath } from '@yarnpkg/fslib';
|
|
5
5
|
import { Usage } from 'clipanion';
|
|
6
|
-
export default class
|
|
6
|
+
export default class PluginImportSourcesCommand extends BaseCommand {
|
|
7
7
|
static paths: string[][];
|
|
8
8
|
static usage: Usage;
|
|
9
9
|
installPath: string | undefined;
|
|
@@ -12,9 +12,9 @@ export default class PluginDlSourcesCommand extends BaseCommand {
|
|
|
12
12
|
noMinify: boolean;
|
|
13
13
|
force: boolean;
|
|
14
14
|
name: string;
|
|
15
|
-
execute(): Promise<
|
|
15
|
+
execute(): Promise<0 | 1>;
|
|
16
16
|
}
|
|
17
|
-
export
|
|
17
|
+
export type BuildAndSavePluginsSpec = {
|
|
18
18
|
context: CommandContext;
|
|
19
19
|
noMinify: boolean;
|
|
20
20
|
};
|