rman 1.2.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants.js +1 -1
- package/core/config.d.ts +40 -31
- package/core/config.js +78 -83
- package/core/merge-config.js +1 -1
- package/core/repository.js +4 -3
- package/interfaces/rman-config.interface.d.ts +14 -10
- package/package.json +1 -1
package/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.
|
|
1
|
+
export const version = '1.3.0';
|
package/core/config.d.ts
CHANGED
|
@@ -27,52 +27,61 @@ export declare function readDirConfig(dirname: string): Promise<RmanConfig>;
|
|
|
27
27
|
* it (inclusive) - each directory level overrides the ones above it, the way tsconfig's `extends`
|
|
28
28
|
* chain does.
|
|
29
29
|
*
|
|
30
|
-
* Every level contributes in two ways
|
|
31
|
-
*
|
|
32
|
-
* - **
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
30
|
+
* Every level contributes in two ways:
|
|
31
|
+
*
|
|
32
|
+
* - **An unmarked key configures that directory and every package under it.** What a parent says
|
|
33
|
+
* reaches the children, which is what every directory-scoped config in the ecosystem does and
|
|
34
|
+
* what a reader expects without being told.
|
|
35
|
+
* - **A `"[selector]"` block narrows the audience** - `"[/]"` to the root package alone, `"[*]"` or
|
|
36
|
+
* a glob to the packages below (never the root, which is nobody's child). See `parseSelector`.
|
|
37
|
+
*
|
|
38
|
+
* **The root used to be the one directory whose unmarked config did *not* cascade**, on the
|
|
39
|
+
* reasoning that a setting means different things to a package and to the repository - and the
|
|
40
|
+
* reasoning is sound, but the rule it produced was not readable: an intermediate `packages/`
|
|
41
|
+
* cascaded while the root did not, so what a file meant depended on whether a `package.json` sat
|
|
42
|
+
* beside it. `vars` then had to be carved out as an exception, which is what a rule fighting itself
|
|
43
|
+
* looks like. One sentence now covers both: what is written above reaches below, and `"[/]"` is how
|
|
44
|
+
* a statement stays at the root.
|
|
45
|
+
*
|
|
46
|
+
* **The cost is real and lands on one subtree.** `run.<script>`'s hooks on the root are a repo-wide
|
|
47
|
+
* bookend, run once at the repository root; on a package they are that package's own hook, run in
|
|
48
|
+
* its directory. Cascaded, one declaration is both - once at the root and once per package. A
|
|
49
|
+
* repo-wide bookend therefore belongs under `"[/]"`, where its audience is visible; that is the
|
|
50
|
+
* migration this change asks for, and the only one that is not mechanical.
|
|
46
51
|
*
|
|
47
52
|
* `packageName` is what selectors match against; without it, selector blocks contribute nothing at
|
|
48
|
-
* all. The root package passes its own, since `"[/]"`
|
|
53
|
+
* all. The root package passes its own, since `"[/]"` speaks to it.
|
|
49
54
|
*/
|
|
50
55
|
export declare function resolveConfig(rootDir: string, targetDir: string, cache?: Map<string, RmanConfig>, packageName?: string): Promise<RmanConfig>;
|
|
51
|
-
/** A config key naming packages rather than settings: `"[*]"`, `"[/]"`, `"[
|
|
56
|
+
/** A config key naming packages rather than settings: `"[*]"`, `"[/]"`, `"[pkg-a]"`. The
|
|
52
57
|
* brackets are what keep this space from colliding with real config keys - no setting starts with
|
|
53
58
|
* one - and in YAML they also mean the key always needs quoting (`"[*]":`), since a bare `[*]`
|
|
54
59
|
* parses as a flow sequence. */
|
|
55
60
|
export declare function isSelectorKey(key: string): boolean;
|
|
56
61
|
/**
|
|
57
|
-
* **Which packages a selector speaks for.**
|
|
62
|
+
* **Which packages a selector speaks for.** Two audiences, and the second is a glob:
|
|
58
63
|
*
|
|
59
64
|
* | | |
|
|
60
65
|
* | --- | --- |
|
|
61
|
-
* | `"[/]"` | the **root package**
|
|
62
|
-
* | `"[*]"`, `"[pkg-a]"`, `"[*-dialect]"` | **
|
|
63
|
-
* | `"[ws:*]"`, `"[workspace:pkg-*]"` | every **non-root** package the glob matches |
|
|
66
|
+
* | `"[/]"` | the **root package** alone |
|
|
67
|
+
* | `"[*]"`, `"[pkg-a]"`, `"[*-dialect]"` | the packages **below** this directory that the glob matches |
|
|
64
68
|
*
|
|
65
69
|
* `/` for the root because that is what a repository root is called everywhere else, and it cannot
|
|
66
|
-
* collide with a package name.
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
70
|
+
* collide with a package name.
|
|
71
|
+
*
|
|
72
|
+
* **The root is never selected by name, and that one rule removes two traps.** A glob matches
|
|
73
|
+
* package names, and the root is nobody's child - so `"[my-*]"` cannot quietly pick up a repository
|
|
74
|
+
* whose root package happens to be called `my-repo`, and `"[*]"` cannot hand a package-shaped
|
|
75
|
+
* setting to a root that has no build directory to apply it to. The root is addressed structurally
|
|
76
|
+
* or not at all.
|
|
77
|
+
*
|
|
78
|
+
* **`"[ws:*]"` / `"[workspace:*]"` is accepted and means exactly `"[*]"`.** The qualifier existed to
|
|
79
|
+
* say "not the root" back when a bare glob included it; the shape of the set says that now, so it
|
|
80
|
+
* has nothing left to add. Accepted rather than rejected because the two spellings resolve to the
|
|
81
|
+
* same packages - an error would be friction with no reader to protect.
|
|
73
82
|
*/
|
|
74
83
|
export declare function parseSelector(key: string): {
|
|
75
|
-
scope: 'root' | '
|
|
84
|
+
scope: 'root' | 'package';
|
|
76
85
|
test: (name: string) => boolean;
|
|
77
86
|
};
|
|
78
87
|
/** The glob inside a selector key, as a `RegExp` anchored at both ends - so `"[*-dialect]"` matches
|
|
@@ -330,7 +339,7 @@ export declare const DEFERRED_PATHS: string[];
|
|
|
330
339
|
* config:
|
|
331
340
|
*
|
|
332
341
|
* ```js
|
|
333
|
-
* '[
|
|
342
|
+
* '[*]': {
|
|
334
343
|
* clean: { include: ({ vars, value }) => [...value, vars.buildDir] }, // a value: called here
|
|
335
344
|
* run: { build: { after: ({ pkg }) => copyDocs(pkg) } }, // a step: called by `run`
|
|
336
345
|
* }
|
package/core/config.js
CHANGED
|
@@ -117,32 +117,37 @@ export async function readDirConfig(dirname) {
|
|
|
117
117
|
* it (inclusive) - each directory level overrides the ones above it, the way tsconfig's `extends`
|
|
118
118
|
* chain does.
|
|
119
119
|
*
|
|
120
|
-
* Every level contributes in two ways
|
|
121
|
-
*
|
|
122
|
-
* - **
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
120
|
+
* Every level contributes in two ways:
|
|
121
|
+
*
|
|
122
|
+
* - **An unmarked key configures that directory and every package under it.** What a parent says
|
|
123
|
+
* reaches the children, which is what every directory-scoped config in the ecosystem does and
|
|
124
|
+
* what a reader expects without being told.
|
|
125
|
+
* - **A `"[selector]"` block narrows the audience** - `"[/]"` to the root package alone, `"[*]"` or
|
|
126
|
+
* a glob to the packages below (never the root, which is nobody's child). See `parseSelector`.
|
|
127
|
+
*
|
|
128
|
+
* **The root used to be the one directory whose unmarked config did *not* cascade**, on the
|
|
129
|
+
* reasoning that a setting means different things to a package and to the repository - and the
|
|
130
|
+
* reasoning is sound, but the rule it produced was not readable: an intermediate `packages/`
|
|
131
|
+
* cascaded while the root did not, so what a file meant depended on whether a `package.json` sat
|
|
132
|
+
* beside it. `vars` then had to be carved out as an exception, which is what a rule fighting itself
|
|
133
|
+
* looks like. One sentence now covers both: what is written above reaches below, and `"[/]"` is how
|
|
134
|
+
* a statement stays at the root.
|
|
135
|
+
*
|
|
136
|
+
* **The cost is real and lands on one subtree.** `run.<script>`'s hooks on the root are a repo-wide
|
|
137
|
+
* bookend, run once at the repository root; on a package they are that package's own hook, run in
|
|
138
|
+
* its directory. Cascaded, one declaration is both - once at the root and once per package. A
|
|
139
|
+
* repo-wide bookend therefore belongs under `"[/]"`, where its audience is visible; that is the
|
|
140
|
+
* migration this change asks for, and the only one that is not mechanical.
|
|
136
141
|
*
|
|
137
142
|
* `packageName` is what selectors match against; without it, selector blocks contribute nothing at
|
|
138
|
-
* all. The root package passes its own, since `"[/]"`
|
|
143
|
+
* all. The root package passes its own, since `"[/]"` speaks to it.
|
|
139
144
|
*/
|
|
140
145
|
export async function resolveConfig(rootDir, targetDir, cache = new Map(), packageName) {
|
|
141
146
|
const result = {};
|
|
142
147
|
const target = path.resolve(targetDir);
|
|
143
148
|
/** The root *package* is the one whose directory is the repository root - no other test is
|
|
144
149
|
* needed, and none would be as reliable: a name can be anything. In a single-package repository
|
|
145
|
-
* that is the only package, so `"[/]"` reaches it and `"[
|
|
150
|
+
* that is the only package, so `"[/]"` reaches it and `"[*]"` reaches nothing. */
|
|
146
151
|
const isRoot = target === path.resolve(rootDir);
|
|
147
152
|
for (const dir of dirChain(rootDir, targetDir)) {
|
|
148
153
|
let local = cache.get(dir);
|
|
@@ -150,39 +155,30 @@ export async function resolveConfig(rootDir, targetDir, cache = new Map(), packa
|
|
|
150
155
|
local = await readDirConfig(dir);
|
|
151
156
|
cache.set(dir, local);
|
|
152
157
|
}
|
|
153
|
-
// A directory holding a package speaks for that package only - which is what keeps the root's
|
|
154
|
-
// own config off every package under it. A directory that holds none (an intermediate
|
|
155
|
-
// `packages/`, say) has no package to speak for, so its unmarked config can only mean
|
|
156
|
-
// "everything below" and still cascades.
|
|
157
|
-
const ownsAPackage = fs.existsSync(path.join(dir, 'package.json'));
|
|
158
|
-
const speaksForTarget = !ownsAPackage || path.resolve(dir) === target;
|
|
159
158
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
159
|
+
* **Unmarked first, because it is the widest thing this level says** - and that is an inversion
|
|
160
|
+
* of the order this loop used to run in, where a directory's own plain config beat a selector
|
|
161
|
+
* declared beside it. Under the old reading "unmarked" meant *this package* and so was the
|
|
162
|
+
* narrower of the two; it now means *this package and everything below*, which is the wider.
|
|
163
|
+
* Precedence follows the audience, not the spelling, so it had to move.
|
|
165
164
|
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
165
|
+
* Its position in the file is deliberately not consulted: a selector block written above the
|
|
166
|
+
* plain keys still wins. Unmarked is not a fourth selector - it is the level's floor, and the
|
|
167
|
+
* layer that feeds the directories below it.
|
|
168
168
|
*/
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// Selectors next, so a directory's own unmarked config still wins over a selector declared
|
|
172
|
-
// alongside it - "this package" is a more specific statement than "packages matching a glob".
|
|
169
|
+
mergeConfig(result, stripSelectors(local));
|
|
170
|
+
/** Then the selector blocks, **in the order they were written** - see `matchingSelectors`. */
|
|
173
171
|
if (packageName) {
|
|
174
172
|
for (const block of matchingSelectors(local, packageName, isRoot))
|
|
175
173
|
mergeConfig(result, block);
|
|
176
174
|
}
|
|
177
|
-
if (speaksForTarget)
|
|
178
|
-
mergeConfig(result, stripSelectors(local));
|
|
179
175
|
}
|
|
180
176
|
/** Every layer has had its turn, so an append still outstanding has nothing left to attach to
|
|
181
177
|
* and becomes the value itself. Done here rather than per layer: until the chain is finished,
|
|
182
178
|
* the key it appends to may still be coming. */
|
|
183
179
|
return finalizeConfig(result);
|
|
184
180
|
}
|
|
185
|
-
/** A config key naming packages rather than settings: `"[*]"`, `"[/]"`, `"[
|
|
181
|
+
/** A config key naming packages rather than settings: `"[*]"`, `"[/]"`, `"[pkg-a]"`. The
|
|
186
182
|
* brackets are what keep this space from colliding with real config keys - no setting starts with
|
|
187
183
|
* one - and in YAML they also mean the key always needs quoting (`"[*]":`), since a bare `[*]`
|
|
188
184
|
* parses as a flow sequence. */
|
|
@@ -190,50 +186,55 @@ export function isSelectorKey(key) {
|
|
|
190
186
|
return key.length > 2 && key.startsWith('[') && key.endsWith(']');
|
|
191
187
|
}
|
|
192
188
|
/**
|
|
193
|
-
* **Which packages a selector speaks for.**
|
|
189
|
+
* **Which packages a selector speaks for.** Two audiences, and the second is a glob:
|
|
194
190
|
*
|
|
195
191
|
* | | |
|
|
196
192
|
* | --- | --- |
|
|
197
|
-
* | `"[/]"` | the **root package**
|
|
198
|
-
* | `"[*]"`, `"[pkg-a]"`, `"[*-dialect]"` | **
|
|
199
|
-
* | `"[ws:*]"`, `"[workspace:pkg-*]"` | every **non-root** package the glob matches |
|
|
193
|
+
* | `"[/]"` | the **root package** alone |
|
|
194
|
+
* | `"[*]"`, `"[pkg-a]"`, `"[*-dialect]"` | the packages **below** this directory that the glob matches |
|
|
200
195
|
*
|
|
201
196
|
* `/` for the root because that is what a repository root is called everywhere else, and it cannot
|
|
202
|
-
* collide with a package name.
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
197
|
+
* collide with a package name.
|
|
198
|
+
*
|
|
199
|
+
* **The root is never selected by name, and that one rule removes two traps.** A glob matches
|
|
200
|
+
* package names, and the root is nobody's child - so `"[my-*]"` cannot quietly pick up a repository
|
|
201
|
+
* whose root package happens to be called `my-repo`, and `"[*]"` cannot hand a package-shaped
|
|
202
|
+
* setting to a root that has no build directory to apply it to. The root is addressed structurally
|
|
203
|
+
* or not at all.
|
|
204
|
+
*
|
|
205
|
+
* **`"[ws:*]"` / `"[workspace:*]"` is accepted and means exactly `"[*]"`.** The qualifier existed to
|
|
206
|
+
* say "not the root" back when a bare glob included it; the shape of the set says that now, so it
|
|
207
|
+
* has nothing left to add. Accepted rather than rejected because the two spellings resolve to the
|
|
208
|
+
* same packages - an error would be friction with no reader to protect.
|
|
209
209
|
*/
|
|
210
210
|
export function parseSelector(key) {
|
|
211
211
|
const inner = key.slice(1, -1);
|
|
212
212
|
if (inner === ROOT_SELECTOR_INNER)
|
|
213
213
|
return { scope: 'root', test: () => true };
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const re = globToRegExp(inner.slice(prefix.length));
|
|
217
|
-
return { scope: 'workspace', test: name => re.test(name) };
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
const re = globToRegExp(inner);
|
|
221
|
-
return { scope: 'all', test: name => re.test(name) };
|
|
214
|
+
const re = globToRegExp(stripWorkspacePrefix(inner));
|
|
215
|
+
return { scope: 'package', test: name => re.test(name) };
|
|
222
216
|
}
|
|
223
217
|
/** The glob inside a selector key, as a `RegExp` anchored at both ends - so `"[*-dialect]"` matches
|
|
224
218
|
* `mysql-dialect` but not `my-dialect-helper`. Glob rather than regex, to match every other
|
|
225
219
|
* pattern in rman (`allowBranch`, `changelog.tagPattern`, `clean.include`). */
|
|
226
220
|
export function selectorToRegExp(key) {
|
|
227
|
-
return globToRegExp(key.slice(1, -1));
|
|
221
|
+
return globToRegExp(stripWorkspacePrefix(key.slice(1, -1)));
|
|
228
222
|
}
|
|
229
223
|
/**
|
|
230
|
-
* Every selector block in `config` that speaks for this package, in
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
224
|
+
* Every selector block in `config` that speaks for this package, **in the order they were written**
|
|
225
|
+
* - later wins, the way `overrides` works in eslint, prettier and babel, and the way a `.gitignore`
|
|
226
|
+
* rule does.
|
|
227
|
+
*
|
|
228
|
+
* **There used to be a ranking** (`"[*]"` lowest, then a catch-all `"[ws:*]"`, then the rest by
|
|
229
|
+
* declaration), so that "everything" could not beat a rule about one package by being written last.
|
|
230
|
+
* It was dropped because the ordering it implies does not exist: specificity only ranks sets that
|
|
231
|
+
* nest, and globs do not. For a package called `pkg-dialect`, neither `"[pkg-*]"` nor
|
|
232
|
+
* `"[*-dialect]"` contains the other, so any answer is an invented tiebreak - and an invented
|
|
233
|
+
* tiebreak is worse than the order the author typed. What was left was already declaration order
|
|
234
|
+
* with one case lifted out of it; this removes the exception rather than generalizing it.
|
|
235
|
+
*
|
|
236
|
+
* The cost, which the docs state rather than hide: a catch-all written *below* a narrower block now
|
|
237
|
+
* overrides it. Writing catch-alls first is a convention, not a rule - the file reads top to bottom.
|
|
237
238
|
*/
|
|
238
239
|
function matchingSelectors(config, packageName, isRoot) {
|
|
239
240
|
const matches = [];
|
|
@@ -241,23 +242,19 @@ function matchingSelectors(config, packageName, isRoot) {
|
|
|
241
242
|
if (!isSelectorKey(key) || !value || typeof value !== 'object')
|
|
242
243
|
continue;
|
|
243
244
|
const { scope, test } = parseSelector(key);
|
|
244
|
-
if (scope === 'root'
|
|
245
|
+
if (scope === 'root' ? !isRoot : isRoot || !test(packageName))
|
|
245
246
|
continue;
|
|
246
|
-
|
|
247
|
-
continue;
|
|
248
|
-
if (!test(packageName))
|
|
249
|
-
continue;
|
|
250
|
-
matches.push([selectorRank(key), value]);
|
|
247
|
+
matches.push(value);
|
|
251
248
|
}
|
|
252
|
-
return matches
|
|
249
|
+
return matches;
|
|
253
250
|
}
|
|
254
|
-
/**
|
|
255
|
-
*
|
|
256
|
-
function
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return
|
|
251
|
+
/** `"[ws:*]"` and `"[workspace:*]"` are the pre-2.x spelling of "not the root", kept working
|
|
252
|
+
* because they now name the same set a bare glob does. Stripped here so one code path serves both. */
|
|
253
|
+
function stripWorkspacePrefix(inner) {
|
|
254
|
+
for (const prefix of WORKSPACE_PREFIXES)
|
|
255
|
+
if (inner.startsWith(prefix))
|
|
256
|
+
return inner.slice(prefix.length);
|
|
257
|
+
return inner;
|
|
261
258
|
}
|
|
262
259
|
function globToRegExp(glob) {
|
|
263
260
|
const source = glob
|
|
@@ -273,12 +270,10 @@ function stripSelectors(config) {
|
|
|
273
270
|
result[key] = value;
|
|
274
271
|
return result;
|
|
275
272
|
}
|
|
276
|
-
const CATCH_ALL = '[*]';
|
|
277
273
|
/** `"[/]"` - the root package, spelled the way a repository root is spelled everywhere else, and
|
|
278
274
|
* unable to collide with a package name. */
|
|
279
275
|
const ROOT_SELECTOR_INNER = '/';
|
|
280
|
-
/**
|
|
281
|
-
* someone else has to understand; the short one is what gets typed. */
|
|
276
|
+
/** Accepted spellings of the retired "not the root" qualifier - see `stripWorkspacePrefix`. */
|
|
282
277
|
const WORKSPACE_PREFIXES = ['workspace:', 'ws:'];
|
|
283
278
|
function dirChain(rootDir, targetDir) {
|
|
284
279
|
const rel = path.relative(rootDir, targetDir);
|
|
@@ -399,7 +394,7 @@ export const DEFERRED_PATHS = ['version.before', 'version.exec', 'version.after'
|
|
|
399
394
|
* config:
|
|
400
395
|
*
|
|
401
396
|
* ```js
|
|
402
|
-
* '[
|
|
397
|
+
* '[*]': {
|
|
403
398
|
* clean: { include: ({ vars, value }) => [...value, vars.buildDir] }, // a value: called here
|
|
404
399
|
* run: { build: { after: ({ pkg }) => copyDocs(pkg) } }, // a step: called by `run`
|
|
405
400
|
* }
|
package/core/merge-config.js
CHANGED
|
@@ -178,7 +178,7 @@ function assignMerged(target, key, value, source, origin) {
|
|
|
178
178
|
*
|
|
179
179
|
* ```js
|
|
180
180
|
* '[*]': { clean: { include: ({ vars }) => [vars.buildDir] } }
|
|
181
|
-
* '[
|
|
181
|
+
* '[*]': { clean: { include: "${{ [...value, pkg.basename + '.log'] }}" } }
|
|
182
182
|
* ```
|
|
183
183
|
*
|
|
184
184
|
* Chained here rather than at resolution time because only the merge knows the order of the
|
package/core/repository.js
CHANGED
|
@@ -208,9 +208,10 @@ export class Repository extends Package {
|
|
|
208
208
|
* second `rawConfig` copy of every package's config for that one reader; measured identical.
|
|
209
209
|
*/
|
|
210
210
|
/**
|
|
211
|
-
* The root is resolved **with its name**, like every other package
|
|
212
|
-
*
|
|
213
|
-
*
|
|
211
|
+
* The root is resolved **with its name**, like every other package. Not because a glob could
|
|
212
|
+
* match it - `"[*]"` and every other name pattern speak only to the packages below - but because
|
|
213
|
+
* `resolveConfig` needs a name to run `matchingSelectors` at all, and `"[/]"` is a selector.
|
|
214
|
+
* Passing none would silently drop the root's own block.
|
|
214
215
|
*/
|
|
215
216
|
const rootRaw = await resolveConfig(this.dirname, this.dirname, cache, this.rootPackage.name);
|
|
216
217
|
this.config = interpolateConfig(rootRaw, this.configScope(this.rootPackage), { skip: DEFERRED_PATHS });
|
|
@@ -166,17 +166,21 @@ export interface RmanConfigKeys {
|
|
|
166
166
|
*/
|
|
167
167
|
dependencies?: string[];
|
|
168
168
|
/**
|
|
169
|
-
* Config for **
|
|
170
|
-
* package
|
|
171
|
-
* Everything else in this object
|
|
172
|
-
*
|
|
173
|
-
*
|
|
169
|
+
* Config for a **narrower audience**, keyed by a `"[selector]"` naming it - `"[/]"` for the root
|
|
170
|
+
* package alone, `"[*]"` for the packages below this directory, `"[*-dialect]"` for a glob over
|
|
171
|
+
* their names, `"[pkg-a]"` for one. Everything else in this object reaches this directory *and*
|
|
172
|
+
* every package under it, so a selector is how a statement stops being everyone's.
|
|
173
|
+
*
|
|
174
|
+
* A glob never matches the root, which is nobody's child - so a package-shaped setting cannot
|
|
175
|
+
* reach a root that has no package directory to apply it to, and `"[/]"` is the only way to
|
|
176
|
+
* address the root.
|
|
174
177
|
*
|
|
175
178
|
* ```yaml
|
|
176
179
|
* # the repository root's own .rmanrc.yml
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
+
* "[/]":
|
|
181
|
+
* run:
|
|
182
|
+
* build:
|
|
183
|
+
* before: node support/generate.cjs # a repo-wide bookend, run once at the root
|
|
180
184
|
* "[*]":
|
|
181
185
|
* run:
|
|
182
186
|
* build:
|
|
@@ -184,8 +188,8 @@ export interface RmanConfigKeys {
|
|
|
184
188
|
* ```
|
|
185
189
|
*
|
|
186
190
|
* In YAML the quotes are **required**: a bare `[*]` parses as a flow sequence, and `*` as an
|
|
187
|
-
* alias indicator. Precedence
|
|
188
|
-
*
|
|
191
|
+
* alias indicator. Precedence: the unmarked keys first, then these blocks **in the order they
|
|
192
|
+
* were written** - later wins. A directory level closer to the package wins over all of them.
|
|
189
193
|
*
|
|
190
194
|
* Recursive, mirroring the schema's own `"$ref": "#"`: whatever a `.rmanrc` may say about its own
|
|
191
195
|
* package it may say here about the ones it names - nested selectors included. Typed as
|