From c402e7ee28194452de684d0297dc38318a264f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 18 Jun 2018 18:39:51 +0100 Subject: [PATCH] Implements --no-default-rc and --use-rc --- __tests__/commands/_helpers.js | 2 + .../fixtures/cache/custom-location/.yarnrc | 1 + .../cache/custom-location/custom-yarnrc | 1 + .../cache/custom-location/package.json | 1 + __tests__/integration.js | 20 +++++++ __tests__/rc.js | 16 ++++++ __tests__/registries/npm-registry.js | 26 ++++----- bin/yarn.js | 5 +- src/cli/index.js | 29 +++++++--- src/config.js | 21 +++++++- src/rc.js | 50 ++++++++++++----- src/registries/base-registry.js | 15 +++++- src/registries/npm-registry.js | 54 ++++++++++++------- src/registries/yarn-registry.js | 15 ++++-- 14 files changed, 198 insertions(+), 58 deletions(-) create mode 100644 __tests__/fixtures/cache/custom-location/.yarnrc create mode 100644 __tests__/fixtures/cache/custom-location/custom-yarnrc create mode 100644 __tests__/fixtures/cache/custom-location/package.json diff --git a/__tests__/commands/_helpers.js b/__tests__/commands/_helpers.js index 3a2da9203c..74b9658942 100644 --- a/__tests__/commands/_helpers.js +++ b/__tests__/commands/_helpers.js @@ -92,6 +92,8 @@ export function makeConfigFromDirectory(cwd: string, reporter: Reporter, flags: production: flags.production, updateChecksums: !!flags.updateChecksums, focus: !!flags.focus, + enableDefaultRc: !flags.noDefaultRc, + extraneousYarnrcFiles: flags.useYarnrc, }, reporter, ); diff --git a/__tests__/fixtures/cache/custom-location/.yarnrc b/__tests__/fixtures/cache/custom-location/.yarnrc new file mode 100644 index 0000000000..aec94e3d74 --- /dev/null +++ b/__tests__/fixtures/cache/custom-location/.yarnrc @@ -0,0 +1 @@ +cache-folder "./uses-default-yarnrc" diff --git a/__tests__/fixtures/cache/custom-location/custom-yarnrc b/__tests__/fixtures/cache/custom-location/custom-yarnrc new file mode 100644 index 0000000000..40a6ca773f --- /dev/null +++ b/__tests__/fixtures/cache/custom-location/custom-yarnrc @@ -0,0 +1 @@ +cache-folder "./uses-custom-yarnrc" diff --git a/__tests__/fixtures/cache/custom-location/package.json b/__tests__/fixtures/cache/custom-location/package.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/__tests__/fixtures/cache/custom-location/package.json @@ -0,0 +1 @@ +{} diff --git a/__tests__/integration.js b/__tests__/integration.js index d193b2bc5f..58a39caec7 100644 --- a/__tests__/integration.js +++ b/__tests__/integration.js @@ -271,6 +271,26 @@ test('--cwd option', async () => { expect(packageJson.dependencies['left-pad']).toBeDefined(); }); +const customCacheCwd = `${__dirname}/fixtures/cache/custom-location`; + +test('default rc', async (): Promise => { + const [stdoutOutput] = await runYarn(['cache', 'dir'], {cwd: customCacheCwd}); + + expect(stdoutOutput).toMatch(/uses-default-yarnrc/); +}); + +test('--no-default-rc', async (): Promise => { + const [stdoutOutput] = await runYarn(['cache', 'dir', '--no-default-rc'], {cwd: customCacheCwd}); + + expect(stdoutOutput).not.toMatch(/uses-default-yarnrc/); +}); + +test('--use-yarnrc', async (): Promise => { + const [stdoutOutput] = await runYarn(['cache', 'dir', '--use-yarnrc', './custom-yarnrc'], {cwd: customCacheCwd}); + + expect(stdoutOutput).toMatch(/uses-custom-yarnrc/); +}); + test('yarnrc arguments', async () => { const cwd = await makeTemp(); diff --git a/__tests__/rc.js b/__tests__/rc.js index ab6c1e2cf9..5733c34c6b 100644 --- a/__tests__/rc.js +++ b/__tests__/rc.js @@ -10,6 +10,22 @@ test('resolve .yarnrc args and use --cwd if present', () => { expect(args.indexOf('--foo') !== -1).toBe(true); }); +test("don't resolve .yarnrc args from the default locations when using --no-default-rc", () => { + const args = getRcArgs('install', ['--cwd', path.join(fixturesLoc, 'empty'), '--no-default-rc']); + expect(args.indexOf('--foo') !== -1).toBe(false); +}); + +test('resolve .yarnrc args from the extraneous locations when using --use-yarnrc', () => { + const args = getRcArgs('install', [ + '--cwd', + path.join(fixturesLoc, 'empty'), + '--no-default-rc', + '--use-yarnrc', + path.join(fixturesLoc, 'empty', '.yarnrc'), + ]); + expect(args.indexOf('--foo') !== -1).toBe(true); +}); + test('resolve .yarnrc args and use process.cwd() if no --cwd present', () => { const cwd = process.cwd(); process.chdir(path.join(fixturesLoc, 'empty')); diff --git a/__tests__/registries/npm-registry.js b/__tests__/registries/npm-registry.js index 6dbb620178..b9a85834cd 100644 --- a/__tests__/registries/npm-registry.js +++ b/__tests__/registries/npm-registry.js @@ -77,7 +77,7 @@ describe('request', () => { function createRegistry(config: Object): Object { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); npmRegistry.config = config; return { request(url: string, options: Object, packageName: string): Object { @@ -577,7 +577,7 @@ describe('isRequestToRegistry functional test', () => { test('request to registry url matching', () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); const validRegistryUrls = [ ['http://foo.bar:80/foo/bar/baz', 'http://foo.bar/foo/'], @@ -609,7 +609,7 @@ describe('isRequestToRegistry functional test', () => { test('isRequestToRegistry with custom host prefix', () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); npmRegistry.config = { 'custom-host-suffix': 'some.host.org', @@ -659,7 +659,7 @@ describe('isScopedPackage functional test', () => { test('identifies scope correctly', () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); packageIdents.forEach(([pathname, scope]) => { expect(npmRegistry.isScopedPackage(pathname)).toEqual(!!scope.length); @@ -671,7 +671,7 @@ describe('getRequestUrl functional test', () => { test('returns pathname when it is a full URL', () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); const fullURL = 'HTTP://xn--xample-hva.com:80/foo/bar/baz'; expect(npmRegistry.getRequestUrl('https://my.registry.co', fullURL)).toEqual(fullURL); @@ -680,7 +680,7 @@ describe('getRequestUrl functional test', () => { test('correctly handles registries lacking a trailing slash', () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); const registry = 'https://my.registry.co/registry'; const pathname = 'foo/bar/baz'; @@ -692,7 +692,7 @@ describe('getScope functional test', () => { describe('matches scope correctly', () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); packageIdents.forEach(([pathname, scope]) => { expect(npmRegistry.getScope(pathname)).toEqual(scope); @@ -705,7 +705,7 @@ describe('getPossibleConfigLocations', () => { const testCwd = './project/subdirectory'; const {mockRequestManager, mockRegistries} = createMocks(); const reporter = new BufferReporter({verbose: true}); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, reporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, reporter, true, []); await npmRegistry.getPossibleConfigLocations('npmrc', reporter); const logs = reporter.getBuffer().map(logItem => logItem.data); @@ -730,7 +730,7 @@ describe('checkOutdated functional test', () => { test('homepage URL from top level', async () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); mockRequestManager.request = () => { return { @@ -758,7 +758,7 @@ describe('checkOutdated functional test', () => { test('homepage URL fallback to wanted package manifest', async () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); mockRequestManager.request = () => { return { @@ -786,7 +786,7 @@ describe('checkOutdated functional test', () => { test('repository URL from top level', async () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); mockRequestManager.request = () => { return { @@ -816,7 +816,7 @@ describe('checkOutdated functional test', () => { test('repository URL fallback to wanted package manifest', async () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); mockRequestManager.request = () => { return { @@ -846,7 +846,7 @@ describe('checkOutdated functional test', () => { test('unpublished package (no versions)', async () => { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); mockRequestManager.request = () => { return { diff --git a/bin/yarn.js b/bin/yarn.js index e46b1f6002..196ebd7571 100755 --- a/bin/yarn.js +++ b/bin/yarn.js @@ -24,6 +24,9 @@ if (majorVer < 4) { // be truthy when built with webpack :( var cli = require(dirPath + 'cli'); if (!cli.autoRun) { - cli.default(); + cli.default().catch(function(error) { + console.error(error.stack || error.message || error); + process.exitCode = 1; + }); } } diff --git a/src/cli/index.js b/src/cli/index.js index 7e60e82d09..e1c1bb7e64 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -41,7 +41,7 @@ function findProjectRoot(base: string): string { return base; } -export function main({ +export async function main({ startArgs, args, endArgs, @@ -49,13 +49,25 @@ export function main({ startArgs: Array, args: Array, endArgs: Array, -}) { +}): Promise { + const collect = (val, acc) => { + acc.push(val); + return acc; + }; + loudRejection(); handleSignals(); // set global options commander.version(version, '-v, --version'); commander.usage('[command] [flags]'); + commander.option('--no-default-rc', 'prevent Yarn from automatically detecting yarnrc and npmrc files'); + commander.option( + '--use-yarnrc ', + 'specifies a yarnrc file that Yarn should use (.yarnrc only, not .npmrc)', + collect, + [], + ); commander.option('--verbose', 'output verbose messages on internal operations'); commander.option('--offline', 'trigger an error if any required dependencies are not available in local cache'); commander.option('--prefer-offline', 'use network only if dependencies are not available in local cache'); @@ -477,11 +489,13 @@ export function main({ const cwd = command.shouldRunInCurrentCwd ? commander.cwd : findProjectRoot(commander.cwd); - config + await config .init({ cwd, commandName, + enableDefaultRc: commander.defaultRc, + extraneousYarnrcFiles: commander.useYarnrc, binLinks: commander.binLinks, modulesFolder: commander.modulesFolder, linkFolder: commander.linkFolder, @@ -564,7 +578,7 @@ export function main({ } async function start(): Promise { - const rc = getRcConfigForCwd(process.cwd()); + const rc = getRcConfigForCwd(process.cwd(), process.argv.slice(2)); const yarnPath = rc['yarn-path']; if (yarnPath && !boolifyWithDefault(process.env.YARN_IGNORE_PATH, false)) { @@ -590,7 +604,7 @@ async function start(): Promise { const args = process.argv.slice(2, doubleDashIndex === -1 ? process.argv.length : doubleDashIndex); const endArgs = doubleDashIndex === -1 ? [] : process.argv.slice(doubleDashIndex); - main({startArgs, args, endArgs}); + await main({startArgs, args, endArgs}); } } @@ -599,7 +613,10 @@ async function start(): Promise { export const autoRun = module.children.length === 0; if (require.main === module) { - start(); + start().catch(error => { + console.error(error.stack || error.message || error); + process.exitCode = 1; + }); } export default start; diff --git a/src/config.js b/src/config.js index 33dabe3690..bd485163c4 100644 --- a/src/config.js +++ b/src/config.js @@ -49,6 +49,9 @@ export type ConfigOptions = { nonInteractive?: boolean, scriptsPrependNodePath?: boolean, + enableDefaultRc?: boolean, + extraneousYarnrcFiles?: Array, + // Loosely compare semver for invalid cases like "0.01.0" looseSemver?: ?boolean, @@ -96,6 +99,10 @@ export default class Config { this._init({}); } + // + enableDefaultRc: boolean; + extraneousYarnrcFiles: Array; + // looseSemver: boolean; offline: boolean; @@ -272,8 +279,17 @@ export default class Config { for (const key of Object.keys(registries)) { const Registry = registries[key]; + const extraneousRcFiles = Registry === registries.yarn ? this.extraneousYarnrcFiles : []; + // instantiate registry - const registry = new Registry(this.cwd, this.registries, this.requestManager, this.reporter); + const registry = new Registry( + this.cwd, + this.registries, + this.requestManager, + this.reporter, + this.enableDefaultRc, + extraneousRcFiles, + ); await registry.init({ registry: opts.registry, }); @@ -386,6 +402,9 @@ export default class Config { this.commandName = opts.commandName || ''; + this.enableDefaultRc = !!opts.enableDefaultRc; + this.extraneousYarnrcFiles = opts.extraneousYarnrcFiles || []; + this.preferOffline = !!opts.preferOffline; this.modulesFolder = opts.modulesFolder; this.globalFolder = opts.globalFolder || constants.GLOBAL_MODULE_DIRECTORY; diff --git a/src/rc.js b/src/rc.js index 34634c40ba..fe19259d95 100644 --- a/src/rc.js +++ b/src/rc.js @@ -1,5 +1,6 @@ /* @flow */ +import {readFileSync} from 'fs'; import {dirname, resolve} from 'path'; import commander from 'commander'; @@ -11,24 +12,45 @@ import * as rcUtil from './util/rc.js'; const PATH_KEYS = new Set(['yarn-path', 'cache-folder', 'global-folder', 'modules-folder', 'cwd']); // given a cwd, load all .yarnrc files relative to it -export function getRcConfigForCwd(cwd: string): {[key: string]: string} { - return rcUtil.findRc('yarn', cwd, (fileText, filePath) => { - const {object: values} = parse(fileText, 'yarnrc'); - - // some keys reference directories so keep their relativity - for (const key in values) { - if (PATH_KEYS.has(key.replace(/^(--)?([^.]+\.)*/, ''))) { - values[key] = resolve(dirname(filePath), values[key]); - } +export function getRcConfigForCwd(cwd: string, args: Array): {[key: string]: string} { + const config = {}; + + if (args.indexOf('--no-default-rc') === -1) { + Object.assign( + config, + rcUtil.findRc('yarn', cwd, (fileText, filePath) => { + return loadRcFile(fileText, filePath); + }), + ); + } + + for (let index = args.indexOf('--use-yarnrc'); index !== -1; index = args.indexOf('--use-yarnrc', index + 1)) { + const value = args[index + 1]; + + if (value && value.charAt(0) !== '-') { + Object.assign(config, loadRcFile(readFileSync(value).toString(), value)); + } + } + + return config; +} + +function loadRcFile(fileText: string, filePath: string): {[key: string]: string} { + const {object: values} = parse(fileText, 'yarnrc'); + + // some keys reference directories so keep their relativity + for (const key in values) { + if (PATH_KEYS.has(key.replace(/^(--)?([^.]+\.)*/, ''))) { + values[key] = resolve(dirname(filePath), values[key]); } + } - return values; - }); + return values; } // get the built of arguments of a .yarnrc chain of the passed cwd -function buildRcArgs(cwd: string): Map> { - const config = getRcConfigForCwd(cwd); +function buildRcArgs(cwd: string, args: Array): Map> { + const config = getRcConfigForCwd(cwd, args); const argsForCommands: Map> = new Map(); @@ -82,7 +104,7 @@ export function getRcArgs(commandName: string, args: Array, previousCwds const origCwd = extractCwdArg(args) || process.cwd(); // get a map of command names and their arguments - const argMap = buildRcArgs(origCwd); + const argMap = buildRcArgs(origCwd, args); // concat wildcard arguments and arguments meant for this specific command const newArgs = [...(argMap.get('*') || []), ...(argMap.get(commandName) || [])]; diff --git a/src/registries/base-registry.js b/src/registries/base-registry.js index eef0e0c9ed..87cdfce385 100644 --- a/src/registries/base-registry.js +++ b/src/registries/base-registry.js @@ -27,7 +27,14 @@ export type CheckOutdatedReturn = Promise<{ }>; export default class BaseRegistry { - constructor(cwd: string, registries: ConfigRegistries, requestManager: RequestManager, reporter: Reporter) { + constructor( + cwd: string, + registries: ConfigRegistries, + requestManager: RequestManager, + reporter: Reporter, + enableDefaultRc: boolean, + extraneousRcFiles: Array, + ) { this.reporter = reporter; this.requestManager = requestManager; this.registries = registries; @@ -36,11 +43,17 @@ export default class BaseRegistry { this.token = ''; this.loc = ''; this.cwd = cwd; + this.enableDefaultRc = enableDefaultRc; + this.extraneousRcFiles = extraneousRcFiles; } // the filename to use for package metadata static filename: string; + // + enableDefaultRc: boolean; + extraneousRcFiles: Array; + // reporter: Reporter; // diff --git a/src/registries/npm-registry.js b/src/registries/npm-registry.js index 02f549a9bd..222245050f 100644 --- a/src/registries/npm-registry.js +++ b/src/registries/npm-registry.js @@ -86,8 +86,15 @@ function urlParts(requestUrl: string): UrlParts { } export default class NpmRegistry extends Registry { - constructor(cwd: string, registries: ConfigRegistries, requestManager: RequestManager, reporter: Reporter) { - super(cwd, registries, requestManager, reporter); + constructor( + cwd: string, + registries: ConfigRegistries, + requestManager: RequestManager, + reporter: Reporter, + enableDefaultRc: boolean, + extraneousRcFiles: Array, + ) { + super(cwd, registries, requestManager, reporter, enableDefaultRc, extraneousRcFiles); this.folder = 'node_modules'; } @@ -209,25 +216,33 @@ export default class NpmRegistry extends Registry { } async getPossibleConfigLocations(filename: string, reporter: Reporter): Promise> { - // npmrc --> ./.npmrc, ~/.npmrc, ${prefix}/etc/npmrc - const localfile = '.' + filename; - const possibles = [ - [false, path.join(this.cwd, localfile)], - [true, this.config.userconfig || path.join(userHome, localfile)], - [false, path.join(getGlobalPrefix(), 'etc', filename)], - ]; - - // When home directory for global install is different from where $HOME/npmrc is stored, - // E.g. /usr/local/share vs /root on linux machines, check the additional location - if (home !== userHome) { - possibles.push([true, path.join(home, localfile)]); + let possibles = []; + + for (const rcFile of this.extraneousRcFiles.slice().reverse()) { + possibles.push([false, path.resolve(process.cwd(), rcFile)]); } - // npmrc --> ../.npmrc, ../../.npmrc, etc. - const foldersFromRootToCwd = getPosixPath(this.cwd).split('/'); - while (foldersFromRootToCwd.length > 1) { - possibles.push([false, path.join(foldersFromRootToCwd.join(path.sep), localfile)]); - foldersFromRootToCwd.pop(); + if (this.enableDefaultRc) { + // npmrc --> ./.npmrc, ~/.npmrc, ${prefix}/etc/npmrc + const localfile = '.' + filename; + possibles = possibles.concat([ + [false, path.join(this.cwd, localfile)], + [true, this.config.userconfig || path.join(userHome, localfile)], + [false, path.join(getGlobalPrefix(), 'etc', filename)], + ]); + + // When home directory for global install is different from where $HOME/npmrc is stored, + // E.g. /usr/local/share vs /root on linux machines, check the additional location + if (home !== userHome) { + possibles.push([true, path.join(home, localfile)]); + } + + // npmrc --> ../.npmrc, ../../.npmrc, etc. + const foldersFromRootToCwd = getPosixPath(this.cwd).split('/'); + while (foldersFromRootToCwd.length > 1) { + possibles.push([false, path.join(foldersFromRootToCwd.join(path.sep), localfile)]); + foldersFromRootToCwd.pop(); + } } const actuals = []; @@ -238,6 +253,7 @@ export default class NpmRegistry extends Registry { actuals.push([isHome, loc, await fs.readFile(loc)]); } } + return actuals; } diff --git a/src/registries/yarn-registry.js b/src/registries/yarn-registry.js index b55aaf4bd2..8c58760296 100644 --- a/src/registries/yarn-registry.js +++ b/src/registries/yarn-registry.js @@ -42,8 +42,15 @@ const npmMap = { }; export default class YarnRegistry extends NpmRegistry { - constructor(cwd: string, registries: ConfigRegistries, requestManager: RequestManager, reporter: Reporter) { - super(cwd, registries, requestManager, reporter); + constructor( + cwd: string, + registries: ConfigRegistries, + requestManager: RequestManager, + reporter: Reporter, + enableDefaultRc: boolean, + extraneousRcFiles: Array, + ) { + super(cwd, registries, requestManager, reporter, enableDefaultRc, extraneousRcFiles); this.homeConfigLoc = path.join(userHome, '.yarnrc'); this.homeConfig = {}; @@ -75,7 +82,9 @@ export default class YarnRegistry extends NpmRegistry { } async loadConfig(): Promise { - for (const [isHome, loc, file] of await this.getPossibleConfigLocations('yarnrc', this.reporter)) { + const locations = await this.getPossibleConfigLocations('yarnrc', this.reporter); + + for (const [isHome, loc, file] of locations) { const {object: config} = parse(file, loc); if (isHome) {