Skip to content

Commit 841ba6e

Browse files
clydinhansl
authored andcommitted
fix(@schematics/update): cache npm configuration options
1 parent c054c4b commit 841ba6e

File tree

1 file changed

+50
-27
lines changed
  • packages/schematics/update/update

1 file changed

+50
-27
lines changed

packages/schematics/update/update/npm.ts

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,64 @@ import { logging } from '@angular-devkit/core';
99
import { exec } from 'child_process';
1010
import { readFileSync } from 'fs';
1111
import { Observable, ReplaySubject, concat, of } from 'rxjs';
12-
import { concatMap, filter, first, map, toArray } from 'rxjs/operators';
12+
import { concatMap, defaultIfEmpty, filter, first, map, toArray } from 'rxjs/operators';
1313
import * as url from 'url';
1414
import { NpmRepositoryPackageJson } from './npm-package-json';
1515

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

1818
const npmPackageJsonCache = new Map<string, Observable<NpmRepositoryPackageJson>>();
19+
const npmConfigOptionCache = new Map<string, Observable<string | undefined>>();
20+
21+
function getNpmConfigOption(
22+
option: string,
23+
scope?: string,
24+
tryWithoutScope?: boolean,
25+
): Observable<string | undefined> {
26+
if (scope && tryWithoutScope) {
27+
return concat(
28+
getNpmConfigOption(option, scope),
29+
getNpmConfigOption(option),
30+
).pipe(
31+
filter(result => !!result),
32+
defaultIfEmpty(),
33+
first(),
34+
);
35+
}
36+
37+
const fullOption = `${scope ? scope + ':' : ''}${option}`;
38+
39+
let value = npmConfigOptionCache.get(fullOption);
40+
if (value) {
41+
return value;
42+
}
1943

44+
const subject = new ReplaySubject<string | undefined>(1);
2045

21-
function getNpmConfigOption(option: string) {
22-
return new Observable<string | undefined>(obs => {
23-
try {
24-
exec(`npm get ${option}`, (error, data) => {
25-
if (error) {
26-
obs.next();
46+
try {
47+
exec(`npm get ${fullOption}`, (error, data) => {
48+
if (error) {
49+
subject.next();
50+
} else {
51+
data = data.trim();
52+
if (!data || data === 'undefined' || data === 'null') {
53+
subject.next();
2754
} else {
28-
data = data.trim();
29-
if (!data || data === 'undefined' || data === 'null') {
30-
obs.next();
31-
} else {
32-
obs.next(data);
33-
}
55+
subject.next(data);
3456
}
57+
}
58+
59+
subject.complete();
60+
});
61+
} catch {
62+
subject.next();
63+
subject.complete();
64+
}
65+
66+
value = subject.asObservable();
67+
npmConfigOptionCache.set(fullOption, value);
3568

36-
obs.complete();
37-
});
38-
} catch {
39-
obs.next();
40-
obs.complete();
41-
}
42-
});
69+
return value;
4370
}
4471

4572
function getNpmClientSslOptions(strictSsl?: string, cafile?: string) {
@@ -71,15 +98,11 @@ export function getNpmPackageJson(
7198
registryUrl: string | undefined,
7299
logger: logging.LoggerApi,
73100
): Observable<Partial<NpmRepositoryPackageJson>> {
74-
const scope = packageName.startsWith('@') ? packageName.split('/')[0] : null;
101+
const scope = packageName.startsWith('@') ? packageName.split('/')[0] : undefined;
75102

76-
return concat(
77-
of(registryUrl),
78-
scope ? getNpmConfigOption(scope + ':registry') : of(undefined),
79-
getNpmConfigOption('registry'),
103+
return (
104+
registryUrl ? of(registryUrl) : getNpmConfigOption('registry', scope, true)
80105
).pipe(
81-
filter(partialUrl => !!partialUrl),
82-
first(),
83106
map(partialUrl => {
84107
if (!partialUrl) {
85108
partialUrl = 'https://registry.npmjs.org/';

0 commit comments

Comments
 (0)