Skip to content

Commit f75d864

Browse files
committed
refactor(@angular/cli): add validation and logging to npm manifest parsing
Introduce a reusable `isValidManifest` type guard to ensure that parsed manifests contain both `name` and `version` strings. This applies to both single object responses and elements within an array response from the package manager.
1 parent 5c1db4e commit f75d864

2 files changed

Lines changed: 45 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
@@ -217,6 +217,15 @@ export function parseYarnClassicDependencies(
217217
return dependencies;
218218
}
219219

220+
function isValidManifest(obj: unknown): obj is PackageManifest {
221+
return (
222+
typeof obj === 'object' &&
223+
obj !== null &&
224+
typeof (obj as Record<string, unknown>).name === 'string' &&
225+
typeof (obj as Record<string, unknown>).version === 'string'
226+
);
227+
}
228+
220229
/**
221230
* Parses the output of `npm view` or a compatible command to get a package manifest.
222231
* @param stdout The standard output of the command.
@@ -242,7 +251,8 @@ export function parseNpmLikeManifest(stdout: string, logger?: Logger): PackageMa
242251
let maxManifest: PackageManifest | null = null;
243252

244253
for (const manifest of result) {
245-
if (!manifest || typeof manifest.version !== 'string') {
254+
if (!isValidManifest(manifest)) {
255+
logger?.debug(' Skipping invalid manifest in array (missing name or version).');
246256
continue;
247257
}
248258

@@ -251,9 +261,19 @@ export function parseNpmLikeManifest(stdout: string, logger?: Logger): PackageMa
251261
}
252262
}
253263

264+
if (!maxManifest) {
265+
logger?.debug(' No valid manifests found in the array.');
266+
}
267+
254268
return maxManifest;
255269
}
256270

271+
if (!isValidManifest(result)) {
272+
logger?.debug(' Parsed JSON is not a valid manifest (missing name or version).');
273+
274+
return null;
275+
}
276+
257277
return result;
258278
}
259279

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,30 @@ describe('parsers', () => {
144144
expect(parseNpmLikeManifest(stdout)).toEqual({ name: 'foo', version: '1.1.0' });
145145
});
146146

147+
it('should skip invalid manifests in an array', () => {
148+
const stdout = JSON.stringify([
149+
{ name: 'foo', version: '1.0.0' },
150+
{ name: 'foo' }, // Missing version
151+
{ version: '1.2.0' }, // Missing name
152+
null,
153+
"invalid",
154+
]);
155+
expect(parseNpmLikeManifest(stdout)).toEqual({ name: 'foo', version: '1.0.0' });
156+
});
157+
158+
it('should return null if no valid manifests found in the array', () => {
159+
const stdout = JSON.stringify([
160+
{ name: 'foo' },
161+
{ version: '1.2.0' },
162+
]);
163+
expect(parseNpmLikeManifest(stdout)).toBeNull();
164+
});
165+
166+
it('should return null for invalid single object', () => {
167+
const stdout = JSON.stringify({ name: 'foo' }); // Missing version
168+
expect(parseNpmLikeManifest(stdout)).toBeNull();
169+
});
170+
147171
it('should return null for empty stdout', () => {
148172
expect(parseNpmLikeManifest('')).toBeNull();
149173
});

0 commit comments

Comments
 (0)