Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Commit 954dd84

Browse files
committed
fix(@schematics/update): cache npm configuration options
1 parent 9245d52 commit 954dd84

File tree

1 file changed

+52
-29
lines changed
  • packages/schematics/update/update

1 file changed

+52
-29
lines changed

packages/schematics/update/update/npm.ts

+52-29
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,64 @@
88
import { logging } from '@angular-devkit/core';
99
import { exec } from 'child_process';
1010
import { Observable, ReplaySubject, concat, of } from 'rxjs';
11-
import { concatMap, filter, first, map, toArray } from 'rxjs/operators';
11+
import { concatMap, defaultIfEmpty, filter, first, map, toArray } from 'rxjs/operators';
1212
import * as url from 'url';
1313
import { NpmRepositoryPackageJson } from './npm-package-json';
1414

1515
const RegistryClient = require('npm-registry-client');
1616

1717
const npmPackageJsonCache = new Map<string, Observable<NpmRepositoryPackageJson>>();
18-
19-
20-
function getNpmConfigOption(option: string) {
21-
return new Observable<string | undefined>(obs => {
22-
try {
23-
exec(`npm get ${option}`, (error, data) => {
24-
if (error) {
25-
obs.next();
18+
const npmConfigOptionCache = new Map<string, Observable<string | undefined>>();
19+
20+
function getNpmConfigOption(
21+
option: string,
22+
scope?: string,
23+
tryWithoutScope?: boolean,
24+
): Observable<string | undefined> {
25+
if (scope && tryWithoutScope) {
26+
return concat(
27+
getNpmConfigOption(option, scope),
28+
getNpmConfigOption(option),
29+
).pipe(
30+
filter(result => !!result),
31+
defaultIfEmpty(),
32+
first(),
33+
);
34+
}
35+
36+
const fullOption = `${scope ? scope + ':' : ''}${option}`;
37+
38+
let value = npmConfigOptionCache.get(fullOption);
39+
if (value) {
40+
return value;
41+
}
42+
43+
const subject = new ReplaySubject<string | undefined>(1);
44+
45+
try {
46+
exec(`npm get ${fullOption}`, (error, data) => {
47+
if (error) {
48+
subject.next();
49+
} else {
50+
data = data.trim();
51+
if (!data || data === 'undefined' || data === 'null') {
52+
subject.next();
2653
} else {
27-
data = data.trim();
28-
if (!data || data === 'undefined' || data === 'null') {
29-
obs.next();
30-
} else {
31-
obs.next(data);
32-
}
54+
subject.next(data);
3355
}
56+
}
57+
58+
subject.complete();
59+
});
60+
} catch {
61+
subject.next();
62+
subject.complete();
63+
}
64+
65+
value = subject.asObservable();
66+
npmConfigOptionCache.set(fullOption, value);
3467

35-
obs.complete();
36-
});
37-
} catch {
38-
obs.next();
39-
obs.complete();
40-
}
41-
});
68+
return value;
4269
}
4370

4471
/**
@@ -54,15 +81,11 @@ export function getNpmPackageJson(
5481
registryUrl: string | undefined,
5582
logger: logging.LoggerApi,
5683
): Observable<Partial<NpmRepositoryPackageJson>> {
57-
const scope = packageName.startsWith('@') ? packageName.split('/')[0] : null;
84+
const scope = packageName.startsWith('@') ? packageName.split('/')[0] : undefined;
5885

59-
return concat(
60-
of(registryUrl),
61-
scope ? getNpmConfigOption(scope + ':registry') : of(undefined),
62-
getNpmConfigOption('registry'),
86+
return (
87+
registryUrl ? of(registryUrl) : getNpmConfigOption('registry', scope, true)
6388
).pipe(
64-
filter(partialUrl => !!partialUrl),
65-
first(),
6689
map(partialUrl => {
6790
if (!partialUrl) {
6891
partialUrl = 'https://registry.npmjs.org/';

0 commit comments

Comments
 (0)