Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(@angular/cli): exclude packages from ng add that contain invalid peer dependencies #22022

Merged
merged 1 commit into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 37 additions & 6 deletions packages/angular/cli/commands/add-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ import { Spinner } from '../utilities/spinner';
import { isTTY } from '../utilities/tty';
import { Schema as AddCommandSchema } from './add';

/**
* The set of packages that should have certain versions excluded from consideration
* when attempting to find a compatible version for a package.
* The key is a package name and the value is a SemVer range of versions to exclude.
*/
const packageVersionExclusions: Record<string, string | undefined> = {
// @angular/localize@9.x versions do not have peer dependencies setup
'@angular/localize': '9.x',
};

export class AddCommand extends SchematicCommand<AddCommandSchema> {
override readonly allowPrivateSchematics = true;

Expand All @@ -40,6 +50,7 @@ export class AddCommand extends SchematicCommand<AddCommandSchema> {
}
}

// eslint-disable-next-line max-lines-per-function
async run(options: AddCommandSchema & Arguments) {
await ensureCompatibleNpm(this.context.root);

Expand Down Expand Up @@ -100,7 +111,13 @@ export class AddCommand extends SchematicCommand<AddCommandSchema> {
return 1;
}

// Start with the version tagged as `latest` if it exists
const latestManifest = packageMetadata.tags['latest'];
if (latestManifest) {
packageIdentifier = npa.resolve(latestManifest.name, latestManifest.version);
}

// Adjust the version based on name and peer dependencies
if (latestManifest && Object.keys(latestManifest.peerDependencies).length === 0) {
if (latestManifest.name === '@angular/pwa') {
const version = await this.findProjectVersion('@angular/cli');
Expand All @@ -113,38 +130,52 @@ export class AddCommand extends SchematicCommand<AddCommandSchema> {
) {
packageIdentifier = npa.resolve('@angular/pwa', '0.12');
}
} else {
packageIdentifier = npa.resolve(latestManifest.name, latestManifest.version);
}

spinner.succeed(
`Found compatible package version: ${colors.grey(packageIdentifier.toString())}.`,
);
} else if (!latestManifest || (await this.hasMismatchedPeer(latestManifest))) {
// 'latest' is invalid so search for most recent matching package
const versionExclusions = packageVersionExclusions[packageMetadata.name];
const versionManifests = Object.values(packageMetadata.versions).filter(
(value: PackageManifest) => !prerelease(value.version) && !value.deprecated,
(value: PackageManifest) => {
// Prerelease versions are not stable and should not be considered by default
if (prerelease(value.version)) {
return false;
}
// Deprecated versions should not be used or considered
if (value.deprecated) {
return false;
}
// Excluded package versions should not be considered
if (versionExclusions && satisfies(value.version, versionExclusions)) {
return false;
}

return true;
},
);

versionManifests.sort((a, b) => rcompare(a.version, b.version, true));

let newIdentifier;
for (const versionManifest of versionManifests) {
if (!(await this.hasMismatchedPeer(versionManifest))) {
newIdentifier = npa.resolve(packageIdentifier.name, versionManifest.version);
newIdentifier = npa.resolve(versionManifest.name, versionManifest.version);
break;
}
}

if (!newIdentifier) {
spinner.warn("Unable to find compatible package. Using 'latest'.");
spinner.warn("Unable to find compatible package. Using 'latest' tag.");
} else {
packageIdentifier = newIdentifier;
spinner.succeed(
`Found compatible package version: ${colors.grey(packageIdentifier.toString())}.`,
);
}
} else {
packageIdentifier = npa.resolve(latestManifest.name, latestManifest.version);
spinner.succeed(
`Found compatible package version: ${colors.grey(packageIdentifier.toString())}.`,
);
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/cli/utilities/spinner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class Spinner {
}

warn(text?: string): void {
this.spinner.fail(text && colors.yellowBright(text));
this.spinner.warn(text && colors.yellowBright(text));
}

stop(): void {
Expand Down