-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
Copy pathrc.js
146 lines (116 loc) · 4.38 KB
/
rc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* @flow */
import {existsSync, readFileSync} from 'fs';
import {dirname, resolve} from 'path';
import commander from 'commander';
import {parse} from './lockfile';
import * as rcUtil from './util/rc.js';
// Keys that will get resolved relative to the path of the rc file they belong to
const PATH_KEYS = new Set([
'yarn-path',
'cache-folder',
'global-folder',
'modules-folder',
'cwd',
'offline-cache-folder',
]);
// given a cwd, load all .yarnrc files relative to it
export function getRcConfigForCwd(cwd: string, args: Array<string>): {[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, 'utf8'), value));
}
}
return config;
}
export function getRcConfigForFolder(cwd: string): {[key: string]: string} {
const filePath = resolve(cwd, '.yarnrc');
if (!existsSync(filePath)) {
return {};
}
const fileText = readFileSync(filePath, 'utf8');
return loadRcFile(fileText, filePath);
}
function loadRcFile(fileText: string, filePath: string): {[key: string]: string} {
let {object: values} = parse(fileText, filePath);
if (filePath.match(/\.yml$/) && typeof values.yarnPath === 'string') {
values = {'yarn-path': values.yarnPath};
}
// 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;
}
// get the built of arguments of a .yarnrc chain of the passed cwd
function buildRcArgs(cwd: string, args: Array<string>): Map<string, Array<string>> {
const config = getRcConfigForCwd(cwd, args);
const argsForCommands: Map<string, Array<string>> = new Map();
for (const key in config) {
// args can be prefixed with the command name they're meant for, eg.
// `--install.check-files true`
const keyMatch = key.match(/^--(?:([^.]+)\.)?(.*)$/);
if (!keyMatch) {
continue;
}
const commandName = keyMatch[1] || '*';
const arg = keyMatch[2];
const value = config[key];
// create args for this command name if we didn't previously have them
const args = argsForCommands.get(commandName) || [];
argsForCommands.set(commandName, args);
// turn config value into appropriate cli flag
const option = commander.optionFor(`--${arg}`);
// If commander doesn't recognize the option or it takes a value after it
if (!option || option.optional || option.required) {
args.push(`--${arg}`, value);
} else if (value === true) {
// we can't force remove an arg from cli
args.push(`--${arg}`);
}
}
return argsForCommands;
}
// extract the value of a --cwd arg if present
function extractCwdArg(args: Array<string>): ?string {
for (let i = 0, I = args.length; i < I; ++i) {
const arg = args[i];
if (arg === '--') {
return null;
} else if (arg === '--cwd') {
return args[i + 1];
}
}
return null;
}
// get a list of arguments from .yarnrc that apply to this commandName
export function getRcArgs(commandName: string, args: Array<string>, previousCwds?: Array<string> = []): Array<string> {
// for the cwd, use the --cwd arg if it was passed or else use process.cwd()
const origCwd = extractCwdArg(args) || process.cwd();
// get a map of command names and their arguments
const argMap = buildRcArgs(origCwd, args);
// concat wildcard arguments and arguments meant for this specific command
const newArgs = [...(argMap.get('*') || []), ...(argMap.get(commandName) || [])];
// check if the .yarnrc args specified a cwd
const newCwd = extractCwdArg(newArgs);
if (newCwd && newCwd !== origCwd) {
// ensure that we don't enter into a loop
if (previousCwds.indexOf(newCwd) !== -1) {
throw new Error(`Recursive .yarnrc files specifying --cwd flags. Bailing out.`);
}
// if we have a new cwd then let's refetch the .yarnrc args relative to it
return getRcArgs(commandName, newArgs, previousCwds.concat(origCwd));
}
return newArgs;
}