Skip to content

Commit 797c652

Browse files
committed
refactor(@angular/cli): clean up package-metadata retrieval logic
With this change we clean up the package-metadata retrieval logic and types by using public `@types/` packages. Also, we lazily require `pacote` since this has a large set to dependencies which slows down module resolution.
1 parent 80d486f commit 797c652

File tree

11 files changed

+140
-391
lines changed

11 files changed

+140
-391
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
"@types/express": "^4.16.0",
100100
"@types/glob": "^7.1.1",
101101
"@types/http-proxy": "^1.17.4",
102+
"@types/ini": "^1.3.31",
102103
"@types/inquirer": "^8.0.0",
103104
"@types/jasmine": "~4.0.0",
104105
"@types/karma": "^6.3.0",
@@ -107,6 +108,7 @@
107108
"@types/node": "^14.15.0",
108109
"@types/node-fetch": "^2.1.6",
109110
"@types/npm-package-arg": "^6.1.0",
111+
"@types/pacote": "^11.1.3",
110112
"@types/parse5-html-rewriting-stream": "^5.1.2",
111113
"@types/pidusage": "^2.0.1",
112114
"@types/postcss-preset-env": "^6.7.1",
@@ -117,6 +119,7 @@
117119
"@types/uuid": "^8.0.0",
118120
"@types/yargs": "^17.0.8",
119121
"@types/yargs-parser": "^21.0.0",
122+
"@types/yarnpkg__lockfile": "^1.1.5",
120123
"@typescript-eslint/eslint-plugin": "5.16.0",
121124
"@typescript-eslint/parser": "5.16.0",
122125
"@yarnpkg/lockfile": "1.1.0",

packages/angular/cli/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,16 @@ ts_library(
5555
"//packages/angular_devkit/schematics/tools",
5656
"@npm//@angular/core",
5757
"@npm//@types/debug",
58+
"@npm//@types/ini",
5859
"@npm//@types/inquirer",
5960
"@npm//@types/node",
6061
"@npm//@types/npm-package-arg",
62+
"@npm//@types/pacote",
6163
"@npm//@types/resolve",
6264
"@npm//@types/semver",
6365
"@npm//@types/uuid",
6466
"@npm//@types/yargs",
67+
"@npm//@types/yarnpkg__lockfile",
6568
"@npm//@yarnpkg/lockfile",
6669
"@npm//ansi-colors",
6770
"@npm//ini",

packages/angular/cli/src/commands/add/cli.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { colors } from '../../utilities/color';
2727
import { installPackage, installTempPackage } from '../../utilities/install-package';
2828
import { ensureCompatibleNpm } from '../../utilities/package-manager';
2929
import {
30-
NgAddSaveDepedency,
30+
NgAddSaveDependency,
3131
PackageManifest,
3232
fetchPackageManifest,
3333
fetchPackageMetadata,
@@ -165,7 +165,10 @@ export class AddCommandModule
165165
}
166166

167167
// Adjust the version based on name and peer dependencies
168-
if (latestManifest && Object.keys(latestManifest.peerDependencies).length === 0) {
168+
if (
169+
latestManifest?.peerDependencies &&
170+
Object.keys(latestManifest.peerDependencies).length === 0
171+
) {
169172
spinner.succeed(
170173
`Found compatible package version: ${colors.grey(packageIdentifier.toString())}.`,
171174
);
@@ -217,7 +220,7 @@ export class AddCommandModule
217220
}
218221

219222
let collectionName = packageIdentifier.name;
220-
let savePackage: NgAddSaveDepedency | undefined;
223+
let savePackage: NgAddSaveDependency | undefined;
221224

222225
try {
223226
spinner.start('Loading package information from registry...');
@@ -415,7 +418,8 @@ export class AddCommandModule
415418
} catch {}
416419

417420
if (projectManifest) {
418-
const version = projectManifest.dependencies[name] || projectManifest.devDependencies[name];
421+
const version =
422+
projectManifest.dependencies?.[name] || projectManifest.devDependencies?.[name];
419423
if (version) {
420424
return version;
421425
}

packages/angular/cli/src/commands/update/schematic/index.ts

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,19 @@
99
import { logging, tags } from '@angular-devkit/core';
1010
import { Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics';
1111
import * as npa from 'npm-package-arg';
12+
import type { Manifest } from 'pacote';
1213
import * as semver from 'semver';
13-
import { Dependency, JsonSchemaForNpmPackageJsonFiles } from '../../../utilities/package-json';
14-
import { NpmRepositoryPackageJson, getNpmPackageJson } from '../../../utilities/package-metadata';
14+
import {
15+
NgPackageManifestProperties,
16+
NpmRepositoryPackageJson,
17+
getNpmPackageJson,
18+
} from '../../../utilities/package-metadata';
1519
import { Schema as UpdateSchema } from './schema';
1620

21+
interface JsonSchemaForNpmPackageJsonFiles extends Manifest, NgPackageManifestProperties {
22+
peerDependenciesMeta?: Record<string, { optional?: boolean }>;
23+
}
24+
1725
type VersionRange = string & { __VERSION_RANGE: void };
1826
type PeerVersionTransform = string | ((range: string) => string);
1927

@@ -264,7 +272,7 @@ function _performUpdate(
264272
throw new SchematicsException('package.json could not be parsed: ' + e.message);
265273
}
266274

267-
const updateDependency = (deps: Dependency, name: string, newVersion: string) => {
275+
const updateDependency = (deps: Record<string, string>, name: string, newVersion: string) => {
268276
const oldVersion = deps[name];
269277
// We only respect caret and tilde ranges on update.
270278
const execResult = /^[\^~]/.exec(oldVersion);
@@ -367,6 +375,7 @@ function _getUpdateMetadata(
367375
} else if (
368376
typeof packageGroup == 'object' &&
369377
packageGroup &&
378+
!Array.isArray(packageGroup) &&
370379
Object.values(packageGroup).every((x) => typeof x == 'string')
371380
) {
372381
result.packageGroup = packageGroup;
@@ -463,15 +472,19 @@ function _usageMessage(
463472
)
464473
.map(({ name, info, version, tag, target }) => {
465474
// Look for packageGroup.
466-
const packageGroup = target['ng-update']['packageGroup'];
475+
const packageGroup = target['ng-update']?.['packageGroup'];
467476
if (packageGroup) {
468-
const packageGroupName = target['ng-update']['packageGroupName'] || packageGroup[0];
477+
const packageGroupNames = Array.isArray(packageGroup)
478+
? packageGroup
479+
: Object.keys(packageGroup);
480+
481+
const packageGroupName = target['ng-update']?.['packageGroupName'] || packageGroupNames[0];
469482
if (packageGroupName) {
470483
if (packageGroups.has(name)) {
471484
return null;
472485
}
473486

474-
packageGroup.forEach((x: string) => packageGroups.set(x, packageGroupName));
487+
packageGroupNames.forEach((x: string) => packageGroups.set(x, packageGroupName));
475488
packageGroups.set(packageGroupName, packageGroupName);
476489
name = packageGroupName;
477490
}
@@ -663,35 +676,37 @@ function _addPackageGroup(
663676
return;
664677
}
665678

666-
let packageGroup = ngUpdateMetadata['packageGroup'];
679+
const packageGroup = ngUpdateMetadata['packageGroup'];
667680
if (!packageGroup) {
668681
return;
669682
}
683+
let packageGroupNormalized: Record<string, string> = {};
670684
if (Array.isArray(packageGroup) && !packageGroup.some((x) => typeof x != 'string')) {
671-
packageGroup = packageGroup.reduce((acc, curr) => {
685+
packageGroupNormalized = packageGroup.reduce((acc, curr) => {
672686
acc[curr] = maybePackage;
673687

674688
return acc;
675689
}, {} as { [name: string]: string });
676-
}
677-
678-
// Only need to check if it's an object because we set it right the time before.
679-
if (
680-
typeof packageGroup != 'object' ||
681-
packageGroup === null ||
682-
Object.values(packageGroup).some((v) => typeof v != 'string')
690+
} else if (
691+
typeof packageGroup == 'object' &&
692+
packageGroup &&
693+
!Array.isArray(packageGroup) &&
694+
Object.values(packageGroup).every((x) => typeof x == 'string')
683695
) {
684-
logger.warn(`packageGroup metadata of package ${npmPackageJson.name} is malformed.`);
696+
packageGroupNormalized = packageGroup;
697+
} else {
698+
logger.warn(`packageGroup metadata of package ${npmPackageJson.name} is malformed. Ignoring.`);
685699

686700
return;
687701
}
688702

689-
Object.keys(packageGroup)
690-
.filter((name) => !packages.has(name)) // Don't override names from the command line.
691-
.filter((name) => allDependencies.has(name)) // Remove packages that aren't installed.
692-
.forEach((name) => {
693-
packages.set(name, packageGroup[name]);
694-
});
703+
for (const [name, value] of Object.entries(packageGroupNormalized)) {
704+
// Don't override names from the command line.
705+
// Remove packages that aren't installed.
706+
if (!packages.has(name) && allDependencies.has(name)) {
707+
packages.set(name, value as VersionRange);
708+
}
709+
}
695710
}
696711

697712
/**
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/* eslint-disable import/no-extraneous-dependencies */
10+
// Workaround for https://github.com/bazelbuild/rules_nodejs/issues/1033
11+
// Alternative approach instead of https://github.com/angular/angular/pull/33226
12+
declare module '@yarnpkg/lockfile' {
13+
export * from '@types/yarnpkg__lockfile';
14+
}

packages/angular/cli/src/typings.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,10 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
declare module '@yarnpkg/lockfile' {
10-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
11-
export function parse(data: string): Record<string, any>;
12-
}
13-
14-
declare module 'ini' {
15-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
16-
export function parse(data: string): Record<string, any>;
17-
}
18-
199
declare module 'npm-pick-manifest' {
2010
function pickManifest(
2111
metadata: import('./utilities/package-metadata').PackageMetadata,
2212
selector: string,
2313
): import('./utilities/package-metadata').PackageManifest;
2414
export = pickManifest;
2515
}
26-
27-
declare module 'pacote' {
28-
export function manifest(
29-
specifier: string,
30-
options: Record<string, unknown>,
31-
): Promise<{ name: string; version: string }>;
32-
33-
export function packument(
34-
specifier: string,
35-
options: Record<string, unknown>,
36-
): Promise<import('./utilities/package-metadata').NpmRepositoryPackageJson>;
37-
}

packages/angular/cli/src/utilities/install-package.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { existsSync, mkdtempSync, readFileSync, realpathSync, rmdirSync, writeFi
1111
import { tmpdir } from 'os';
1212
import { join, resolve } from 'path';
1313
import { PackageManager } from '../../lib/config/workspace-schema';
14-
import { NgAddSaveDepedency } from './package-metadata';
14+
import { NgAddSaveDependency } from './package-metadata';
1515
import { Spinner } from './spinner';
1616

1717
interface PackageManagerOptions {
@@ -70,7 +70,7 @@ export async function installAllPackages(
7070
export async function installPackage(
7171
packageName: string,
7272
packageManager: PackageManager = PackageManager.Npm,
73-
save: Exclude<NgAddSaveDepedency, false> = true,
73+
save: Exclude<NgAddSaveDependency, false> = true,
7474
extraArgs: string[] = [],
7575
cwd = process.cwd(),
7676
): Promise<1 | 0> {

0 commit comments

Comments
 (0)