@yarnpkg/plugin-essentials 4.0.0-rc.50 → 4.0.0-rc.52

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.
@@ -3,6 +3,7 @@ import { Usage } from 'clipanion';
3
3
  export default class ConfigGetCommand extends BaseCommand {
4
4
  static paths: string[][];
5
5
  static usage: Usage;
6
+ why: boolean;
6
7
  json: boolean;
7
8
  unsafe: boolean;
8
9
  name: string;
@@ -10,6 +10,9 @@ const util_1 = require("util");
10
10
  class ConfigGetCommand extends cli_1.BaseCommand {
11
11
  constructor() {
12
12
  super(...arguments);
13
+ this.why = clipanion_1.Option.Boolean(`--why`, false, {
14
+ description: `Print the explanation for why a setting has its value`,
15
+ });
13
16
  this.json = clipanion_1.Option.Boolean(`--json`, false, {
14
17
  description: `Format the output as an NDJSON stream`,
15
18
  });
@@ -3,8 +3,10 @@ import { Usage } from 'clipanion';
3
3
  export default class ConfigCommand extends BaseCommand {
4
4
  static paths: string[][];
5
5
  static usage: Usage;
6
- verbose: boolean;
7
- why: boolean;
6
+ noDefaults: boolean;
8
7
  json: boolean;
8
+ verbose: boolean | undefined;
9
+ why: boolean | undefined;
10
+ names: string[];
9
11
  execute(): Promise<0 | 1>;
10
12
  }
@@ -2,31 +2,50 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const cli_1 = require("@yarnpkg/cli");
4
4
  const core_1 = require("@yarnpkg/core");
5
- const core_2 = require("@yarnpkg/core");
5
+ const fslib_1 = require("@yarnpkg/fslib");
6
6
  const clipanion_1 = require("clipanion");
7
7
  const util_1 = require("util");
8
8
  // eslint-disable-next-line arca/no-default-export
9
9
  class ConfigCommand extends cli_1.BaseCommand {
10
10
  constructor() {
11
11
  super(...arguments);
12
- this.verbose = clipanion_1.Option.Boolean(`-v,--verbose`, false, {
13
- description: `Print the setting description on top of the regular key/value information`,
14
- });
15
- this.why = clipanion_1.Option.Boolean(`--why`, false, {
16
- description: `Print the reason why a setting is set a particular way`,
12
+ this.noDefaults = clipanion_1.Option.Boolean(`--no-defaults`, false, {
13
+ description: `Omit the default values from the display`,
17
14
  });
18
15
  this.json = clipanion_1.Option.Boolean(`--json`, false, {
19
16
  description: `Format the output as an NDJSON stream`,
20
17
  });
18
+ // Legacy flags; will emit errors or warnings when used
19
+ this.verbose = clipanion_1.Option.Boolean(`-v,--verbose`, { hidden: true });
20
+ this.why = clipanion_1.Option.Boolean(`--why`, { hidden: true });
21
+ this.names = clipanion_1.Option.Rest();
21
22
  }
22
23
  async execute() {
23
24
  const configuration = await core_1.Configuration.find(this.context.cwd, this.context.plugins, {
24
25
  strict: false,
25
26
  });
27
+ const deprecationExitCode = await (0, core_1.reportOptionDeprecations)({
28
+ configuration,
29
+ stdout: this.context.stdout,
30
+ forceError: this.json,
31
+ }, [{
32
+ option: this.verbose,
33
+ message: `The --verbose option is deprecated, the settings' descriptions are now always displayed`,
34
+ }, {
35
+ option: this.why,
36
+ message: `The --why option is deprecated, the settings' sources are now always displayed`,
37
+ }]);
38
+ if (deprecationExitCode !== null)
39
+ return deprecationExitCode;
40
+ const names = this.names.length > 0
41
+ ? [...new Set(this.names)].sort()
42
+ : [...configuration.settings.keys()].sort();
43
+ let trailingValue;
26
44
  const report = await core_1.StreamReport.start({
27
45
  configuration,
28
46
  json: this.json,
29
47
  stdout: this.context.stdout,
48
+ includeFooter: false,
30
49
  }, async (report) => {
31
50
  if (configuration.invalid.size > 0 && !this.json) {
32
51
  for (const [key, source] of configuration.invalid)
@@ -34,54 +53,92 @@ class ConfigCommand extends cli_1.BaseCommand {
34
53
  report.reportSeparator();
35
54
  }
36
55
  if (this.json) {
37
- const keys = core_2.miscUtils.sortMap(configuration.settings.keys(), key => key);
38
- for (const key of keys) {
39
- const data = configuration.settings.get(key);
40
- const effective = configuration.getSpecial(key, {
56
+ for (const name of names) {
57
+ const data = configuration.settings.get(name);
58
+ if (typeof data === `undefined`)
59
+ report.reportError(core_1.MessageName.INVALID_CONFIGURATION_KEY, `No configuration key named "${name}"`);
60
+ const effective = configuration.getSpecial(name, {
41
61
  hideSecrets: true,
42
62
  getNativePaths: true,
43
63
  });
44
- const source = configuration.sources.get(key);
45
- if (this.verbose) {
46
- report.reportJson({ key, effective, source });
47
- }
48
- else {
49
- report.reportJson({ key, effective, source, ...data });
50
- }
64
+ const source = configuration.sources.get(name) ?? `<default>`;
65
+ const sourceAsNativePath = source && source[0] !== `<`
66
+ ? fslib_1.npath.fromPortablePath(source)
67
+ : source;
68
+ report.reportJson({ key: name, effective, source: sourceAsNativePath, ...data });
51
69
  }
52
70
  }
53
71
  else {
54
- const keys = core_2.miscUtils.sortMap(configuration.settings.keys(), key => key);
55
- const maxKeyLength = keys.reduce((max, key) => Math.max(max, key.length), 0);
56
72
  const inspectConfig = {
57
73
  breakLength: Infinity,
58
74
  colors: configuration.get(`enableColors`),
59
75
  maxArrayLength: 2,
60
76
  };
61
- if (this.why || this.verbose) {
62
- const keysAndDescriptions = keys.map(key => {
63
- const setting = configuration.settings.get(key);
64
- if (!setting)
65
- throw new Error(`Assertion failed: This settings ("${key}") should have been registered`);
66
- const description = this.why
67
- ? configuration.sources.get(key) || `<default>`
68
- : setting.description;
69
- return [key, description];
70
- });
71
- const maxDescriptionLength = keysAndDescriptions.reduce((max, [, description]) => {
72
- return Math.max(max, description.length);
73
- }, 0);
74
- for (const [key, description] of keysAndDescriptions) {
75
- report.reportInfo(null, `${key.padEnd(maxKeyLength, ` `)} ${description.padEnd(maxDescriptionLength, ` `)} ${(0, util_1.inspect)(configuration.getSpecial(key, { hideSecrets: true, getNativePaths: true }), inspectConfig)}`);
77
+ const configTreeChildren = {};
78
+ const configTree = { children: configTreeChildren };
79
+ for (const name of names) {
80
+ if (this.noDefaults && !configuration.sources.has(name))
81
+ continue;
82
+ const setting = configuration.settings.get(name);
83
+ const source = configuration.sources.get(name) ?? `<default>`;
84
+ const value = configuration.getSpecial(name, { hideSecrets: true, getNativePaths: true });
85
+ const fields = {
86
+ Description: {
87
+ label: `Description`,
88
+ value: core_1.formatUtils.tuple(core_1.formatUtils.Type.MARKDOWN, { text: setting.description, format: this.cli.format(), paragraphs: false }),
89
+ },
90
+ Source: {
91
+ label: `Source`,
92
+ value: core_1.formatUtils.tuple(source[0] === `<` ? core_1.formatUtils.Type.CODE : core_1.formatUtils.Type.PATH, source),
93
+ },
94
+ };
95
+ configTreeChildren[name] = {
96
+ value: core_1.formatUtils.tuple(core_1.formatUtils.Type.CODE, name),
97
+ children: fields,
98
+ };
99
+ const setValueTo = (node, value) => {
100
+ for (const [key, subValue] of value) {
101
+ if (subValue instanceof Map) {
102
+ const subFields = {};
103
+ node[key] = { children: subFields };
104
+ setValueTo(subFields, subValue);
105
+ }
106
+ else {
107
+ node[key] = {
108
+ label: key,
109
+ value: core_1.formatUtils.tuple(core_1.formatUtils.Type.NO_HINT, (0, util_1.inspect)(subValue, inspectConfig)),
110
+ };
111
+ }
112
+ }
113
+ };
114
+ if (value instanceof Map) {
115
+ setValueTo(fields, value);
76
116
  }
77
- }
78
- else {
79
- for (const key of keys) {
80
- report.reportInfo(null, `${key.padEnd(maxKeyLength, ` `)} ${(0, util_1.inspect)(configuration.getSpecial(key, { hideSecrets: true, getNativePaths: true }), inspectConfig)}`);
117
+ else {
118
+ fields.Value = {
119
+ label: `Value`,
120
+ value: core_1.formatUtils.tuple(core_1.formatUtils.Type.NO_HINT, (0, util_1.inspect)(value, inspectConfig)),
121
+ };
81
122
  }
82
123
  }
124
+ if (names.length !== 1)
125
+ trailingValue = undefined;
126
+ core_1.treeUtils.emitTree(configTree, {
127
+ configuration,
128
+ json: this.json,
129
+ stdout: this.context.stdout,
130
+ separators: 2,
131
+ });
83
132
  }
84
133
  });
134
+ if (!this.json && typeof trailingValue !== `undefined`) {
135
+ const name = names[0];
136
+ const value = (0, util_1.inspect)(configuration.getSpecial(name, { hideSecrets: true, getNativePaths: true }), {
137
+ colors: configuration.get(`enableColors`),
138
+ });
139
+ this.context.stdout.write(`\n`);
140
+ this.context.stdout.write(`${value}\n`);
141
+ }
85
142
  return report.exitCode();
86
143
  }
87
144
  }
@@ -183,16 +183,12 @@ class InfoCommand extends cli_1.BaseCommand {
183
183
  async (pkg, extra, registerData) => {
184
184
  if (!extra.has(`cache`))
185
185
  return;
186
- const cacheOptions = {
187
- mockedPackages: project.disabledLocators,
188
- unstablePackages: project.conditionalLocators,
189
- };
190
186
  const checksum = project.storedChecksums.get(pkg.locatorHash) ?? null;
191
- const cachePath = cache.getLocatorPath(pkg, checksum, cacheOptions);
187
+ const cachePath = cache.getLocatorPath(pkg, checksum);
192
188
  let stat;
193
189
  if (cachePath !== null) {
194
190
  try {
195
- stat = fslib_1.xfs.statSync(cachePath);
191
+ stat = await fslib_1.xfs.statPromise(cachePath);
196
192
  }
197
193
  catch { }
198
194
  }
@@ -70,109 +70,68 @@ class YarnCommand extends cli_1.BaseCommand {
70
70
  // in process of deploying Google Cloud Functions and
71
71
  // Google App Engine
72
72
  const isGCP = !!process.env.FUNCTION_TARGET || !!process.env.GOOGLE_RUNTIME;
73
- const reportDeprecation = async (message, { error }) => {
74
- const deprecationReport = await core_1.StreamReport.start({
75
- configuration,
76
- stdout: this.context.stdout,
77
- includeFooter: false,
78
- }, async (report) => {
79
- if (error) {
80
- report.reportError(core_1.MessageName.DEPRECATED_CLI_SETTINGS, message);
81
- }
82
- else {
83
- report.reportWarning(core_1.MessageName.DEPRECATED_CLI_SETTINGS, message);
84
- }
85
- });
86
- if (deprecationReport.hasErrors()) {
87
- return deprecationReport.exitCode();
88
- }
89
- else {
90
- return null;
91
- }
92
- };
93
- // The ignoreEngines flag isn't implemented at the moment. I'm still
94
- // considering how it should work in the context of plugins - would it
95
- // make sense to allow them (or direct dependencies) to define new
96
- // "engine check"? Since it has implications regarding the architecture,
97
- // I prefer to postpone the decision to later. Also it wouldn't be a flag,
98
- // it would definitely be a configuration setting.
99
- if (typeof this.ignoreEngines !== `undefined`) {
100
- const exitCode = await reportDeprecation(`The --ignore-engines option is deprecated; engine checking isn't a core feature anymore`, {
73
+ const deprecationExitCode = await (0, core_1.reportOptionDeprecations)({
74
+ configuration,
75
+ stdout: this.context.stdout,
76
+ }, [{
77
+ // The ignoreEngines flag isn't implemented at the moment. I'm still
78
+ // considering how it should work in the context of plugins - would it
79
+ // make sense to allow them (or direct dependencies) to define new
80
+ // "engine check"? Since it has implications regarding the architecture,
81
+ // I prefer to postpone the decision to later. Also it wouldn't be a flag,
82
+ // it would definitely be a configuration setting.
83
+ option: this.ignoreEngines,
84
+ message: `The --ignore-engines option is deprecated; engine checking isn't a core feature anymore`,
101
85
  error: !ci_info_1.default.VERCEL,
102
- });
103
- if (exitCode !== null) {
104
- return exitCode;
105
- }
106
- }
107
- // The registry flag isn't supported anymore because it makes little sense
108
- // to use a registry for a single install. You instead want to configure it
109
- // for all installs inside a project, so through the .yarnrc.yml file. Note
110
- // that if absolutely necessary, the old behavior can be emulated by adding
111
- // the YARN_NPM_REGISTRY_SERVER variable to the environment.
112
- if (typeof this.registry !== `undefined`) {
113
- const exitCode = await reportDeprecation(`The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file`, {
114
- error: false,
115
- });
116
- if (exitCode !== null) {
117
- return exitCode;
118
- }
119
- }
120
- // The preferOffline flag doesn't make much sense with our architecture.
121
- // It would require the fetchers to also act as resolvers, which is
122
- // doable but quirky. Since a similar behavior is available via the
123
- // --cached flag in yarn add, I prefer to move it outside of the core and
124
- // let someone implement this "resolver-that-reads-the-cache" logic.
125
- if (typeof this.preferOffline !== `undefined`) {
126
- const exitCode = await reportDeprecation(`The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead`, {
86
+ }, {
87
+ // The registry flag isn't supported anymore because it makes little sense
88
+ // to use a registry for a single install. You instead want to configure it
89
+ // for all installs inside a project, so through the .yarnrc.yml file. Note
90
+ // that if absolutely necessary, the old behavior can be emulated by adding
91
+ // the YARN_NPM_REGISTRY_SERVER variable to the environment.
92
+ option: this.registry,
93
+ message: `The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file`,
94
+ }, {
95
+ // The preferOffline flag doesn't make much sense with our architecture.
96
+ // It would require the fetchers to also act as resolvers, which is
97
+ // doable but quirky. Since a similar behavior is available via the
98
+ // --cached flag in yarn add, I prefer to move it outside of the core and
99
+ // let someone implement this "resolver-that-reads-the-cache" logic.
100
+ option: this.preferOffline,
101
+ message: `The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead`,
127
102
  error: !ci_info_1.default.VERCEL,
128
- });
129
- if (exitCode !== null) {
130
- return exitCode;
131
- }
132
- }
133
- // Since the production flag would yield a different lockfile than the
134
- // regular installs, it's not part of the regular `install` command anymore.
135
- // Instead, we expect users to use it with `yarn workspaces focus` (which can
136
- // be used even outside of monorepos).
137
- if (typeof this.production !== `undefined`) {
138
- const exitCode = await reportDeprecation(`The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead`, {
103
+ }, {
104
+ // Since the production flag would yield a different lockfile than the
105
+ // regular installs, it's not part of the regular `install` command anymore.
106
+ // Instead, we expect users to use it with `yarn workspaces focus` (which can
107
+ // be used even outside of monorepos).
108
+ option: this.production,
109
+ message: `The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead`,
139
110
  error: true,
140
- });
141
- if (exitCode !== null) {
142
- return exitCode;
143
- }
144
- }
145
- // Yarn 2 isn't interactive during installs anyway, so there's no real point
146
- // to this flag at the moment.
147
- if (typeof this.nonInteractive !== `undefined`) {
148
- const exitCode = await reportDeprecation(`The --non-interactive option is deprecated`, {
111
+ }, {
112
+ // Yarn 2+ isn't interactive during installs anyway, so there's no real point
113
+ // to this flag at the moment.
114
+ option: this.nonInteractive,
115
+ message: `The --non-interactive option is deprecated`,
149
116
  error: !isGCP,
150
- });
151
- if (exitCode !== null) {
152
- return exitCode;
153
- }
154
- }
155
- // We want to prevent people from using --frozen-lockfile
156
- // Note: it's been deprecated because we're now locking more than just the
157
- // lockfile - for example the PnP artifacts will also be locked.
158
- if (typeof this.frozenLockfile !== `undefined`) {
159
- await reportDeprecation(`The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead`, {
160
- error: false,
161
- });
162
- this.immutable = this.frozenLockfile;
163
- }
164
- // We also want to prevent them from using --cache-folder
165
- // Note: it's been deprecated because the cache folder should be set from
166
- // the settings. Otherwise there would be a very high chance that multiple
167
- // Yarn commands would use different caches, causing unexpected behaviors.
168
- if (typeof this.cacheFolder !== `undefined`) {
169
- const exitCode = await reportDeprecation(`The cache-folder option has been deprecated; use rc settings instead`, {
117
+ }, {
118
+ // We want to prevent people from using --frozen-lockfile
119
+ // Note: it's been deprecated because we're now locking more than just the
120
+ // lockfile - for example the PnP artifacts will also be locked.
121
+ option: this.frozenLockfile,
122
+ message: `The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead`,
123
+ callback: () => this.immutable = this.frozenLockfile,
124
+ }, {
125
+ // We also want to prevent them from using --cache-folder
126
+ // Note: it's been deprecated because the cache folder should be set from
127
+ // the settings. Otherwise there would be a very high chance that multiple
128
+ // Yarn commands would use different caches, causing unexpected behaviors.
129
+ option: this.cacheFolder,
130
+ message: `The cache-folder option has been deprecated; use rc settings instead`,
170
131
  error: !ci_info_1.default.NETLIFY,
171
- });
172
- if (exitCode !== null) {
173
- return exitCode;
174
- }
175
- }
132
+ }]);
133
+ if (deprecationExitCode !== null)
134
+ return deprecationExitCode;
176
135
  const updateMode = this.mode === core_1.InstallMode.UpdateLockfile;
177
136
  if (updateMode && (this.immutable || this.immutableCache))
178
137
  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)}`);
@@ -269,6 +269,8 @@ async function getSuggestedDescriptors(request, { project, workspace, cache, tar
269
269
  break;
270
270
  case Strategy.LATEST:
271
271
  {
272
+ const hasNetwork = project.configuration.get(`enableNetwork`);
273
+ const isOfflineMode = project.configuration.get(`enableOfflineMode`);
272
274
  await trySuggest(async () => {
273
275
  if (target === Target.PEER) {
274
276
  suggested.push({
@@ -277,7 +279,7 @@ async function getSuggestedDescriptors(request, { project, workspace, cache, tar
277
279
  reason: `(catch-all peer dependency pattern)`,
278
280
  });
279
281
  }
280
- else if (!project.configuration.get(`enableNetwork`)) {
282
+ else if (!hasNetwork && !isOfflineMode) {
281
283
  suggested.push({
282
284
  descriptor: null,
283
285
  name: `Resolve from latest`,
@@ -290,7 +292,7 @@ async function getSuggestedDescriptors(request, { project, workspace, cache, tar
290
292
  suggested.push({
291
293
  descriptor: latest,
292
294
  name: `Use ${core_2.structUtils.prettyDescriptor(project.configuration, latest)}`,
293
- reason: `(resolved from latest)`,
295
+ reason: `(resolved from ${isOfflineMode ? `the cache` : `latest`})`,
294
296
  });
295
297
  }
296
298
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yarnpkg/plugin-essentials",
3
- "version": "4.0.0-rc.50",
3
+ "version": "4.0.0-rc.52",
4
4
  "stableVersion": "3.3.0",
5
5
  "license": "BSD-2-Clause",
6
6
  "main": "./lib/index.js",
@@ -9,8 +9,8 @@
9
9
  "./package.json": "./package.json"
10
10
  },
11
11
  "dependencies": {
12
- "@yarnpkg/fslib": "^3.0.0-rc.50",
13
- "@yarnpkg/parsers": "^3.0.0-rc.50",
12
+ "@yarnpkg/fslib": "^3.0.0-rc.52",
13
+ "@yarnpkg/parsers": "^3.0.0-rc.52",
14
14
  "ci-info": "^3.2.0",
15
15
  "clipanion": "^4.0.0-rc.2",
16
16
  "enquirer": "^2.3.6",
@@ -21,17 +21,17 @@
21
21
  "typanion": "^3.14.0"
22
22
  },
23
23
  "peerDependencies": {
24
- "@yarnpkg/cli": "^4.0.0-rc.50",
25
- "@yarnpkg/core": "^4.0.0-rc.50",
26
- "@yarnpkg/plugin-git": "^3.0.0-rc.50"
24
+ "@yarnpkg/cli": "^4.0.0-rc.52",
25
+ "@yarnpkg/core": "^4.0.0-rc.52",
26
+ "@yarnpkg/plugin-git": "^3.0.0-rc.52"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/lodash": "^4.14.136",
30
30
  "@types/micromatch": "^4.0.1",
31
31
  "@types/semver": "^7.1.0",
32
- "@yarnpkg/cli": "^4.0.0-rc.50",
33
- "@yarnpkg/core": "^4.0.0-rc.50",
34
- "@yarnpkg/plugin-git": "^3.0.0-rc.50"
32
+ "@yarnpkg/cli": "^4.0.0-rc.52",
33
+ "@yarnpkg/core": "^4.0.0-rc.52",
34
+ "@yarnpkg/plugin-git": "^3.0.0-rc.52"
35
35
  },
36
36
  "repository": {
37
37
  "type": "git",