@fynpo/base 1.1.22 → 2.0.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/README.md +62 -1
- package/dist/caching.d.ts +4 -4
- package/dist/caching.js +30 -38
- package/dist/fynpo-config.js +38 -21
- package/dist/fynpo-dep-graph.d.ts +28 -2
- package/dist/fynpo-dep-graph.js +109 -50
- package/dist/gitignore.d.ts +17 -0
- package/dist/gitignore.js +67 -0
- package/dist/index.d.ts +18 -7
- package/dist/index.js +158 -66
- package/dist/minimatch-group.d.ts +10 -10
- package/dist/minimatch-group.js +15 -18
- package/dist/packages-config.d.ts +78 -0
- package/dist/packages-config.js +149 -0
- package/dist/util.js +2 -7
- package/package.json +42 -18
- package/dist/caching.js.map +0 -1
- package/dist/fynpo-config.js.map +0 -1
- package/dist/fynpo-dep-graph.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/minimatch-group.js.map +0 -1
- package/dist/util.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
tslib_1.__exportStar(require("./util"), exports);
|
|
16
|
-
exports.caching = tslib_1.__importStar(require("./caching"));
|
|
1
|
+
import Path from "path";
|
|
2
|
+
import { promises as Fs } from "fs";
|
|
3
|
+
import { filterScanDir } from "filter-scan-dir";
|
|
4
|
+
import { Minimatch } from "minimatch";
|
|
5
|
+
import _ from "lodash";
|
|
6
|
+
import { groupMM } from "./minimatch-group.js";
|
|
7
|
+
import { resolvePackagesConfig, scanPatterns, includeFilter, outOfScopePackages, } from "./packages-config.js";
|
|
8
|
+
import { makeGitignoreMatcher } from "./gitignore.js";
|
|
9
|
+
export * from "./fynpo-dep-graph.js";
|
|
10
|
+
export * from "./fynpo-config.js";
|
|
11
|
+
export * from "./packages-config.js";
|
|
12
|
+
export * from "./gitignore.js";
|
|
13
|
+
export * from "./util.js";
|
|
14
|
+
export * as caching from "./caching.js";
|
|
17
15
|
/**
|
|
18
16
|
* Take an array of packages and figure out their dependencies on each other
|
|
19
17
|
*
|
|
@@ -22,7 +20,7 @@ exports.caching = tslib_1.__importStar(require("./caching"));
|
|
|
22
20
|
function processDirectDeps(packages) {
|
|
23
21
|
const add = (name, deps, type) => {
|
|
24
22
|
const depPkg = packages[name];
|
|
25
|
-
|
|
23
|
+
_.each(deps, (semver, depName) => {
|
|
26
24
|
if (!packages.hasOwnProperty(depName)) {
|
|
27
25
|
return;
|
|
28
26
|
}
|
|
@@ -31,7 +29,7 @@ function processDirectDeps(packages) {
|
|
|
31
29
|
depPkg.localDepsByType[type].push(depName);
|
|
32
30
|
});
|
|
33
31
|
};
|
|
34
|
-
|
|
32
|
+
_.each(packages, (pkg, name) => {
|
|
35
33
|
add(name, pkg.dependencies, "dep");
|
|
36
34
|
add(name, pkg.devDependencies, "dev");
|
|
37
35
|
add(name, pkg.optionalDependencies, "opt");
|
|
@@ -44,31 +42,81 @@ function processDirectDeps(packages) {
|
|
|
44
42
|
* @param circulars - array of package pairs that depend on each other
|
|
45
43
|
*/
|
|
46
44
|
function processIndirectDeps(packages, circulars) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
//
|
|
46
|
+
// Membership used to be `Array.indexOf` over localDeps / indirectDeps / circulars, and
|
|
47
|
+
// both the walk and the fixpoint were recursive. That is what made a cycle fatal before
|
|
48
|
+
// FPO-19, and it stayed expensive afterwards: a 500-package chain took ~17s to resolve,
|
|
49
|
+
// and a deep enough graph could still exhaust the stack through the walk alone, cycle or
|
|
50
|
+
// no cycle. Sets for membership and explicit stacks for both loops (FPO-43).
|
|
51
|
+
//
|
|
52
|
+
// The arrays are still the output, appended in the same discovery order as before - the
|
|
53
|
+
// Sets only answer "already have it?" without an O(n) scan.
|
|
54
|
+
//
|
|
55
|
+
const localDepsSet = new Map();
|
|
56
|
+
const indirectDepsSet = new Map();
|
|
57
|
+
const circularsSet = new Set(circulars);
|
|
58
|
+
_.each(packages, (pkg, name) => {
|
|
59
|
+
localDepsSet.set(name, new Set(pkg.localDeps));
|
|
60
|
+
indirectDepsSet.set(name, new Set(pkg.indirectDeps));
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Accumulate every package reachable from `info` into its indirectDeps.
|
|
64
|
+
*
|
|
65
|
+
* Depth-first over a snapshot of each package's deps, taken as it is reached - the same
|
|
66
|
+
* order the recursive walk produced. `seen` expands each package once per traversal,
|
|
67
|
+
* which is all a transitive closure needs and is what keeps a cycle from looping.
|
|
68
|
+
*
|
|
69
|
+
* @param info the package whose indirect deps we are accumulating
|
|
70
|
+
* @returns how many indirect deps were added
|
|
71
|
+
*/
|
|
72
|
+
const add = (info) => {
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
const infoIndirect = indirectDepsSet.get(info.name);
|
|
75
|
+
const infoLocal = localDepsSet.get(info.name);
|
|
76
|
+
let added = 0;
|
|
77
|
+
// each frame is a dep list plus how far into it we have gone
|
|
78
|
+
const stack = [
|
|
79
|
+
{ deps: info.localDeps.concat(info.indirectDeps), at: 0 },
|
|
80
|
+
];
|
|
81
|
+
while (stack.length > 0) {
|
|
82
|
+
const frame = stack[stack.length - 1];
|
|
83
|
+
if (frame.at >= frame.deps.length) {
|
|
84
|
+
stack.pop();
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const dep = frame.deps[frame.at++];
|
|
50
88
|
const depPkg = packages[dep];
|
|
51
|
-
if (
|
|
52
|
-
|
|
89
|
+
if (!infoLocal.has(dep) && !infoIndirect.has(dep)) {
|
|
90
|
+
added++;
|
|
53
91
|
info.indirectDeps.push(dep);
|
|
92
|
+
infoIndirect.add(dep);
|
|
54
93
|
depPkg.dependents.push(info.name);
|
|
55
94
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
95
|
+
// a cycle that comes straight back to `info` - record the pair and stop descending
|
|
96
|
+
if (localDepsSet.get(dep).has(info.name)) {
|
|
97
|
+
const pair = [info.name, depPkg.name].sort().join(",");
|
|
98
|
+
if (!circularsSet.has(pair)) {
|
|
99
|
+
circularsSet.add(pair);
|
|
100
|
+
circulars.push(pair);
|
|
60
101
|
}
|
|
61
|
-
|
|
102
|
+
continue;
|
|
62
103
|
}
|
|
63
|
-
|
|
64
|
-
|
|
104
|
+
if (seen.has(dep)) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
seen.add(dep);
|
|
108
|
+
stack.push({ deps: depPkg.localDeps.concat(depPkg.indirectDeps), at: 0 });
|
|
109
|
+
}
|
|
110
|
+
return added;
|
|
65
111
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
112
|
+
// run to a fixpoint: expanding one package can give another package more to reach through
|
|
113
|
+
let change = 0;
|
|
114
|
+
do {
|
|
115
|
+
change = 0;
|
|
116
|
+
_.each(packages, (pkg) => {
|
|
117
|
+
change += add(pkg);
|
|
118
|
+
});
|
|
119
|
+
} while (change > 0);
|
|
72
120
|
}
|
|
73
121
|
/**
|
|
74
122
|
*
|
|
@@ -76,7 +124,7 @@ function processIndirectDeps(packages, circulars) {
|
|
|
76
124
|
* @param level
|
|
77
125
|
*/
|
|
78
126
|
function includeDeps(packages, level) {
|
|
79
|
-
const localDeps =
|
|
127
|
+
const localDeps = _.uniq(Object.keys(packages).reduce((acc, p) => {
|
|
80
128
|
if (packages[p] && !packages[p].ignore) {
|
|
81
129
|
return acc.concat(packages[p].localDeps.filter((x) => packages[x] && packages[x].ignore));
|
|
82
130
|
}
|
|
@@ -97,35 +145,72 @@ function includeDeps(packages, level) {
|
|
|
97
145
|
/**
|
|
98
146
|
* Read the packages of a fynpo mono-repo
|
|
99
147
|
*
|
|
100
|
-
* @
|
|
148
|
+
* Honors the same `packages` config as {@link FynpoDepGraph}, so both discovery paths agree.
|
|
149
|
+
* Passing `patterns` directly still works and takes precedence, for callers that already know
|
|
150
|
+
* what they want.
|
|
151
|
+
*
|
|
152
|
+
* @param patterns - explicit minimatch patterns. Overrides whatever `packages` config says.
|
|
153
|
+
* @param cwd - repo root
|
|
154
|
+
* @param packages - raw `packages` config, resolved via {@link resolvePackagesConfig}
|
|
101
155
|
* @returns - packages from the fynpo mono-repo
|
|
102
156
|
*/
|
|
103
|
-
async function readFynpoPackages({ patterns =
|
|
104
|
-
const
|
|
105
|
-
const
|
|
157
|
+
export async function readFynpoPackages({ patterns = undefined, cwd = process.cwd(), packages = undefined, } = {}) {
|
|
158
|
+
const config = resolvePackagesConfig(packages);
|
|
159
|
+
const explicit = _.isEmpty(patterns) ? scanPatterns(config) : patterns;
|
|
160
|
+
const gitignore = makeGitignoreMatcher(cwd);
|
|
161
|
+
const excludeMms = config.exclude.map((p) => new Minimatch(p));
|
|
162
|
+
const isExcluded = (path) => Boolean(path) && excludeMms.some((m) => m.match(path.split(Path.sep).join("/")));
|
|
163
|
+
// `include` filters what the scan found - it does not replace the scan (FPO-17)
|
|
164
|
+
const includeMms = (_.isEmpty(patterns) ? includeFilter(config) : []).map((p) => new Minimatch(p));
|
|
165
|
+
const isIncluded = (path) => includeMms.length === 0 || includeMms.some((m) => m.match(path.split(Path.sep).join("/")));
|
|
166
|
+
// null patterns means auto-search: scan from the root for every package.json
|
|
167
|
+
const autoSearch = explicit === null;
|
|
168
|
+
const groups = autoSearch
|
|
169
|
+
? { ".": null }
|
|
170
|
+
: groupMM(explicit.map((p) => new Minimatch(p)), {});
|
|
171
|
+
const skipForAutoSearch = (path) => autoSearch && config.autoSearch.respectGitignore && gitignore.ignores(path);
|
|
106
172
|
const files = [];
|
|
107
173
|
for (const prefix in groups) {
|
|
108
|
-
files.push(await
|
|
174
|
+
files.push(await filterScanDir({
|
|
109
175
|
cwd,
|
|
110
176
|
prefix,
|
|
111
177
|
concurrency: 500,
|
|
112
|
-
filter: (f) =>
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
return
|
|
178
|
+
filter: (f, path, extras) => {
|
|
179
|
+
var _a;
|
|
180
|
+
if (f !== "package.json") {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
if (autoSearch && (!path || path === ".")) {
|
|
184
|
+
// the monorepo's own package.json is not a member
|
|
185
|
+
return false;
|
|
116
186
|
}
|
|
117
|
-
|
|
187
|
+
if (autoSearch && ((_a = extras === null || extras === void 0 ? void 0 : extras.files) === null || _a === void 0 ? void 0 : _a.includes("fynpo.json"))) {
|
|
188
|
+
// a nested fynpo root is its own monorepo
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
return !isExcluded(path) && !skipForAutoSearch(path);
|
|
192
|
+
},
|
|
193
|
+
filterDir: (dir, path, extras) => {
|
|
194
|
+
if (dir === "node_modules" || isExcluded(path) || skipForAutoSearch(path)) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
if (autoSearch) {
|
|
198
|
+
return !dir.startsWith(".");
|
|
199
|
+
}
|
|
200
|
+
return Boolean(groups[prefix].find((save) => save.mm.match(extras.dirFile)));
|
|
118
201
|
},
|
|
119
202
|
}));
|
|
120
203
|
}
|
|
121
|
-
const allFiles = [].concat(...files)
|
|
204
|
+
const allFiles = [].concat(...files)
|
|
205
|
+
.filter((f) => isIncluded(Path.dirname(f)))
|
|
206
|
+
.sort();
|
|
122
207
|
const allPkgs = {};
|
|
123
208
|
for (const pkgFile of allFiles) {
|
|
124
|
-
const pkgStr = await
|
|
209
|
+
const pkgStr = await Fs.readFile(Path.join(cwd, pkgFile), "utf-8");
|
|
125
210
|
const pkgJson = JSON.parse(pkgStr);
|
|
126
|
-
const path =
|
|
127
|
-
const pkgDir = pkgJson.name[0] === "@" && path.endsWith(pkgJson.name) ? pkgJson.name :
|
|
128
|
-
allPkgs[pkgJson.name] = Object.assign(
|
|
211
|
+
const path = Path.dirname(pkgFile);
|
|
212
|
+
const pkgDir = pkgJson.name[0] === "@" && path.endsWith(pkgJson.name) ? pkgJson.name : Path.basename(path);
|
|
213
|
+
allPkgs[pkgJson.name] = Object.assign(_.pick(pkgJson, [
|
|
129
214
|
"name",
|
|
130
215
|
"version",
|
|
131
216
|
"dependencies",
|
|
@@ -162,7 +247,7 @@ async function readFynpoPackages({ patterns = ["packages/*"], cwd = process.cwd(
|
|
|
162
247
|
* @param opts - options
|
|
163
248
|
* @returns
|
|
164
249
|
*/
|
|
165
|
-
function makePkgDeps(packages, opts) {
|
|
250
|
+
export function makePkgDeps(packages, opts) {
|
|
166
251
|
const cwd = opts.cwd || process.cwd();
|
|
167
252
|
let circulars = [];
|
|
168
253
|
let ignores = opts.ignore || [];
|
|
@@ -180,14 +265,11 @@ function makePkgDeps(packages, opts) {
|
|
|
180
265
|
}
|
|
181
266
|
}
|
|
182
267
|
// If options.scope is defined, then ignore packages not in it
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
}
|
|
268
|
+
outOfScopePackages(opts.scope, Object.keys(packages)).forEach((p) => {
|
|
269
|
+
if (!ignores[p]) {
|
|
270
|
+
ignores.push(p);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
191
273
|
if (opts.only && opts.only.length > 0) {
|
|
192
274
|
opts.only.forEach((x) => {
|
|
193
275
|
if (!packages[x]) {
|
|
@@ -200,17 +282,28 @@ function makePkgDeps(packages, opts) {
|
|
|
200
282
|
}
|
|
201
283
|
});
|
|
202
284
|
}
|
|
203
|
-
const depMap =
|
|
204
|
-
return
|
|
285
|
+
const depMap = _.mapValues(packages, (pkg) => {
|
|
286
|
+
return _.pick(pkg, ["name", "localDeps", "indirectDeps", "dependents"]);
|
|
205
287
|
});
|
|
206
|
-
circulars =
|
|
207
|
-
|
|
288
|
+
circulars = _.uniq(circulars).map((x) => x.split(","));
|
|
289
|
+
// Breaking a cycle costs a package: the less depended-on half of each pair is dropped from
|
|
290
|
+
// the run. That used to happen in silence, so a repo with cycles quietly processed fewer
|
|
291
|
+
// packages than it has and nothing said which ones or why (FPO-43).
|
|
292
|
+
const circularIgnores = _.uniq(_.map(circulars, (pair) => {
|
|
208
293
|
const depA = packages[pair[0]].dependents.length;
|
|
209
294
|
const depB = packages[pair[1]].dependents.length;
|
|
210
295
|
if (depA === depB)
|
|
211
296
|
return undefined;
|
|
212
297
|
return depA > depB ? pair[1] : pair[0];
|
|
213
298
|
}).filter((x) => x));
|
|
299
|
+
if (circulars.length > 0) {
|
|
300
|
+
warnings.push(`Circular local dependencies: ${circulars.map((pair) => pair.join(" <-> ")).join(", ")}`);
|
|
301
|
+
if (circularIgnores.length > 0) {
|
|
302
|
+
warnings.push(`Ignoring ${circularIgnores.join(", ")} to break the circular dependencies above - ` +
|
|
303
|
+
`they are dropped from this run. Break the cycles to include them.`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
ignores = ignores.concat(circularIgnores);
|
|
214
307
|
ignores.forEach((x) => {
|
|
215
308
|
if (packages[x]) {
|
|
216
309
|
packages[x].ignore = true;
|
|
@@ -231,4 +324,3 @@ function makePkgDeps(packages, opts) {
|
|
|
231
324
|
focusPkgPath,
|
|
232
325
|
};
|
|
233
326
|
}
|
|
234
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Minimatch, type ParseReturnFiltered } from "minimatch";
|
|
2
2
|
/**
|
|
3
3
|
* Remember the minimatch group info from a pattern
|
|
4
4
|
*/
|
|
5
5
|
type MMGroup = {
|
|
6
6
|
/** the minimatch object */
|
|
7
|
-
mm:
|
|
8
|
-
/**
|
|
9
|
-
set:
|
|
7
|
+
mm: Minimatch;
|
|
8
|
+
/** one expanded pattern set (a row of Minimatch.set) */
|
|
9
|
+
set: ParseReturnFiltered[];
|
|
10
10
|
/** index of the set within the minimatch object */
|
|
11
11
|
setIx: number;
|
|
12
12
|
/** index of the first set that's not a literal string */
|
|
@@ -22,16 +22,16 @@ export type MMGroups = Record<string, MMGroup[]>;
|
|
|
22
22
|
* @param groups - object to group the minimatch objects
|
|
23
23
|
* @returns object of grouped minimatch objects
|
|
24
24
|
*/
|
|
25
|
-
export declare function groupMM(mms:
|
|
25
|
+
export declare function groupMM(mms: Minimatch[], groups: MMGroups): MMGroups;
|
|
26
26
|
/**
|
|
27
27
|
* process a minimatch pattern to group them for matching directories
|
|
28
28
|
*
|
|
29
29
|
* - needs to create a new pattern at every non-string part
|
|
30
30
|
* @param m0 minimatch pattern
|
|
31
31
|
*/
|
|
32
|
-
export declare function deconstructMM(m0:
|
|
33
|
-
m0:
|
|
34
|
-
mms:
|
|
32
|
+
export declare function deconstructMM(m0: Minimatch): {
|
|
33
|
+
m0: Minimatch;
|
|
34
|
+
mms: Minimatch[];
|
|
35
35
|
};
|
|
36
36
|
/**
|
|
37
37
|
* check that a path matches against a list of minimatch patterns
|
|
@@ -40,7 +40,7 @@ export declare function deconstructMM(m0: mm.IMinimatch): {
|
|
|
40
40
|
* @param patterns
|
|
41
41
|
* @returns the first pattern that match or false
|
|
42
42
|
*/
|
|
43
|
-
export declare function checkMmMatch(fullPath: string, patterns:
|
|
43
|
+
export declare function checkMmMatch(fullPath: string, patterns: Minimatch[]): false | Minimatch;
|
|
44
44
|
/**
|
|
45
45
|
* Take a full path and match each level of it to a list of minimatch patterns
|
|
46
46
|
*
|
|
@@ -48,5 +48,5 @@ export declare function checkMmMatch(fullPath: string, patterns: mm.IMinimatch[]
|
|
|
48
48
|
* @param mms
|
|
49
49
|
* @returns
|
|
50
50
|
*/
|
|
51
|
-
export declare function unrollMmMatch(path: string, mms:
|
|
51
|
+
export declare function unrollMmMatch(path: string, mms: Minimatch[]): false | Minimatch;
|
|
52
52
|
export {};
|
package/dist/minimatch-group.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.groupMM = groupMM;
|
|
4
|
-
exports.deconstructMM = deconstructMM;
|
|
5
|
-
exports.checkMmMatch = checkMmMatch;
|
|
6
|
-
exports.unrollMmMatch = unrollMmMatch;
|
|
7
|
-
const tslib_1 = require("tslib");
|
|
8
|
-
const minimatch_1 = tslib_1.__importDefault(require("minimatch"));
|
|
9
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
1
|
+
import { Minimatch, GLOBSTAR } from "minimatch";
|
|
2
|
+
import _ from "lodash";
|
|
10
3
|
/**
|
|
11
4
|
* process a list of minimatch objects and group them by the string prefix of their patterns
|
|
12
5
|
*
|
|
@@ -14,7 +7,7 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
|
14
7
|
* @param groups - object to group the minimatch objects
|
|
15
8
|
* @returns object of grouped minimatch objects
|
|
16
9
|
*/
|
|
17
|
-
function groupMM(mms, groups) {
|
|
10
|
+
export function groupMM(mms, groups) {
|
|
18
11
|
mms.forEach((mm) => {
|
|
19
12
|
mm.set.forEach((set, setIx) => {
|
|
20
13
|
const ix = set.findIndex((s) => typeof s !== "string");
|
|
@@ -43,20 +36,19 @@ function groupMM(mms, groups) {
|
|
|
43
36
|
* - needs to create a new pattern at every non-string part
|
|
44
37
|
* @param m0 minimatch pattern
|
|
45
38
|
*/
|
|
46
|
-
function deconstructMM(m0) {
|
|
39
|
+
export function deconstructMM(m0) {
|
|
47
40
|
const mms = [];
|
|
48
41
|
const patterns = { m0, mms };
|
|
49
42
|
const set = m0.set[0];
|
|
50
43
|
const globParts = m0.globParts[0];
|
|
51
44
|
const iParts = [];
|
|
52
|
-
const { GLOBSTAR } = minimatch_1.default;
|
|
53
45
|
for (let ix = 0; ix < set.length; ix++) {
|
|
54
46
|
const s = set[ix];
|
|
55
47
|
const g = globParts[ix];
|
|
56
48
|
// if we hit something that's not string, then we need a mm with just the strings
|
|
57
49
|
// because a dir like "src" will not match "src/*"
|
|
58
50
|
if (typeof s !== "string" && iParts.length > 0) {
|
|
59
|
-
mms.push(new
|
|
51
|
+
mms.push(new Minimatch(iParts.join("/"), m0.options));
|
|
60
52
|
}
|
|
61
53
|
if (ix === set.length - 1) {
|
|
62
54
|
mms.push(m0);
|
|
@@ -65,7 +57,7 @@ function deconstructMM(m0) {
|
|
|
65
57
|
else {
|
|
66
58
|
iParts.push(g);
|
|
67
59
|
if (typeof s !== "string") {
|
|
68
|
-
mms.push(new
|
|
60
|
+
mms.push(new Minimatch(iParts.join("/"), m0.options));
|
|
69
61
|
}
|
|
70
62
|
}
|
|
71
63
|
if (s === GLOBSTAR) {
|
|
@@ -82,8 +74,14 @@ function deconstructMM(m0) {
|
|
|
82
74
|
* @param patterns
|
|
83
75
|
* @returns the first pattern that match or false
|
|
84
76
|
*/
|
|
85
|
-
function checkMmMatch(fullPath, patterns) {
|
|
86
|
-
|
|
77
|
+
export function checkMmMatch(fullPath, patterns) {
|
|
78
|
+
// Callers append a trailing "/" to force matching a directory. minimatch 3 never let a
|
|
79
|
+
// pattern part that can match the empty string (e.g. "?(a|b)") consume that trailing empty
|
|
80
|
+
// segment, but minimatch 10 does, so "**/?(a|b)" would wrongly match "src/". For every
|
|
81
|
+
// other case v3's match of "dir/" is equivalent to matching "dir", so strip the trailing
|
|
82
|
+
// slash to keep the v3 semantics.
|
|
83
|
+
const path = fullPath.length > 1 && fullPath.endsWith("/") ? fullPath.slice(0, -1) : fullPath;
|
|
84
|
+
return !_.isEmpty(patterns) && patterns.find((patternMm) => patternMm.match(path));
|
|
87
85
|
}
|
|
88
86
|
/**
|
|
89
87
|
* Take a full path and match each level of it to a list of minimatch patterns
|
|
@@ -92,7 +90,7 @@ function checkMmMatch(fullPath, patterns) {
|
|
|
92
90
|
* @param mms
|
|
93
91
|
* @returns
|
|
94
92
|
*/
|
|
95
|
-
function unrollMmMatch(path, mms) {
|
|
93
|
+
export function unrollMmMatch(path, mms) {
|
|
96
94
|
const parts = path.split("/");
|
|
97
95
|
let rp;
|
|
98
96
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
@@ -104,4 +102,3 @@ function unrollMmMatch(path, mms) {
|
|
|
104
102
|
}
|
|
105
103
|
return checkMmMatch(path, mms);
|
|
106
104
|
}
|
|
107
|
-
//# sourceMappingURL=minimatch-group.js.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** auto-search settings, after defaults are applied */
|
|
2
|
+
export type AutoSearchConfig = {
|
|
3
|
+
/** search the whole repo for package.json when no explicit `include` patterns are given */
|
|
4
|
+
enable: boolean;
|
|
5
|
+
/** when true, auto-search skips gitignored paths. Does NOT affect the publish veto. */
|
|
6
|
+
respectGitignore: boolean;
|
|
7
|
+
};
|
|
8
|
+
/** the `packages` config, after defaults are applied */
|
|
9
|
+
export type PackagesConfig = {
|
|
10
|
+
autoSearch: AutoSearchConfig;
|
|
11
|
+
/** explicit discovery patterns. Empty means "not specified" */
|
|
12
|
+
include: string[];
|
|
13
|
+
/** applies to every package, auto-searched or explicitly matched */
|
|
14
|
+
exclude: string[];
|
|
15
|
+
/** publish allow list. Empty means every discovered package is eligible */
|
|
16
|
+
publishInclude: string[];
|
|
17
|
+
/** publish deny list, applied after the allow list */
|
|
18
|
+
publishExclude: string[];
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Normalize `packages` from a fynpo config into a complete {@link PackagesConfig}.
|
|
22
|
+
*
|
|
23
|
+
* Accepts both shapes:
|
|
24
|
+
*
|
|
25
|
+
* - **array** - the historical form. Treated as `publishInclude`, with auto-search on and
|
|
26
|
+
* `respectGitignore` off. It no longer narrows discovery.
|
|
27
|
+
* - **object** - `{ autoSearch, include, exclude, publishInclude, publishExclude }`.
|
|
28
|
+
*
|
|
29
|
+
* Defaults: `autoSearch` on, `respectGitignore` off. With auto-search off and no `include`,
|
|
30
|
+
* `include` falls back to `["packages/*"]`.
|
|
31
|
+
*
|
|
32
|
+
* @param packages - the raw `packages` value from fynpo.json / fynpo.config.js
|
|
33
|
+
* @returns the resolved config, every field populated
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolvePackagesConfig(packages?: unknown): PackagesConfig;
|
|
36
|
+
/**
|
|
37
|
+
* The npm scope of a package name, or undefined when it is unscoped.
|
|
38
|
+
*
|
|
39
|
+
* @param name - package name
|
|
40
|
+
* @returns the scope including its `@`, e.g. `@fynjs`
|
|
41
|
+
*/
|
|
42
|
+
export declare function packageScope(name: string): string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Package names that fall OUTSIDE the given scopes, i.e. the ones `--scope` should exclude.
|
|
45
|
+
*
|
|
46
|
+
* An unscoped package is never in any scope, so it is always excluded once `--scope` is given.
|
|
47
|
+
* Scopes may be written with or without the leading `@`.
|
|
48
|
+
*
|
|
49
|
+
* Shared by both selection paths so they cannot disagree: `makePkgDeps` (used by prepare) and
|
|
50
|
+
* the dep-graph path (used by bootstrap, local and run). `--scope` used to be applied only in
|
|
51
|
+
* the former, so the three commands that actually advertise it silently ignored it. See FPO-37.
|
|
52
|
+
*
|
|
53
|
+
* @param scopes - the requested scopes
|
|
54
|
+
* @param names - all known package names
|
|
55
|
+
* @returns names to exclude; empty when no scope was requested
|
|
56
|
+
*/
|
|
57
|
+
export declare function outOfScopePackages(scopes: unknown, names: string[]): string[];
|
|
58
|
+
/**
|
|
59
|
+
* Decide how to scan for packages.
|
|
60
|
+
*
|
|
61
|
+
* `include` does NOT turn auto-search off - auto-search is on by default and stays on, so it
|
|
62
|
+
* still decides *how the tree is walked*. `include` then filters what the walk found, via
|
|
63
|
+
* {@link includeFilter}. Only with auto-search off does `include` become the scan patterns
|
|
64
|
+
* themselves, falling back to `packages/*`.
|
|
65
|
+
*
|
|
66
|
+
* @param config - resolved packages config
|
|
67
|
+
* @returns `null` to auto-search the whole repo, otherwise the patterns to scan
|
|
68
|
+
*/
|
|
69
|
+
export declare function scanPatterns(config: PackagesConfig): string[] | null;
|
|
70
|
+
/**
|
|
71
|
+
* The patterns a discovered package must match to be kept.
|
|
72
|
+
*
|
|
73
|
+
* Empty means keep everything the scan found.
|
|
74
|
+
*
|
|
75
|
+
* @param config - resolved packages config
|
|
76
|
+
* @returns patterns to match a package path against
|
|
77
|
+
*/
|
|
78
|
+
export declare function includeFilter(config: PackagesConfig): string[];
|