@yarnpkg/plugin-essentials 4.0.0-rc.3 → 4.0.0-rc.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/add.js +27 -16
- package/lib/commands/dedupe.js +1 -1
- package/lib/commands/info.js +1 -1
- package/lib/commands/install.js +51 -68
- package/lib/commands/link.d.ts +1 -1
- package/lib/commands/link.js +31 -25
- package/lib/commands/plugin/check.d.ts +8 -0
- package/lib/commands/plugin/check.js +62 -0
- package/lib/commands/plugin/import/sources.d.ts +2 -2
- package/lib/commands/plugin/import/sources.js +4 -4
- package/lib/commands/plugin/import.d.ts +4 -3
- package/lib/commands/plugin/import.js +14 -27
- package/lib/commands/plugin/list.d.ts +1 -1
- package/lib/commands/plugin/list.js +4 -4
- package/lib/commands/plugin/runtime.d.ts +1 -1
- package/lib/commands/plugin/runtime.js +4 -4
- package/lib/commands/rebuild.d.ts +1 -1
- package/lib/commands/rebuild.js +4 -4
- package/lib/commands/remove.js +2 -2
- package/lib/commands/runIndex.d.ts +1 -1
- package/lib/commands/runIndex.js +3 -3
- package/lib/commands/set/version/sources.d.ts +1 -1
- package/lib/commands/set/version.d.ts +1 -2
- package/lib/commands/set/version.js +16 -10
- package/lib/commands/up.js +3 -3
- package/lib/commands/why.js +4 -12
- package/lib/commands/workspace.js +1 -4
- package/lib/commands/workspaces/list.d.ts +1 -0
- package/lib/commands/workspaces/list.js +7 -0
- package/lib/dedupeUtils.d.ts +3 -3
- package/lib/dedupeUtils.js +1 -2
- package/lib/index.d.ts +76 -1
- package/lib/index.js +40 -1
- package/lib/suggestUtils.d.ts +4 -4
- package/lib/suggestUtils.js +7 -7
- package/package.json +20 -14
package/lib/commands/add.js
CHANGED
|
@@ -86,24 +86,27 @@ class AddCommand extends cli_1.BaseCommand {
|
|
|
86
86
|
: core_3.structUtils.tryParseDescriptor(pseudoDescriptor);
|
|
87
87
|
const unsupportedPrefix = pseudoDescriptor.match(/^(https?:|git@github)/);
|
|
88
88
|
if (unsupportedPrefix)
|
|
89
|
-
throw new clipanion_1.UsageError(`It seems you are trying to add a package using a ${core_1.formatUtils.pretty(configuration, `${unsupportedPrefix[0]}...`, core_1.
|
|
89
|
+
throw new clipanion_1.UsageError(`It seems you are trying to add a package using a ${core_1.formatUtils.pretty(configuration, `${unsupportedPrefix[0]}...`, core_1.formatUtils.Type.RANGE)} url; we now require package names to be explicitly specified.\nTry running the command again with the package name prefixed: ${core_1.formatUtils.pretty(configuration, `yarn add`, core_1.formatUtils.Type.CODE)} ${core_1.formatUtils.pretty(configuration, core_3.structUtils.makeDescriptor(core_3.structUtils.makeIdent(null, `my-package`), `${unsupportedPrefix[0]}...`), core_1.formatUtils.Type.DESCRIPTOR)}`);
|
|
90
90
|
if (!request)
|
|
91
|
-
throw new clipanion_1.UsageError(`The ${core_1.formatUtils.pretty(configuration, pseudoDescriptor, core_1.
|
|
92
|
-
const
|
|
91
|
+
throw new clipanion_1.UsageError(`The ${core_1.formatUtils.pretty(configuration, pseudoDescriptor, core_1.formatUtils.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);
|
|
92
|
+
const targetList = suggestTargetList(workspace, request, {
|
|
93
93
|
dev: this.dev,
|
|
94
94
|
peer: this.peer,
|
|
95
95
|
preferDev: this.preferDev,
|
|
96
96
|
optional: this.optional,
|
|
97
97
|
});
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
const results = await Promise.all(targetList.map(async (target) => {
|
|
99
|
+
const suggestedDescriptors = await suggestUtils.getSuggestedDescriptors(request, { project, workspace, cache, fixed, target, modifier, strategies, maxResults });
|
|
100
|
+
return { request, suggestedDescriptors, target };
|
|
101
|
+
}));
|
|
102
|
+
return results;
|
|
103
|
+
})).then(results => results.flat());
|
|
101
104
|
const checkReport = await core_1.LightReport.start({
|
|
102
105
|
configuration,
|
|
103
106
|
stdout: this.context.stdout,
|
|
104
107
|
suggestInstall: false,
|
|
105
108
|
}, async (report) => {
|
|
106
|
-
for (const
|
|
109
|
+
for (const { request, suggestedDescriptors: { suggestions, rejections } } of allSuggestions) {
|
|
107
110
|
const nonNullSuggestions = suggestions.filter(suggestion => {
|
|
108
111
|
return suggestion.descriptor !== null;
|
|
109
112
|
});
|
|
@@ -125,7 +128,7 @@ class AddCommand extends cli_1.BaseCommand {
|
|
|
125
128
|
let askedQuestions = false;
|
|
126
129
|
const afterWorkspaceDependencyAdditionList = [];
|
|
127
130
|
const afterWorkspaceDependencyReplacementList = [];
|
|
128
|
-
for (const
|
|
131
|
+
for (const { suggestedDescriptors: { suggestions }, target } of allSuggestions) {
|
|
129
132
|
let selected;
|
|
130
133
|
const nonNullSuggestions = suggestions.filter(suggestion => {
|
|
131
134
|
return suggestion.descriptor !== null;
|
|
@@ -236,7 +239,7 @@ AddCommand.usage = clipanion_1.Command.Usage({
|
|
|
236
239
|
|
|
237
240
|
If the \`--mode=<mode>\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:
|
|
238
241
|
|
|
239
|
-
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the
|
|
242
|
+
- \`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.
|
|
240
243
|
|
|
241
244
|
- \`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.
|
|
242
245
|
|
|
@@ -262,7 +265,7 @@ AddCommand.usage = clipanion_1.Command.Usage({
|
|
|
262
265
|
`$0 add lodash-es@lodash/lodash#es`,
|
|
263
266
|
]],
|
|
264
267
|
});
|
|
265
|
-
function
|
|
268
|
+
function suggestTargetList(workspace, ident, { dev, peer, preferDev, optional }) {
|
|
266
269
|
const hasRegular = workspace.manifest[suggestUtils.Target.REGULAR].has(ident.identHash);
|
|
267
270
|
const hasDev = workspace.manifest[suggestUtils.Target.DEVELOPMENT].has(ident.identHash);
|
|
268
271
|
const hasPeer = workspace.manifest[suggestUtils.Target.PEER].has(ident.identHash);
|
|
@@ -276,13 +279,21 @@ function suggestTarget(workspace, ident, { dev, peer, preferDev, optional }) {
|
|
|
276
279
|
throw new clipanion_1.UsageError(`Package "${core_3.structUtils.prettyIdent(workspace.project.configuration, ident)}" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);
|
|
277
280
|
if ((dev || preferDev) && optional)
|
|
278
281
|
throw new clipanion_1.UsageError(`Package "${core_3.structUtils.prettyIdent(workspace.project.configuration, ident)}" cannot simultaneously be a dev dependency and an optional dependency`);
|
|
282
|
+
// When the program executes this line, the command is expected to be legal
|
|
283
|
+
const targetList = [];
|
|
279
284
|
if (peer)
|
|
280
|
-
|
|
285
|
+
targetList.push(suggestUtils.Target.PEER);
|
|
281
286
|
if (dev || preferDev)
|
|
282
|
-
|
|
283
|
-
if (
|
|
284
|
-
|
|
287
|
+
targetList.push(suggestUtils.Target.DEVELOPMENT);
|
|
288
|
+
if (optional)
|
|
289
|
+
targetList.push(suggestUtils.Target.REGULAR);
|
|
290
|
+
// The user explicitly define the targets
|
|
291
|
+
if (targetList.length > 0)
|
|
292
|
+
return targetList;
|
|
293
|
+
// The user does not define the targets, find it from the `workspace.manifest`
|
|
285
294
|
if (hasDev)
|
|
286
|
-
return suggestUtils.Target.DEVELOPMENT;
|
|
287
|
-
|
|
295
|
+
return [suggestUtils.Target.DEVELOPMENT];
|
|
296
|
+
if (hasPeer)
|
|
297
|
+
return [suggestUtils.Target.PEER];
|
|
298
|
+
return [suggestUtils.Target.REGULAR];
|
|
288
299
|
}
|
package/lib/commands/dedupe.js
CHANGED
|
@@ -91,7 +91,7 @@ DedupeCommand.usage = clipanion_1.Command.Usage({
|
|
|
91
91
|
|
|
92
92
|
If the \`--mode=<mode>\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:
|
|
93
93
|
|
|
94
|
-
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the
|
|
94
|
+
- \`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.
|
|
95
95
|
|
|
96
96
|
- \`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.
|
|
97
97
|
|
package/lib/commands/info.js
CHANGED
|
@@ -160,7 +160,7 @@ class InfoCommand extends cli_1.BaseCommand {
|
|
|
160
160
|
const infoTreeChildren = {};
|
|
161
161
|
const infoTree = { children: infoTreeChildren };
|
|
162
162
|
const fetcher = configuration.makeFetcher();
|
|
163
|
-
const fetcherOptions = { project, fetcher, cache, checksums: project.storedChecksums, report: new core_1.ThrowReport(), cacheOptions: { skipIntegrityCheck: true }
|
|
163
|
+
const fetcherOptions = { project, fetcher, cache, checksums: project.storedChecksums, report: new core_1.ThrowReport(), cacheOptions: { skipIntegrityCheck: true } };
|
|
164
164
|
const builtinInfoBuilders = [
|
|
165
165
|
// Manifest fields
|
|
166
166
|
async (pkg, extra, registerData) => {
|
package/lib/commands/install.js
CHANGED
|
@@ -288,7 +288,7 @@ YarnCommand.usage = clipanion_1.Command.Usage({
|
|
|
288
288
|
|
|
289
289
|
If the \`--mode=<mode>\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:
|
|
290
290
|
|
|
291
|
-
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the
|
|
291
|
+
- \`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
292
|
|
|
293
293
|
- \`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
294
|
`,
|
|
@@ -303,9 +303,6 @@ YarnCommand.usage = clipanion_1.Command.Usage({
|
|
|
303
303
|
`$0 install --immutable --immutable-cache --check-cache`,
|
|
304
304
|
]],
|
|
305
305
|
});
|
|
306
|
-
const MERGE_CONFLICT_ANCESTOR = `|||||||`;
|
|
307
|
-
const MERGE_CONFLICT_END = `>>>>>>>`;
|
|
308
|
-
const MERGE_CONFLICT_SEP = `=======`;
|
|
309
306
|
const MERGE_CONFLICT_START = `<<<<<<<`;
|
|
310
307
|
async function autofixMergeConflicts(configuration, immutable) {
|
|
311
308
|
if (!configuration.projectCwd)
|
|
@@ -318,22 +315,57 @@ async function autofixMergeConflicts(configuration, immutable) {
|
|
|
318
315
|
return false;
|
|
319
316
|
if (immutable)
|
|
320
317
|
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_IMMUTABLE, `Cannot autofix a lockfile when running an immutable install`);
|
|
321
|
-
const [
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
318
|
+
const commits = await core_1.execUtils.execvp(`git`, [`rev-parse`, `MERGE_HEAD`, `HEAD`], {
|
|
319
|
+
cwd: configuration.projectCwd,
|
|
320
|
+
});
|
|
321
|
+
if (commits.code !== 0)
|
|
322
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_GIT_ERROR, `Git returned an error when trying to find the commits pertaining to the merge conflict`);
|
|
323
|
+
let variants = await Promise.all(commits.stdout.trim().split(/\n/).map(async (hash) => {
|
|
324
|
+
const content = await core_1.execUtils.execvp(`git`, [`show`, `${hash}:./${fslib_1.Filename.lockfile}`], {
|
|
325
|
+
cwd: configuration.projectCwd,
|
|
326
|
+
});
|
|
327
|
+
if (content.code !== 0)
|
|
328
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_GIT_ERROR, `Git returned an error when trying to access the lockfile content in ${hash}`);
|
|
329
|
+
try {
|
|
330
|
+
return (0, parsers_1.parseSyml)(content.stdout);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
throw new core_1.ReportError(core_1.MessageName.AUTOMERGE_FAILED_TO_PARSE, `A variant of the conflicting lockfile failed to parse`);
|
|
334
|
+
}
|
|
335
|
+
}));
|
|
335
336
|
// Old-style lockfiles should be filtered out (for example when switching
|
|
336
|
-
// from a Yarn 2 branch to a Yarn 1 branch).
|
|
337
|
+
// from a Yarn 2 branch to a Yarn 1 branch).
|
|
338
|
+
variants = variants.filter(variant => {
|
|
339
|
+
return !!variant.__metadata;
|
|
340
|
+
});
|
|
341
|
+
for (const variant of variants) {
|
|
342
|
+
// Pre-lockfile v7, the entries weren't normalized (ie we had "foo@x.y.z"
|
|
343
|
+
// in the lockfile rather than "foo@npm:x.y.z")
|
|
344
|
+
if (variant.__metadata.version < 7) {
|
|
345
|
+
for (const key of Object.keys(variant)) {
|
|
346
|
+
if (key === `__metadata`)
|
|
347
|
+
continue;
|
|
348
|
+
const descriptor = core_1.structUtils.parseDescriptor(key, true);
|
|
349
|
+
const normalizedDescriptor = configuration.normalizeDependency(descriptor);
|
|
350
|
+
const newKey = core_1.structUtils.stringifyDescriptor(normalizedDescriptor);
|
|
351
|
+
if (newKey !== key) {
|
|
352
|
+
variant[newKey] = variant[key];
|
|
353
|
+
delete variant[key];
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const merged = Object.assign({}, ...variants);
|
|
359
|
+
// We must keep the lockfile version as small as necessary to force Yarn to
|
|
360
|
+
// refresh the merged-in lockfile metadata that may be missing.
|
|
361
|
+
merged.__metadata.version = Math.min(0, ...variants.map(variant => {
|
|
362
|
+
var _a;
|
|
363
|
+
return (_a = variant.__metadata.version) !== null && _a !== void 0 ? _a : Infinity;
|
|
364
|
+
}));
|
|
365
|
+
merged.__metadata.cacheKey = Math.min(0, ...variants.map(variant => {
|
|
366
|
+
var _a;
|
|
367
|
+
return (_a = variant.__metadata.cacheKey) !== null && _a !== void 0 ? _a : 0;
|
|
368
|
+
}));
|
|
337
369
|
// parse as valid YAML except that the objects become strings. We can use
|
|
338
370
|
// that to detect them. Damn, it's really ugly though.
|
|
339
371
|
for (const [key, value] of Object.entries(merged))
|
|
@@ -344,52 +376,3 @@ async function autofixMergeConflicts(configuration, immutable) {
|
|
|
344
376
|
});
|
|
345
377
|
return true;
|
|
346
378
|
}
|
|
347
|
-
function getVariants(file) {
|
|
348
|
-
const variants = [[], []];
|
|
349
|
-
const lines = file.split(/\r?\n/g);
|
|
350
|
-
let skip = false;
|
|
351
|
-
while (lines.length > 0) {
|
|
352
|
-
const line = lines.shift();
|
|
353
|
-
if (typeof line === `undefined`)
|
|
354
|
-
throw new Error(`Assertion failed: Some lines should remain`);
|
|
355
|
-
if (line.startsWith(MERGE_CONFLICT_START)) {
|
|
356
|
-
// get the first variant
|
|
357
|
-
while (lines.length > 0) {
|
|
358
|
-
const conflictLine = lines.shift();
|
|
359
|
-
if (typeof conflictLine === `undefined`)
|
|
360
|
-
throw new Error(`Assertion failed: Some lines should remain`);
|
|
361
|
-
if (conflictLine === MERGE_CONFLICT_SEP) {
|
|
362
|
-
skip = false;
|
|
363
|
-
break;
|
|
364
|
-
}
|
|
365
|
-
else if (skip || conflictLine.startsWith(MERGE_CONFLICT_ANCESTOR)) {
|
|
366
|
-
skip = true;
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
variants[0].push(conflictLine);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
// get the second variant
|
|
374
|
-
while (lines.length > 0) {
|
|
375
|
-
const conflictLine = lines.shift();
|
|
376
|
-
if (typeof conflictLine === `undefined`)
|
|
377
|
-
throw new Error(`Assertion failed: Some lines should remain`);
|
|
378
|
-
if (conflictLine.startsWith(MERGE_CONFLICT_END)) {
|
|
379
|
-
break;
|
|
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
|
-
];
|
|
395
|
-
}
|
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,29 +28,35 @@ 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
62
|
const fullName = core_1.structUtils.stringifyIdent(workspace.locator);
|
|
@@ -81,8 +87,8 @@ LinkCommand.usage = clipanion_1.Command.Usage({
|
|
|
81
87
|
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
88
|
`,
|
|
83
89
|
examples: [[
|
|
84
|
-
`Register
|
|
85
|
-
`$0 link ~/ts-loader`,
|
|
90
|
+
`Register one or more remote workspaces for use in the current project`,
|
|
91
|
+
`$0 link ~/ts-loader ~/jest`,
|
|
86
92
|
], [
|
|
87
93
|
`Register all workspaces from a remote project for use in the current project`,
|
|
88
94
|
`$0 link ~/jest --all`,
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
var _a;
|
|
23
|
+
for (const rcFile of rcFiles) {
|
|
24
|
+
if (!((_a = rcFile.data) === null || _a === void 0 ? void 0 : _a.plugins))
|
|
25
|
+
continue;
|
|
26
|
+
for (const plugin of rcFile.data.plugins) {
|
|
27
|
+
if (!plugin.checksum)
|
|
28
|
+
continue;
|
|
29
|
+
if (!plugin.spec.match(/^https?:/))
|
|
30
|
+
continue;
|
|
31
|
+
const newBuffer = await core_1.httpUtils.get(plugin.spec, { configuration });
|
|
32
|
+
const newChecksum = core_1.hashUtils.makeHash(newBuffer);
|
|
33
|
+
if (plugin.checksum === newChecksum)
|
|
34
|
+
continue;
|
|
35
|
+
const prettyPath = core_1.formatUtils.pretty(configuration, plugin.path, core_1.formatUtils.Type.PATH);
|
|
36
|
+
const prettySpec = core_1.formatUtils.pretty(configuration, plugin.spec, core_1.formatUtils.Type.URL);
|
|
37
|
+
const prettyMessage = `${prettyPath} is different from the file provided by ${prettySpec}`;
|
|
38
|
+
report.reportJson({ ...plugin, newChecksum });
|
|
39
|
+
report.reportError(core_1.MessageName.UNNAMED, prettyMessage);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return report.exitCode();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = PluginCheckCommand;
|
|
47
|
+
PluginCheckCommand.paths = [
|
|
48
|
+
[`plugin`, `check`],
|
|
49
|
+
];
|
|
50
|
+
PluginCheckCommand.usage = clipanion_1.Command.Usage({
|
|
51
|
+
category: `Plugin-related commands`,
|
|
52
|
+
description: `find all third-party plugins that differ from their own spec`,
|
|
53
|
+
details: `
|
|
54
|
+
Check only the plugins from https.
|
|
55
|
+
|
|
56
|
+
If this command detects any plugin differences in the CI environment, it will throw an error.
|
|
57
|
+
`,
|
|
58
|
+
examples: [[
|
|
59
|
+
`find all third-party plugins that differ from their own spec`,
|
|
60
|
+
`$0 plugin check`,
|
|
61
|
+
]],
|
|
62
|
+
});
|
|
@@ -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;
|
|
@@ -14,7 +14,7 @@ export default class PluginDlSourcesCommand extends BaseCommand {
|
|
|
14
14
|
name: string;
|
|
15
15
|
execute(): Promise<1 | 0>;
|
|
16
16
|
}
|
|
17
|
-
export
|
|
17
|
+
export type BuildAndSavePluginsSpec = {
|
|
18
18
|
context: CommandContext;
|
|
19
19
|
noMinify: boolean;
|
|
20
20
|
};
|
|
@@ -14,7 +14,7 @@ const buildWorkflow = ({ pluginName, noMinify }, target) => [
|
|
|
14
14
|
[`yarn`, `build:${pluginName}`, ...noMinify ? [`--no-minify`] : [], `|`],
|
|
15
15
|
];
|
|
16
16
|
// eslint-disable-next-line arca/no-default-export
|
|
17
|
-
class
|
|
17
|
+
class PluginImportSourcesCommand extends cli_1.BaseCommand {
|
|
18
18
|
constructor() {
|
|
19
19
|
super(...arguments);
|
|
20
20
|
this.installPath = clipanion_1.Option.String(`--path`, {
|
|
@@ -56,11 +56,11 @@ class PluginDlSourcesCommand extends cli_1.BaseCommand {
|
|
|
56
56
|
return report.exitCode();
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
exports.default =
|
|
60
|
-
|
|
59
|
+
exports.default = PluginImportSourcesCommand;
|
|
60
|
+
PluginImportSourcesCommand.paths = [
|
|
61
61
|
[`plugin`, `import`, `from`, `sources`],
|
|
62
62
|
];
|
|
63
|
-
|
|
63
|
+
PluginImportSourcesCommand.usage = clipanion_1.Command.Usage({
|
|
64
64
|
category: `Plugin-related commands`,
|
|
65
65
|
description: `build a plugin from sources`,
|
|
66
66
|
details: `
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
2
|
import { BaseCommand } from '@yarnpkg/cli';
|
|
4
3
|
import { Project, Report } from '@yarnpkg/core';
|
|
5
4
|
import { Usage } from 'clipanion';
|
|
6
|
-
export default class
|
|
5
|
+
export default class PluginImportCommand extends BaseCommand {
|
|
7
6
|
static paths: string[][];
|
|
8
7
|
static usage: Usage;
|
|
9
8
|
name: string;
|
|
9
|
+
checksum: boolean;
|
|
10
10
|
execute(): Promise<1 | 0>;
|
|
11
11
|
}
|
|
12
|
-
export declare function savePlugin(pluginSpec: string, pluginBuffer: Buffer, { project, report }: {
|
|
12
|
+
export declare function savePlugin(pluginSpec: string, pluginBuffer: Buffer, { checksum, project, report }: {
|
|
13
|
+
checksum?: boolean;
|
|
13
14
|
project: Project;
|
|
14
15
|
report: Report;
|
|
15
16
|
}): Promise<void>;
|
|
@@ -12,10 +12,13 @@ const url_1 = require("url");
|
|
|
12
12
|
const vm_1 = require("vm");
|
|
13
13
|
const list_1 = require("./list");
|
|
14
14
|
// eslint-disable-next-line arca/no-default-export
|
|
15
|
-
class
|
|
15
|
+
class PluginImportCommand extends cli_1.BaseCommand {
|
|
16
16
|
constructor() {
|
|
17
17
|
super(...arguments);
|
|
18
18
|
this.name = clipanion_1.Option.String();
|
|
19
|
+
this.checksum = clipanion_1.Option.Boolean(`--checksum`, true, {
|
|
20
|
+
description: `Whether to care if this plugin is modified`,
|
|
21
|
+
});
|
|
19
22
|
}
|
|
20
23
|
async execute() {
|
|
21
24
|
const configuration = await core_1.Configuration.find(this.context.cwd, this.context.plugins);
|
|
@@ -70,16 +73,16 @@ class PluginDlCommand extends cli_1.BaseCommand {
|
|
|
70
73
|
report.reportInfo(core_1.MessageName.UNNAMED, `Downloading ${core_2.formatUtils.pretty(configuration, pluginUrl, `green`)}`);
|
|
71
74
|
pluginBuffer = await core_2.httpUtils.get(pluginUrl, { configuration });
|
|
72
75
|
}
|
|
73
|
-
await savePlugin(pluginSpec, pluginBuffer, { project, report });
|
|
76
|
+
await savePlugin(pluginSpec, pluginBuffer, { checksum: this.checksum, project, report });
|
|
74
77
|
});
|
|
75
78
|
return report.exitCode();
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
|
-
exports.default =
|
|
79
|
-
|
|
81
|
+
exports.default = PluginImportCommand;
|
|
82
|
+
PluginImportCommand.paths = [
|
|
80
83
|
[`plugin`, `import`],
|
|
81
84
|
];
|
|
82
|
-
|
|
85
|
+
PluginImportCommand.usage = clipanion_1.Command.Usage({
|
|
83
86
|
category: `Plugin-related commands`,
|
|
84
87
|
description: `download a plugin`,
|
|
85
88
|
details: `
|
|
@@ -91,6 +94,8 @@ PluginDlCommand.usage = clipanion_1.Command.Usage({
|
|
|
91
94
|
- Third-party plugins can be referenced directly through their public urls.
|
|
92
95
|
- Local plugins can be referenced by their path on the disk.
|
|
93
96
|
|
|
97
|
+
If the \`--no-checksum\` option is set, Yarn will no longer care if the plugin is modified.
|
|
98
|
+
|
|
94
99
|
Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \`@yarnpkg/builder\` package).
|
|
95
100
|
`,
|
|
96
101
|
examples: [[
|
|
@@ -107,7 +112,7 @@ PluginDlCommand.usage = clipanion_1.Command.Usage({
|
|
|
107
112
|
`$0 plugin import ./path/to/plugin.js`,
|
|
108
113
|
]],
|
|
109
114
|
});
|
|
110
|
-
async function savePlugin(pluginSpec, pluginBuffer, { project, report }) {
|
|
115
|
+
async function savePlugin(pluginSpec, pluginBuffer, { checksum = true, project, report }) {
|
|
111
116
|
const { configuration } = project;
|
|
112
117
|
const vmExports = {};
|
|
113
118
|
const vmModule = { exports: vmExports };
|
|
@@ -125,26 +130,8 @@ async function savePlugin(pluginSpec, pluginBuffer, { project, report }) {
|
|
|
125
130
|
path: relativePath,
|
|
126
131
|
spec: pluginSpec,
|
|
127
132
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
for (const entry of current.plugins || []) {
|
|
132
|
-
const userProvidedPath = typeof entry !== `string`
|
|
133
|
-
? entry.path
|
|
134
|
-
: entry;
|
|
135
|
-
const pluginPath = fslib_1.ppath.resolve(project.cwd, fslib_1.npath.toPortablePath(userProvidedPath));
|
|
136
|
-
const { name } = core_1.miscUtils.dynamicRequire(pluginPath);
|
|
137
|
-
if (name !== pluginName) {
|
|
138
|
-
plugins.push(entry);
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
plugins.push(pluginMeta);
|
|
142
|
-
hasBeenReplaced = true;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (!hasBeenReplaced)
|
|
146
|
-
plugins.push(pluginMeta);
|
|
147
|
-
return { ...current, plugins };
|
|
148
|
-
});
|
|
133
|
+
if (checksum)
|
|
134
|
+
pluginMeta.checksum = core_2.hashUtils.makeHash(pluginBuffer);
|
|
135
|
+
await core_1.Configuration.addPlugin(project.cwd, [pluginMeta]);
|
|
149
136
|
}
|
|
150
137
|
exports.savePlugin = savePlugin;
|
|
@@ -4,7 +4,7 @@ import { Usage } from 'clipanion';
|
|
|
4
4
|
export declare function getAvailablePlugins(configuration: Configuration, version: string | null): Promise<{
|
|
5
5
|
[k: string]: any;
|
|
6
6
|
}>;
|
|
7
|
-
export default class
|
|
7
|
+
export default class PluginListCommand extends BaseCommand {
|
|
8
8
|
static paths: string[][];
|
|
9
9
|
static usage: Usage;
|
|
10
10
|
json: boolean;
|
|
@@ -16,7 +16,7 @@ async function getAvailablePlugins(configuration, version) {
|
|
|
16
16
|
}
|
|
17
17
|
exports.getAvailablePlugins = getAvailablePlugins;
|
|
18
18
|
// eslint-disable-next-line arca/no-default-export
|
|
19
|
-
class
|
|
19
|
+
class PluginListCommand extends cli_1.BaseCommand {
|
|
20
20
|
constructor() {
|
|
21
21
|
super(...arguments);
|
|
22
22
|
this.json = clipanion_1.Option.Boolean(`--json`, false, {
|
|
@@ -42,11 +42,11 @@ class PluginDlCommand extends cli_1.BaseCommand {
|
|
|
42
42
|
return report.exitCode();
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
exports.default =
|
|
46
|
-
|
|
45
|
+
exports.default = PluginListCommand;
|
|
46
|
+
PluginListCommand.paths = [
|
|
47
47
|
[`plugin`, `list`],
|
|
48
48
|
];
|
|
49
|
-
|
|
49
|
+
PluginListCommand.usage = clipanion_1.Command.Usage({
|
|
50
50
|
category: `Plugin-related commands`,
|
|
51
51
|
description: `list the available official plugins`,
|
|
52
52
|
details: `
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseCommand } from '@yarnpkg/cli';
|
|
2
2
|
import { Usage } from 'clipanion';
|
|
3
|
-
export default class
|
|
3
|
+
export default class PluginRuntimeCommand extends BaseCommand {
|
|
4
4
|
static paths: string[][];
|
|
5
5
|
static usage: Usage;
|
|
6
6
|
json: boolean;
|
|
@@ -4,7 +4,7 @@ const cli_1 = require("@yarnpkg/cli");
|
|
|
4
4
|
const core_1 = require("@yarnpkg/core");
|
|
5
5
|
const clipanion_1 = require("clipanion");
|
|
6
6
|
// eslint-disable-next-line arca/no-default-export
|
|
7
|
-
class
|
|
7
|
+
class PluginRuntimeCommand extends cli_1.BaseCommand {
|
|
8
8
|
constructor() {
|
|
9
9
|
super(...arguments);
|
|
10
10
|
this.json = clipanion_1.Option.Boolean(`--json`, false, {
|
|
@@ -30,11 +30,11 @@ class PluginListCommand extends cli_1.BaseCommand {
|
|
|
30
30
|
return report.exitCode();
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
exports.default =
|
|
34
|
-
|
|
33
|
+
exports.default = PluginRuntimeCommand;
|
|
34
|
+
PluginRuntimeCommand.paths = [
|
|
35
35
|
[`plugin`, `runtime`],
|
|
36
36
|
];
|
|
37
|
-
|
|
37
|
+
PluginRuntimeCommand.usage = clipanion_1.Command.Usage({
|
|
38
38
|
category: `Plugin-related commands`,
|
|
39
39
|
description: `list the active plugins`,
|
|
40
40
|
details: `
|