@yarnpkg/plugin-essentials 4.0.0 → 4.0.2

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.
@@ -240,7 +240,7 @@ AddCommand.usage = clipanion_1.Command.Usage({
240
240
 
241
241
  - \`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
242
 
243
- For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/features/protocols.
243
+ For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/protocols.
244
244
  `,
245
245
  examples: [[
246
246
  `Add a regular package to the current workspace`,
@@ -5,7 +5,7 @@ import { Writable } from 'stream';
5
5
  export default class ExplainPeerRequirementsCommand extends BaseCommand {
6
6
  static paths: string[][];
7
7
  static usage: import("clipanion").Usage;
8
- hash: string | undefined;
8
+ hash: string;
9
9
  execute(): Promise<0 | 1>;
10
10
  }
11
11
  export declare function explainPeerRequirements(peerRequirementsHash: string, project: Project, opts: {
@@ -11,8 +11,7 @@ class ExplainPeerRequirementsCommand extends cli_1.BaseCommand {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.hash = clipanion_1.Option.String({
14
- required: false,
15
- validator: t.applyCascade(t.isString(), [
14
+ validator: t.cascade(t.isString(), [
16
15
  t.matchesRegExp(/^p[0-9a-f]{5}$/),
17
16
  ]),
18
17
  });
@@ -23,42 +22,10 @@ class ExplainPeerRequirementsCommand extends cli_1.BaseCommand {
23
22
  await project.restoreInstallState({
24
23
  restoreResolutions: false,
25
24
  });
26
- // peerRequirements aren't stored inside the install state
27
25
  await project.applyLightResolution();
28
- if (typeof this.hash !== `undefined`) {
29
- return await explainPeerRequirements(this.hash, project, {
30
- stdout: this.context.stdout,
31
- });
32
- }
33
- const report = await core_1.StreamReport.start({
34
- configuration,
26
+ return await explainPeerRequirements(this.hash, project, {
35
27
  stdout: this.context.stdout,
36
- includeFooter: false,
37
- }, async (report) => {
38
- const sortCriterias = [
39
- ([, requirement]) => core_1.structUtils.stringifyLocator(project.storedPackages.get(requirement.subject)),
40
- ([, requirement]) => core_1.structUtils.stringifyIdent(requirement.requested),
41
- ];
42
- for (const [hash, requirement] of core_1.miscUtils.sortMap(project.peerRequirements, sortCriterias)) {
43
- const subject = project.storedPackages.get(requirement.subject);
44
- if (typeof subject === `undefined`)
45
- throw new Error(`Assertion failed: Expected the subject package to have been registered`);
46
- const rootRequester = project.storedPackages.get(requirement.rootRequester);
47
- if (typeof rootRequester === `undefined`)
48
- throw new Error(`Assertion failed: Expected the root package to have been registered`);
49
- const providedDescriptor = subject.dependencies.get(requirement.requested.identHash) ?? null;
50
- const prettyHash = core_1.formatUtils.pretty(configuration, hash, core_1.formatUtils.Type.CODE);
51
- const prettySubject = core_1.structUtils.prettyLocator(configuration, subject);
52
- const prettyIdent = core_1.structUtils.prettyIdent(configuration, requirement.requested);
53
- const prettyRoot = core_1.structUtils.prettyIdent(configuration, rootRequester);
54
- const descendantCount = requirement.allRequesters.length - 1;
55
- const pluralized = `descendant${descendantCount === 1 ? `` : `s`}`;
56
- const maybeDescendants = descendantCount > 0 ? ` and ${descendantCount} ${pluralized}` : ``;
57
- const provides = providedDescriptor !== null ? `provides` : `doesn't provide`;
58
- report.reportInfo(null, `${prettyHash} → ${prettySubject} ${provides} ${prettyIdent} to ${prettyRoot}${maybeDescendants}`);
59
- }
60
28
  });
61
- return report.exitCode();
62
29
  }
63
30
  }
64
31
  ExplainPeerRequirementsCommand.paths = [
@@ -85,79 +52,83 @@ ExplainPeerRequirementsCommand.usage = clipanion_1.Command.Usage({
85
52
  });
86
53
  exports.default = ExplainPeerRequirementsCommand;
87
54
  async function explainPeerRequirements(peerRequirementsHash, project, opts) {
88
- const { configuration } = project;
89
- const requirement = project.peerRequirements.get(peerRequirementsHash);
90
- if (typeof requirement === `undefined`)
55
+ const warning = project.peerWarnings.find(warning => {
56
+ return warning.hash === peerRequirementsHash;
57
+ });
58
+ if (typeof warning === `undefined`)
91
59
  throw new Error(`No peerDependency requirements found for hash: "${peerRequirementsHash}"`);
92
60
  const report = await core_1.StreamReport.start({
93
- configuration,
61
+ configuration: project.configuration,
94
62
  stdout: opts.stdout,
95
63
  includeFooter: false,
64
+ includePrefix: false,
96
65
  }, async (report) => {
97
- const subject = project.storedPackages.get(requirement.subject);
98
- if (typeof subject === `undefined`)
99
- throw new Error(`Assertion failed: Expected the subject package to have been registered`);
100
- const rootRequester = project.storedPackages.get(requirement.rootRequester);
101
- if (typeof rootRequester === `undefined`)
102
- throw new Error(`Assertion failed: Expected the root package to have been registered`);
103
- const providedDescriptor = subject.dependencies.get(requirement.requested.identHash) ?? null;
104
- const providedResolution = providedDescriptor !== null
105
- ? project.storedResolutions.get(providedDescriptor.descriptorHash)
106
- : null;
107
- if (typeof providedResolution === `undefined`)
108
- throw new Error(`Assertion failed: Expected the resolution to have been registered`);
109
- const provided = providedResolution !== null
110
- ? project.storedPackages.get(providedResolution)
111
- : null;
112
- if (typeof provided === `undefined`)
113
- throw new Error(`Assertion failed: Expected the provided package to have been registered`);
114
- const allRequesters = [...requirement.allRequesters.values()].map(requesterHash => {
115
- const pkg = project.storedPackages.get(requesterHash);
116
- if (typeof pkg === `undefined`)
117
- throw new Error(`Assertion failed: Expected the package to be registered`);
118
- const devirtualizedLocator = core_1.structUtils.devirtualizeLocator(pkg);
119
- const devirtualizedPkg = project.storedPackages.get(devirtualizedLocator.locatorHash);
120
- if (typeof devirtualizedPkg === `undefined`)
121
- throw new Error(`Assertion failed: Expected the package to be registered`);
122
- const peerDependency = devirtualizedPkg.peerDependencies.get(requirement.requested.identHash);
123
- if (typeof peerDependency === `undefined`)
124
- throw new Error(`Assertion failed: Expected the peer dependency to be registered`);
125
- return { pkg, peerDependency };
126
- });
127
- if (provided !== null) {
128
- const satisfiesAllRanges = allRequesters.every(({ peerDependency }) => {
129
- return core_1.semverUtils.satisfiesWithPrereleases(provided.version, peerDependency.range);
130
- });
131
- report.reportInfo(core_1.MessageName.UNNAMED, `${core_1.structUtils.prettyLocator(configuration, subject)} provides ${core_1.structUtils.prettyLocator(configuration, provided)} with version ${core_1.structUtils.prettyReference(configuration, provided.version ?? `<missing>`)}, which ${satisfiesAllRanges ? `satisfies` : `doesn't satisfy`} the following requirements:`);
132
- }
133
- else {
134
- report.reportInfo(core_1.MessageName.UNNAMED, `${core_1.structUtils.prettyLocator(configuration, subject)} doesn't provide ${core_1.structUtils.prettyIdent(configuration, requirement.requested)}, breaking the following requirements:`);
135
- }
136
- report.reportSeparator();
137
- const Mark = core_1.formatUtils.mark(configuration);
138
- const requirements = [];
139
- for (const { pkg, peerDependency } of core_1.miscUtils.sortMap(allRequesters, requester => core_1.structUtils.stringifyLocator(requester.pkg))) {
140
- const isSatisfied = provided !== null
141
- ? core_1.semverUtils.satisfiesWithPrereleases(provided.version, peerDependency.range)
142
- : false;
143
- const mark = isSatisfied ? Mark.Check : Mark.Cross;
144
- requirements.push({
145
- stringifiedLocator: core_1.structUtils.stringifyLocator(pkg),
146
- prettyLocator: core_1.structUtils.prettyLocator(configuration, pkg),
147
- prettyRange: core_1.structUtils.prettyRange(configuration, peerDependency.range),
148
- mark,
149
- });
150
- }
151
- const maxStringifiedLocatorLength = Math.max(...requirements.map(({ stringifiedLocator }) => stringifiedLocator.length));
152
- const maxPrettyRangeLength = Math.max(...requirements.map(({ prettyRange }) => prettyRange.length));
153
- for (const { stringifiedLocator, prettyLocator, prettyRange, mark } of core_1.miscUtils.sortMap(requirements, ({ stringifiedLocator }) => stringifiedLocator)) {
154
- report.reportInfo(null, `${
155
- // We have to do this because prettyLocators can contain multiple colors
156
- prettyLocator.padEnd(maxStringifiedLocatorLength + (prettyLocator.length - stringifiedLocator.length), ` `)} → ${prettyRange.padEnd(maxPrettyRangeLength, ` `)} ${mark}`);
157
- }
158
- if (requirements.length > 1) {
159
- report.reportSeparator();
160
- report.reportInfo(core_1.MessageName.UNNAMED, `Note: these requirements start with ${core_1.structUtils.prettyLocator(project.configuration, rootRequester)}`);
66
+ const Marks = core_1.formatUtils.mark(project.configuration);
67
+ switch (warning.type) {
68
+ case core_1.PeerWarningType.NotCompatibleAggregate:
69
+ {
70
+ report.reportInfo(core_1.MessageName.UNNAMED, `We have a problem with ${core_1.formatUtils.pretty(project.configuration, warning.requested, core_1.formatUtils.Type.IDENT)}, which is provided with version ${core_1.structUtils.prettyReference(project.configuration, warning.version)}.`);
71
+ report.reportInfo(core_1.MessageName.UNNAMED, `It is needed by the following direct dependencies of workspaces in your project:`);
72
+ report.reportSeparator();
73
+ for (const dependent of warning.requesters.values()) {
74
+ const dependentPkg = project.storedPackages.get(dependent.locatorHash);
75
+ if (!dependentPkg)
76
+ throw new Error(`Assertion failed: Expected the package to be registered`);
77
+ const descriptor = dependentPkg?.peerDependencies.get(warning.requested.identHash);
78
+ if (!descriptor)
79
+ throw new Error(`Assertion failed: Expected the package to list the peer dependency`);
80
+ const mark = core_1.semverUtils.satisfiesWithPrereleases(warning.version, descriptor.range)
81
+ ? Marks.Check
82
+ : Marks.Cross;
83
+ report.reportInfo(null, ` ${mark} ${core_1.structUtils.prettyLocator(project.configuration, dependent)} (via ${core_1.structUtils.prettyRange(project.configuration, descriptor.range)})`);
84
+ }
85
+ const transitiveLinks = [...warning.links.values()].filter(link => {
86
+ return !warning.requesters.has(link.locatorHash);
87
+ });
88
+ if (transitiveLinks.length > 0) {
89
+ report.reportSeparator();
90
+ report.reportInfo(core_1.MessageName.UNNAMED, `However, those packages themselves have more dependencies listing ${core_1.structUtils.prettyIdent(project.configuration, warning.requested)} as peer dependency:`);
91
+ report.reportSeparator();
92
+ for (const link of transitiveLinks) {
93
+ const linkPkg = project.storedPackages.get(link.locatorHash);
94
+ if (!linkPkg)
95
+ throw new Error(`Assertion failed: Expected the package to be registered`);
96
+ const descriptor = linkPkg?.peerDependencies.get(warning.requested.identHash);
97
+ if (!descriptor)
98
+ throw new Error(`Assertion failed: Expected the package to list the peer dependency`);
99
+ const mark = core_1.semverUtils.satisfiesWithPrereleases(warning.version, descriptor.range)
100
+ ? Marks.Check
101
+ : Marks.Cross;
102
+ report.reportInfo(null, ` ${mark} ${core_1.structUtils.prettyLocator(project.configuration, link)} (via ${core_1.structUtils.prettyRange(project.configuration, descriptor.range)})`);
103
+ }
104
+ }
105
+ const allRanges = Array.from(warning.links.values(), locator => {
106
+ const pkg = project.storedPackages.get(locator.locatorHash);
107
+ if (typeof pkg === `undefined`)
108
+ throw new Error(`Assertion failed: Expected the package to be registered`);
109
+ const peerDependency = pkg.peerDependencies.get(warning.requested.identHash);
110
+ if (typeof peerDependency === `undefined`)
111
+ throw new Error(`Assertion failed: Expected the ident to be registered`);
112
+ return peerDependency.range;
113
+ });
114
+ if (allRanges.length > 1) {
115
+ const resolvedRange = core_1.semverUtils.simplifyRanges(allRanges);
116
+ report.reportSeparator();
117
+ if (resolvedRange === null) {
118
+ report.reportInfo(core_1.MessageName.UNNAMED, `Unfortunately, put together, we found no single range that can satisfy all those peer requirements.`);
119
+ report.reportInfo(core_1.MessageName.UNNAMED, `Your best option may be to try to upgrade some dependencies with ${core_1.formatUtils.pretty(project.configuration, `yarn up`, core_1.formatUtils.Type.CODE)}, or silence the warning via ${core_1.formatUtils.pretty(project.configuration, `logFilters`, core_1.formatUtils.Type.CODE)}.`);
120
+ }
121
+ else {
122
+ report.reportInfo(core_1.MessageName.UNNAMED, `Put together, the final range we computed is ${core_1.formatUtils.pretty(project.configuration, resolvedRange, core_1.formatUtils.Type.RANGE)}`);
123
+ }
124
+ }
125
+ }
126
+ break;
127
+ default:
128
+ {
129
+ report.reportInfo(core_1.MessageName.UNNAMED, `The ${core_1.formatUtils.pretty(project.configuration, `yarn explain peer-requirements`, core_1.formatUtils.Type.CODE)} command doesn't support this warning type yet.`);
130
+ }
131
+ break;
161
132
  }
162
133
  });
163
134
  return report.exitCode();
@@ -241,6 +241,18 @@ class YarnCommand extends cli_1.BaseCommand {
241
241
  restoreResolutions: false,
242
242
  });
243
243
  const enableHardenedMode = configuration.get(`enableHardenedMode`);
244
+ if (enableHardenedMode && typeof configuration.sources.get(`enableHardenedMode`) === `undefined`) {
245
+ await core_1.StreamReport.start({
246
+ configuration,
247
+ json: this.json,
248
+ stdout: this.context.stdout,
249
+ includeFooter: false,
250
+ }, async (report) => {
251
+ report.reportWarning(core_1.MessageName.UNNAMED, `Yarn detected that the current workflow is executed from a public pull request. For safety the hardened mode has been enabled.`);
252
+ report.reportWarning(core_1.MessageName.UNNAMED, `It will prevent malicious lockfile manipulations, in exchange for a slower install time. You can opt-out if necessary; check our ${core_1.formatUtils.applyHyperlink(configuration, `documentation`, `https://yarnpkg.com/features/security#hardened-mode`)} for more details.`);
253
+ report.reportSeparator();
254
+ });
255
+ }
244
256
  if (this.refreshLockfile ?? enableHardenedMode)
245
257
  project.lockfileNeedsRefresh = true;
246
258
  const checkResolutions = this.checkResolutions ?? enableHardenedMode;
@@ -251,15 +263,17 @@ class YarnCommand extends cli_1.BaseCommand {
251
263
  // install logic should be implemented elsewhere (probably in either of
252
264
  // the Configuration and Install classes). Feel free to open an issue
253
265
  // in order to ask for design feedback before writing features.
254
- return await project.installWithNewReport({
266
+ const report = await core_1.StreamReport.start({
267
+ configuration,
255
268
  json: this.json,
256
269
  stdout: this.context.stdout,
257
- }, {
258
- cache,
259
- immutable,
260
- checkResolutions,
261
- mode: this.mode,
270
+ forceSectionAlignment: true,
271
+ includeLogs: true,
272
+ includeVersion: true,
273
+ }, async (report) => {
274
+ await project.install({ cache, report, immutable, checkResolutions, mode: this.mode });
262
275
  });
276
+ return report.exitCode();
263
277
  }
264
278
  }
265
279
  YarnCommand.paths = [
@@ -3,7 +3,6 @@ import { Usage } from 'clipanion';
3
3
  export default class SetResolutionCommand extends BaseCommand {
4
4
  static paths: string[][];
5
5
  static usage: Usage;
6
- save: boolean;
7
6
  descriptor: string;
8
7
  resolution: string;
9
8
  execute(): Promise<0 | 1>;
@@ -8,9 +8,6 @@ const clipanion_1 = require("clipanion");
8
8
  class SetResolutionCommand extends cli_1.BaseCommand {
9
9
  constructor() {
10
10
  super(...arguments);
11
- this.save = clipanion_1.Option.Boolean(`-s,--save`, false, {
12
- description: `Persist the resolution inside the top-level manifest`,
13
- });
14
11
  this.descriptor = clipanion_1.Option.String();
15
12
  this.resolution = clipanion_1.Option.String();
16
13
  }
@@ -43,7 +40,7 @@ SetResolutionCommand.usage = clipanion_1.Command.Usage({
43
40
  details: `
44
41
  This command updates the resolution table so that \`descriptor\` is resolved by \`resolution\`.
45
42
 
46
- Note that by default this command only affect the current resolution table - meaning that this "manual override" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, add the \`-s,--save\` flag which will also edit the \`resolutions\` field from your top-level manifest.
43
+ Note that by default this command only affect the current resolution table - meaning that this "manual override" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, edit the \`resolutions\` field in your top-level manifest.
47
44
 
48
45
  Note that no attempt is made at validating that \`resolution\` is a valid resolution entry for \`descriptor\`.
49
46
  `,
@@ -10,6 +10,7 @@ const sources_1 = require("../../plugin/import/sources");
10
10
  const list_1 = require("../../plugin/list");
11
11
  const version_1 = require("../version");
12
12
  const PR_REGEXP = /^[0-9]+$/;
13
+ const IS_WIN32 = process.platform === `win32`;
13
14
  function getBranchRef(branch) {
14
15
  if (PR_REGEXP.test(branch)) {
15
16
  return `pull/${branch}/head`;
@@ -31,7 +32,7 @@ const updateWorkflow = ({ branch }) => [
31
32
  ];
32
33
  const buildWorkflow = ({ plugins, noMinify }, output, target) => [
33
34
  [`yarn`, `build:cli`, ...new Array().concat(...plugins.map(plugin => [`--plugin`, fslib_1.ppath.resolve(target, plugin)])), ...noMinify ? [`--no-minify`] : [], `|`],
34
- [`mv`, `packages/yarnpkg-cli/bundles/yarn.js`, fslib_1.npath.fromPortablePath(output), `|`],
35
+ [IS_WIN32 ? `move` : `mv`, `packages/yarnpkg-cli/bundles/yarn.js`, fslib_1.npath.fromPortablePath(output), `|`],
35
36
  ];
36
37
  // eslint-disable-next-line arca/no-default-export
37
38
  class SetVersionSourcesCommand extends cli_1.BaseCommand {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yarnpkg/plugin-essentials",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "license": "BSD-2-Clause",
5
5
  "main": "./lib/index.js",
6
6
  "exports": {
@@ -8,7 +8,7 @@
8
8
  "./package.json": "./package.json"
9
9
  },
10
10
  "dependencies": {
11
- "@yarnpkg/fslib": "^3.0.0",
11
+ "@yarnpkg/fslib": "^3.0.1",
12
12
  "@yarnpkg/parsers": "^3.0.0",
13
13
  "ci-info": "^3.2.0",
14
14
  "clipanion": "^4.0.0-rc.2",
@@ -20,16 +20,16 @@
20
20
  "typanion": "^3.14.0"
21
21
  },
22
22
  "peerDependencies": {
23
- "@yarnpkg/cli": "^4.0.0",
24
- "@yarnpkg/core": "^4.0.0",
23
+ "@yarnpkg/cli": "^4.0.2",
24
+ "@yarnpkg/core": "^4.0.2",
25
25
  "@yarnpkg/plugin-git": "^3.0.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/lodash": "^4.14.136",
29
29
  "@types/micromatch": "^4.0.1",
30
30
  "@types/semver": "^7.1.0",
31
- "@yarnpkg/cli": "^4.0.0",
32
- "@yarnpkg/core": "^4.0.0",
31
+ "@yarnpkg/cli": "^4.0.2",
32
+ "@yarnpkg/core": "^4.0.2",
33
33
  "@yarnpkg/plugin-git": "^3.0.0"
34
34
  },
35
35
  "repository": {