fix(@angular/cli): correctly handle yarn classic tag manifest fetching · angular/angular-cli@d8b76e9
@@ -269,12 +269,12 @@ export function parseNpmLikeMetadata(stdout: string, logger?: Logger): PackageMe
269269}
270270271271/**
272- * Parses the output of `yarn info` (classic).
272+ * Parses the output of `yarn info` (classic) to get a package manifest.
273273 * @param stdout The standard output of the command.
274274 * @param logger An optional logger instance.
275275 * @returns The package manifest object.
276276 */
277-export function parseYarnLegacyManifest(stdout: string, logger?: Logger): PackageManifest | null {
277+export function parseYarnClassicManifest(stdout: string, logger?: Logger): PackageManifest | null {
278278logger?.debug(`Parsing yarn classic manifest...`);
279279logStdout(stdout, logger);
280280@@ -287,5 +287,43 @@ export function parseYarnLegacyManifest(stdout: string, logger?: Logger): Packag
287287const data = JSON.parse(stdout);
288288289289// Yarn classic wraps the manifest in a `data` property.
290-return data.data ?? data;
290+const manifest = data.data as PackageManifest;
291+292+// Yarn classic removes any field with a falsy value
293+// https://github.com/yarnpkg/yarn/blob/7cafa512a777048ce0b666080a24e80aae3d66a9/src/cli/commands/info.js#L26-L29
294+// Add a default of 'false' for the `save` field when the `ng-add` object is present but does not have any fields.
295+// There is a small chance this causes an incorrect value. However, the use of `ng-add` is rare and, in the cases
296+// it is used, save is set to either a `false` literal or a truthy value. Special cases can be added for specific
297+// packages if discovered.
298+if (
299+manifest['ng-add'] &&
300+typeof manifest['ng-add'] === 'object' &&
301+Object.keys(manifest['ng-add']).length === 0
302+) {
303+manifest['ng-add'].save ??= false;
304+}
305+306+return manifest;
307+}
308+309+/**
310+ * Parses the output of `yarn info` (classic) to get package metadata.
311+ * @param stdout The standard output of the command.
312+ * @param logger An optional logger instance.
313+ * @returns The package metadata object.
314+ */
315+export function parseYarnClassicMetadata(stdout: string, logger?: Logger): PackageMetadata | null {
316+logger?.debug(`Parsing yarn classic metadata...`);
317+logStdout(stdout, logger);
318+319+if (!stdout) {
320+logger?.debug(' stdout is empty. No metadata found.');
321+322+return null;
323+}
324+325+const data = JSON.parse(stdout);
326+327+// Yarn classic wraps the metadata in a `data` property.
328+return data.data;
291329}