Skip to content

Commit 7932caa

Browse files
committed
fix(@angular/cli): robustly parse npm manifest from array
Update `parseNpmLikeManifest` to find the manifest with the highest version instead of assuming the last item in the array is the correct one. This makes the parsing robust against out-of-order results from `npm view` or similar commands without incurring performance penalties. This change ensures that the latest relevant version is always selected when a range is queried and multiple versions are returned, improving reliability in edge cases where registry output might not be sorted.
1 parent 93b5206 commit 7932caa

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

packages/angular/cli/src/package-managers/parsers.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ErrorInfo } from './error';
1616
import { Logger } from './logger';
1717
import { PackageManifest, PackageMetadata } from './package-metadata';
1818
import { InstalledPackage } from './package-tree';
19+
import { compare } from 'semver';
1920

2021
const MAX_LOG_LENGTH = 1024;
2122

@@ -234,7 +235,26 @@ export function parseNpmLikeManifest(stdout: string, logger?: Logger): PackageMa
234235

235236
const result = JSON.parse(stdout);
236237

237-
return Array.isArray(result) ? result[result.length - 1] : result;
238+
// npm view returns an array of manifests if the query matches multiple versions
239+
// (e.g. when using a version range). We find the highest version to ensure
240+
// we get the latest relevant manifest, even if the output is not sorted.
241+
if (Array.isArray(result)) {
242+
let maxManifest: PackageManifest | null = null;
243+
244+
for (const manifest of result) {
245+
if (!manifest || typeof manifest.version !== 'string') {
246+
continue;
247+
}
248+
249+
if (!maxManifest || compare(manifest.version, maxManifest.version) > 0) {
250+
maxManifest = manifest;
251+
}
252+
}
253+
254+
return maxManifest;
255+
}
256+
257+
return result;
238258
}
239259

240260
/**

packages/angular/cli/src/package-managers/parsers_spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ describe('parsers', () => {
136136
expect(parseNpmLikeManifest(stdout)).toEqual({ name: 'foo', version: '1.1.0' });
137137
});
138138

139+
it('should return the highest version manifest from an unsorted array', () => {
140+
const stdout = JSON.stringify([
141+
{ name: 'foo', version: '1.1.0' },
142+
{ name: 'foo', version: '1.0.0' },
143+
]);
144+
expect(parseNpmLikeManifest(stdout)).toEqual({ name: 'foo', version: '1.1.0' });
145+
});
146+
139147
it('should return null for empty stdout', () => {
140148
expect(parseNpmLikeManifest('')).toBeNull();
141149
});

0 commit comments

Comments
 (0)