Skip to content

Commit c976f3c

Browse files
committed
fix(@angular/cli): use unquoted specifier for registry manifest cache keys
The resolved-version manifest cache entry was stored using an unquoted `name@version` key while lookups on hosts that require shell quoting used a quoted key, so the entry was never reused. Both keys are now derived from the unquoted specifier.
1 parent 05eb47c commit c976f3c

2 files changed

Lines changed: 34 additions & 6 deletions

File tree

‎packages/angular/cli/src/package-managers/package-manager.ts‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,18 @@ export class PackageManager {
533533
return metadata;
534534
}
535535

536+
/**
537+
* Creates the in-memory cache key for a registry manifest.
538+
*
539+
* The key is intentionally based on the unquoted `name@version` specifier so that it is
540+
* stable regardless of whether the host requires shell quoting for command arguments.
541+
*/
542+
#getManifestCacheKey(packageName: string, version: string, registry?: string): string {
543+
const specifier = `${packageName}@${version}`;
544+
545+
return registry ? `${specifier}|${registry}` : specifier;
546+
}
547+
536548
/**
537549
* Fetches the registry manifest for a specific version of a package.
538550
* The manifest is similar to the package's `package.json` file.
@@ -558,7 +570,7 @@ export class PackageManager {
558570
commandArgs.push(...formatter(MANIFEST_FIELDS));
559571
}
560572

561-
const cacheKey = options.registry ? `${specifier}|${options.registry}` : specifier;
573+
const cacheKey = this.#getManifestCacheKey(packageName, version, options.registry);
562574
const normalizedRange = validRange(version);
563575

564576
const manifest = await this.#fetchAndParse(
@@ -588,11 +600,10 @@ export class PackageManager {
588600

589601
// If the provided version was not a specific version, also cache the specific fetched version
590602
if (manifest && manifest.version !== version) {
591-
const manifestSpecifier = `${manifest.name}@${manifest.version}`;
592-
const manifestCacheKey = options.registry
593-
? `${manifestSpecifier}|${options.registry}`
594-
: manifestSpecifier;
595-
this.#manifestCache.set(manifestCacheKey, manifest);
603+
this.#manifestCache.set(
604+
this.#getManifestCacheKey(manifest.name, manifest.version, options.registry),
605+
manifest,
606+
);
596607
}
597608

598609
return manifest;

‎packages/angular/cli/src/package-managers/package-manager_spec.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ describe('PackageManager', () => {
180180
);
181181
});
182182

183+
it('should reuse the resolved version cache entry when the host requires quoting', async () => {
184+
Object.assign(host, { requiresQuoting: true });
185+
186+
const pm = new PackageManager(host, '/tmp', descriptor);
187+
runCommandSpy.and.resolveTo({
188+
stdout: JSON.stringify({ name: 'foo', version: '1.5.0' }),
189+
stderr: '',
190+
});
191+
192+
await pm.getRegistryManifest('foo', '^1.0.0');
193+
expect(await pm.getRegistryManifest('foo', '1.5.0')).toEqual({
194+
name: 'foo',
195+
version: '1.5.0',
196+
});
197+
expect(runCommandSpy).toHaveBeenCalledTimes(1);
198+
});
199+
183200
it('should return null when bun pm view fails with No matching version found', async () => {
184201
const pm = new PackageManager(host, '/tmp', SUPPORTED_PACKAGE_MANAGERS['bun']);
185202
runCommandSpy.and.rejectWith(

0 commit comments

Comments
 (0)