Skip to content

Commit

Permalink
fix(@angular/cli): exclude packages from ng add that contain invalid …
Browse files Browse the repository at this point in the history
…peer dependencies

Certain older versions of packages may contain missing or invalid peer dependencies. As a result these packages may be incorrectly added to the project when no newer compatible version is found. An exclusion list is now present within `ng add` that will exclude packages with known peer dependency concerns from consideration when adding a package. Currently, only `@angular/localize@9.x` is included in the list.

(cherry picked from commit 084eff6)
  • Loading branch information
clydin authored and filipesilva committed Oct 27, 2021
1 parent 17c029a commit e4bc35e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
43 changes: 37 additions & 6 deletions packages/angular/cli/commands/add-impl.ts
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
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

0 comments on commit e4bc35e

Please sign in to comment.