Skip to content

Commit d182376

Browse files
clydinvikerman
authored andcommitted
refactor(@angular/cli): use canonical npm logic to determine update package version
1 parent a3e82ae commit d182376

File tree

5 files changed

+55
-29
lines changed

5 files changed

+55
-29
lines changed

packages/angular/cli/commands/add-impl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export class AddCommand extends SchematicCommand<AddCommandSchema> {
9090
}
9191
} else if (!latestManifest || (await this.hasMismatchedPeer(latestManifest))) {
9292
// 'latest' is invalid so search for most recent matching package
93-
const versionManifests = Array.from(packageMetadata.versions.values()).filter(
93+
const versionManifests = Object.values(packageMetadata.versions).filter(
9494
value => !prerelease(value.version),
9595
);
9696

packages/angular/cli/commands/update-impl.ts

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import { execSync } from 'child_process';
99
import * as fs from 'fs';
1010
import * as path from 'path';
11-
import * as semver from 'semver';
1211
import { Arguments, Option } from '../models/interface';
1312
import { SchematicCommand } from '../models/schematic-command';
1413
import { getPackageManager } from '../utilities/package-manager';
@@ -21,7 +20,11 @@ import {
2120
import { PackageTreeNode, findNodeDependencies, readPackageTree } from '../utilities/package-tree';
2221
import { Schema as UpdateCommandSchema } from './update';
2322

24-
const npa = require('npm-package-arg');
23+
const npa = require('npm-package-arg') as (selector: string) => PackageIdentifier;
24+
const pickManifest = require('npm-pick-manifest') as (
25+
metadata: PackageMetadata,
26+
selector: string,
27+
) => PackageManifest;
2528

2629
const oldConfigFileNames = ['.angular-cli.json', 'angular-cli.json'];
2730

@@ -37,7 +40,7 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
3740
const packages: PackageIdentifier[] = [];
3841
for (const request of options['--'] || []) {
3942
try {
40-
const packageIdentifier: PackageIdentifier = npa(request);
43+
const packageIdentifier = npa(request);
4144

4245
// only registry identifiers are supported
4346
if (!packageIdentifier.registry) {
@@ -245,7 +248,7 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
245248

246249
const requests: {
247250
identifier: PackageIdentifier;
248-
node: PackageTreeNode | string;
251+
node: PackageTreeNode;
249252
}[] = [];
250253

251254
// Validate packages actually are part of the workspace
@@ -258,11 +261,7 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
258261
}
259262

260263
// If a specific version is requested and matches the installed version, skip.
261-
if (
262-
pkg.type === 'version' &&
263-
typeof node === 'object' &&
264-
node.package.version === pkg.fetchSpec
265-
) {
264+
if (pkg.type === 'version' && node.package.version === pkg.fetchSpec) {
266265
this.logger.info(`Package '${pkg.name}' is already at '${pkg.fetchSpec}'.`);
267266
continue;
268267
}
@@ -294,18 +293,34 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
294293
// Try to find a package version based on the user requested package specifier
295294
// registry specifier types are either version, range, or tag
296295
let manifest: PackageManifest | undefined;
297-
if (requestIdentifier.type === 'version') {
298-
manifest = metadata.versions.get(requestIdentifier.fetchSpec);
299-
} else if (requestIdentifier.type === 'range') {
300-
const maxVersion = semver.maxSatisfying(
301-
Array.from(metadata.versions.keys()),
302-
requestIdentifier.fetchSpec,
303-
);
304-
if (maxVersion) {
305-
manifest = metadata.versions.get(maxVersion);
296+
if (
297+
requestIdentifier.type === 'version' ||
298+
requestIdentifier.type === 'range' ||
299+
requestIdentifier.type === 'tag'
300+
) {
301+
try {
302+
manifest = pickManifest(metadata, requestIdentifier.fetchSpec);
303+
} catch (e) {
304+
if (e.code === 'ETARGET') {
305+
// If not found and next was used and user did not provide a specifier, try latest.
306+
// Package may not have a next tag.
307+
if (
308+
requestIdentifier.type === 'tag' &&
309+
requestIdentifier.fetchSpec === 'next' &&
310+
!requestIdentifier.rawSpec
311+
) {
312+
try {
313+
manifest = pickManifest(metadata, 'latest');
314+
} catch (e) {
315+
if (e.code !== 'ETARGET' && e.code !== 'ENOVERSIONS') {
316+
throw e;
317+
}
318+
}
319+
}
320+
} else if (e.code !== 'ENOVERSIONS') {
321+
throw e;
322+
}
306323
}
307-
} else if (requestIdentifier.type === 'tag') {
308-
manifest = metadata.tags[requestIdentifier.fetchSpec];
309324
}
310325

311326
if (!manifest) {
@@ -316,10 +331,7 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
316331
return 1;
317332
}
318333

319-
if (
320-
(typeof node === 'string' && manifest.version === node) ||
321-
(typeof node === 'object' && manifest.version === node.package.version)
322-
) {
334+
if (manifest.version === node.package.version) {
323335
this.logger.info(`Package '${packageName}' is already up to date.`);
324336
continue;
325337
}

packages/angular/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"ini": "1.3.5",
3737
"inquirer": "6.5.1",
3838
"npm-package-arg": "6.1.0",
39+
"npm-pick-manifest": "3.0.2",
3940
"open": "6.4.0",
4041
"pacote": "9.5.5",
4142
"read-package-tree": "5.3.1",

packages/angular/cli/utilities/package-metadata.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export interface PackageManifest {
5050
export interface PackageMetadata {
5151
name: string;
5252
tags: { [tag: string]: PackageManifest | undefined };
53-
versions: Map<string, PackageManifest>;
53+
versions: Record<string, PackageManifest>;
5454
}
5555

5656
let npmrc: { [key: string]: string };
@@ -179,18 +179,22 @@ export async function fetchPackageMetadata(
179179
const metadata: PackageMetadata = {
180180
name: response.name,
181181
tags: {},
182-
versions: new Map(),
182+
versions: {},
183183
};
184184

185185
if (response.versions) {
186186
for (const [version, manifest] of Object.entries(response.versions)) {
187-
metadata.versions.set(version, normalizeManifest(manifest as {}));
187+
metadata.versions[version] = normalizeManifest(manifest as {});
188188
}
189189
}
190190

191191
if (response['dist-tags']) {
192+
// Store this for use with other npm utility packages
193+
// tslint:disable-next-line: no-any
194+
(metadata as any)['dist-tags'] = response['dist-tags'];
195+
192196
for (const [tag, version] of Object.entries(response['dist-tags'])) {
193-
const manifest = metadata.versions.get(version as string);
197+
const manifest = metadata.versions[version as string];
194198
if (manifest) {
195199
metadata.tags[tag] = manifest;
196200
} else if (verbose) {

yarn.lock

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8092,6 +8092,15 @@ npm-packlist@^1.1.6:
80928092
ignore-walk "^3.0.1"
80938093
npm-bundled "^1.0.1"
80948094

8095+
8096+
version "3.0.2"
8097+
resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7"
8098+
integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==
8099+
dependencies:
8100+
figgy-pudding "^3.5.1"
8101+
npm-package-arg "^6.0.0"
8102+
semver "^5.4.1"
8103+
80958104
npm-pick-manifest@^2.2.3:
80968105
version "2.2.3"
80978106
resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40"

0 commit comments

Comments
 (0)