66 * found in the LICENSE file at https://angular.io/license
77 */
88import { logging } from '@angular-devkit/core' ;
9- import { readFileSync } from 'fs' ;
9+ import { existsSync , readFileSync } from 'fs' ;
10+ import { homedir } from 'os' ;
11+ import * as path from 'path' ;
1012import { Observable , from } from 'rxjs' ;
1113import { shareReplay } from 'rxjs/operators' ;
1214import { NpmRepositoryPackageJson } from './npm-package-json' ;
1315
16+ const ini = require ( 'ini' ) ;
17+ const lockfile = require ( '@yarnpkg/lockfile' ) ;
1418const pacote = require ( 'pacote' ) ;
1519
1620const npmPackageJsonCache = new Map < string , Observable < NpmRepositoryPackageJson > > ( ) ;
17-
1821let npmrc : { [ key : string ] : string } ;
19- try {
20- npmrc = _readNpmRc ( ) ;
21- } catch {
22- npmrc = { } ;
23- }
2422
2523
26- function _readNpmRc ( ) : { [ key : string ] : string } {
24+ function readOptions ( yarn = false ) : { [ key : string ] : string } {
2725 // TODO: have a way to read options without using fs directly.
28- const path = require ( 'path' ) ;
29- const fs = require ( 'fs' ) ;
30- const perProjectNpmrc = path . resolve ( '.npmrc' ) ;
26+ const cwd = process . cwd ( ) ;
27+ const baseFilename = yarn ? 'yarnrc' : 'npmrc' ;
28+ const dotFilename = '.' + baseFilename ;
3129
32- const configs : string [ ] = [ ] ;
33-
34- if ( process . platform === 'win32' ) {
35- if ( process . env . LOCALAPPDATA ) {
36- configs . push ( fs . readFileSync ( path . join ( process . env . LOCALAPPDATA , '.npmrc' ) , 'utf8' ) ) ;
37- }
30+ let globalPrefix : string ;
31+ if ( process . env . PREFIX ) {
32+ globalPrefix = process . env . PREFIX ;
3833 } else {
39- if ( process . env . HOME ) {
40- configs . push ( fs . readFileSync ( path . join ( process . env . HOME , '.npmrc' ) , 'utf8' ) ) ;
34+ globalPrefix = path . dirname ( process . execPath ) ;
35+ if ( process . platform !== 'win32' ) {
36+ globalPrefix = path . dirname ( globalPrefix ) ;
4137 }
4238 }
4339
44- if ( fs . existsSync ( perProjectNpmrc ) ) {
45- configs . push ( fs . readFileSync ( perProjectNpmrc , 'utf8' ) ) ;
46- }
47-
48- const allOptions : { [ key : string ] : string } = { } ;
49- for ( const config of configs ) {
50- const allOptionsArr = config . split ( / \r ? \n / ) . map ( x => x . trim ( ) ) ;
40+ const defaultConfigLocations = [
41+ path . join ( globalPrefix , 'etc' , baseFilename ) ,
42+ path . join ( homedir ( ) , dotFilename ) ,
43+ ] ;
5144
52- allOptionsArr . forEach ( x => {
53- const [ key , ...value ] = x . split ( '=' ) ;
54- const fullValue = value . join ( '=' ) . trim ( ) ;
55- if ( key && fullValue && fullValue !== 'null' ) {
56- allOptions [ key . trim ( ) ] = fullValue ;
45+ const projectConfigLocations : string [ ] = [ ] ;
46+ const root = path . parse ( cwd ) . root ;
47+ for ( let curDir = path . dirname ( cwd ) ; curDir && curDir !== root ; curDir = path . dirname ( curDir ) ) {
48+ projectConfigLocations . unshift ( path . join ( curDir , dotFilename ) ) ;
49+ }
50+ projectConfigLocations . push ( path . join ( cwd , dotFilename ) ) ;
51+
52+ let options : { [ key : string ] : string } = { } ;
53+ for ( const location of [ ...defaultConfigLocations , ...projectConfigLocations ] ) {
54+ if ( existsSync ( location ) ) {
55+ const data = readFileSync ( location , 'utf8' ) ;
56+ options = {
57+ ...options ,
58+ ...( yarn ? lockfile . parse ( data ) : ini . parse ( data ) ) ,
59+ } ;
60+
61+ if ( options . cafile ) {
62+ const cafile = path . resolve ( path . dirname ( location ) , options . cafile ) ;
63+ delete options . cafile ;
64+ try {
65+ options . ca = readFileSync ( cafile , 'utf8' ) . replace ( / \r ? \n / , '\\n' ) ;
66+ } catch { }
5767 }
58- } ) ;
59-
60- if ( allOptions . cafile ) {
61- const cafile = allOptions . cafile ;
62- delete allOptions . cafile ;
63- try {
64- allOptions . ca = readFileSync ( cafile , 'utf8' ) ;
65- allOptions . ca = allOptions . ca . replace ( / \r ? \n / , '\\n' ) ;
66- } catch { }
6768 }
6869 }
6970
70- return allOptions ;
71+ return options ;
7172}
7273
7374/**
@@ -82,12 +83,25 @@ export function getNpmPackageJson(
8283 packageName : string ,
8384 registryUrl : string | undefined ,
8485 _logger : logging . LoggerApi ,
86+ usingYarn = false ,
8587) : Observable < Partial < NpmRepositoryPackageJson > > {
8688 const cachedResponse = npmPackageJsonCache . get ( packageName ) ;
8789 if ( cachedResponse ) {
8890 return cachedResponse ;
8991 }
9092
93+ if ( ! npmrc ) {
94+ try {
95+ npmrc = readOptions ( ) ;
96+ } catch { }
97+
98+ if ( usingYarn ) {
99+ try {
100+ npmrc = { ...npmrc , ...readOptions ( true ) } ;
101+ } catch { }
102+ }
103+ }
104+
91105 const resultPromise = pacote . packument (
92106 packageName ,
93107 {
0 commit comments