@fynpo/base 1.1.23 → 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 +21 -2
- package/dist/fynpo-dep-graph.js +108 -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/fynpo-dep-graph.js
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import Path from "path";
|
|
3
|
+
import { promises as Fs } from "fs";
|
|
4
|
+
import { filterScanDir } from "filter-scan-dir";
|
|
5
|
+
import { Minimatch } from "minimatch";
|
|
6
|
+
import _ from "lodash";
|
|
7
|
+
import Semver from "semver";
|
|
8
|
+
import { groupMM } from "./minimatch-group.js";
|
|
9
|
+
import { posixify } from "./util.js";
|
|
10
|
+
import { resolvePackagesConfig, scanPatterns, includeFilter } from "./packages-config.js";
|
|
11
|
+
import { makeGitignoreMatcher } from "./gitignore.js";
|
|
12
|
+
/**
|
|
13
|
+
* Check that `childPath` is inside `parentPath`.
|
|
14
|
+
*
|
|
15
|
+
* Local replacement for the `is-path-inside` package, mirroring its exact
|
|
16
|
+
* semantics: based on `path.relative`, so on win32 it inherits node's
|
|
17
|
+
* case-insensitive drive/path comparison. A path is not inside itself.
|
|
18
|
+
*/
|
|
19
|
+
function isPathInside(childPath, parentPath) {
|
|
20
|
+
const relation = Path.relative(parentPath, childPath);
|
|
21
|
+
return Boolean(relation &&
|
|
22
|
+
relation !== ".." &&
|
|
23
|
+
!relation.startsWith(`..${Path.sep}`) &&
|
|
24
|
+
relation !== Path.resolve(childPath));
|
|
25
|
+
}
|
|
19
26
|
const DepSectionMap = {
|
|
20
27
|
dependencies: "dep",
|
|
21
28
|
devDependencies: "dev",
|
|
@@ -32,7 +39,7 @@ const DepSectionMap = {
|
|
|
32
39
|
* @param fullName - full name from package.json dep section
|
|
33
40
|
* @returns dep section
|
|
34
41
|
*/
|
|
35
|
-
function getDepSection(fullName) {
|
|
42
|
+
export function getDepSection(fullName) {
|
|
36
43
|
return DepSectionMap[fullName] || "dep";
|
|
37
44
|
}
|
|
38
45
|
/**
|
|
@@ -43,7 +50,7 @@ function getDepSection(fullName) {
|
|
|
43
50
|
* @param sec section it's specified as a dep package
|
|
44
51
|
* @returns step string
|
|
45
52
|
*/
|
|
46
|
-
function makeDepStep(name, version, sec) {
|
|
53
|
+
export function makeDepStep(name, version, sec) {
|
|
47
54
|
return `${pkgId(name, version)}(${sec})`;
|
|
48
55
|
}
|
|
49
56
|
/**
|
|
@@ -51,7 +58,7 @@ function makeDepStep(name, version, sec) {
|
|
|
51
58
|
*
|
|
52
59
|
* Supports RegExp or minimatch (for path)
|
|
53
60
|
*/
|
|
54
|
-
class PackageRef {
|
|
61
|
+
export class PackageRef {
|
|
55
62
|
constructor(ref) {
|
|
56
63
|
this.parseRef(ref);
|
|
57
64
|
}
|
|
@@ -96,7 +103,7 @@ class PackageRef {
|
|
|
96
103
|
}
|
|
97
104
|
}
|
|
98
105
|
else if (this.type === "path") {
|
|
99
|
-
this.mm = new
|
|
106
|
+
this.mm = new Minimatch(this.value);
|
|
100
107
|
}
|
|
101
108
|
}
|
|
102
109
|
match(pkgInfo) {
|
|
@@ -113,7 +120,6 @@ class PackageRef {
|
|
|
113
120
|
}
|
|
114
121
|
}
|
|
115
122
|
}
|
|
116
|
-
exports.PackageRef = PackageRef;
|
|
117
123
|
/**
|
|
118
124
|
* Create a package ID by joining name and version into a single string with `@`
|
|
119
125
|
*
|
|
@@ -121,7 +127,7 @@ exports.PackageRef = PackageRef;
|
|
|
121
127
|
* @param version package version
|
|
122
128
|
* @returns
|
|
123
129
|
*/
|
|
124
|
-
function pkgId(name, version) {
|
|
130
|
+
export function pkgId(name, version) {
|
|
125
131
|
/* istanbul ignore next */
|
|
126
132
|
const ver = version ? `@${version}` : "";
|
|
127
133
|
return `${name}${ver}`;
|
|
@@ -137,7 +143,7 @@ function pkgId(name, version) {
|
|
|
137
143
|
* @returns package info
|
|
138
144
|
*/
|
|
139
145
|
function resolvePackage(semver, packages, fallbackToFirst = true) {
|
|
140
|
-
const found = packages.find((pkg) =>
|
|
146
|
+
const found = packages.find((pkg) => Semver.satisfies(pkg.version, semver));
|
|
141
147
|
if (found) {
|
|
142
148
|
return found;
|
|
143
149
|
}
|
|
@@ -152,13 +158,13 @@ function resolvePackage(semver, packages, fallbackToFirst = true) {
|
|
|
152
158
|
* @param info package basic info
|
|
153
159
|
* @returns
|
|
154
160
|
*/
|
|
155
|
-
function pkgInfoId(info) {
|
|
161
|
+
export function pkgInfoId(info) {
|
|
156
162
|
return pkgId(info.name, info.version);
|
|
157
163
|
}
|
|
158
164
|
/**
|
|
159
165
|
* fynpo dep graph manager
|
|
160
166
|
*/
|
|
161
|
-
class FynpoDepGraph {
|
|
167
|
+
export class FynpoDepGraph {
|
|
162
168
|
constructor(options = {}) {
|
|
163
169
|
this._options = { cwd: process.cwd(), ...options };
|
|
164
170
|
this.depMapByPath = Object.create(null);
|
|
@@ -175,7 +181,7 @@ class FynpoDepGraph {
|
|
|
175
181
|
* @param indirects - set true to resolve indirect deps also
|
|
176
182
|
*/
|
|
177
183
|
async resolve(indirects = false) {
|
|
178
|
-
if (
|
|
184
|
+
if (_.isEmpty(this.packages.byName)) {
|
|
179
185
|
await this.readPackages();
|
|
180
186
|
}
|
|
181
187
|
this.resolveDirectDeps();
|
|
@@ -301,23 +307,36 @@ class FynpoDepGraph {
|
|
|
301
307
|
async readPackages() {
|
|
302
308
|
const { patterns, cwd } = this._options;
|
|
303
309
|
let groups;
|
|
304
|
-
//
|
|
305
|
-
|
|
310
|
+
//
|
|
311
|
+
// Discovery is driven by the `packages` config, resolved the same way readFynpoPackages
|
|
312
|
+
// resolves it so the two paths cannot drift again (FPO-17). Explicit `patterns` passed to
|
|
313
|
+
// the constructor still win, for callers that already decided.
|
|
314
|
+
//
|
|
315
|
+
const pkgConfig = resolvePackagesConfig(this._options.packages);
|
|
316
|
+
const resolved = _.isEmpty(patterns) ? scanPatterns(pkgConfig) : patterns;
|
|
317
|
+
// `include` filters what the scan found - it does not replace the scan (FPO-17)
|
|
318
|
+
const includeMms = (_.isEmpty(patterns) ? includeFilter(pkgConfig) : []).map((p) => new Minimatch(p));
|
|
319
|
+
const isIncluded = (path) => includeMms.length === 0 || includeMms.some((m) => m.match(posixify(path)));
|
|
320
|
+
const autoSearch = resolved === null;
|
|
306
321
|
this.autoSearched = autoSearch;
|
|
307
322
|
const autoSearchFound = [];
|
|
323
|
+
const gitignore = makeGitignoreMatcher(cwd);
|
|
324
|
+
const excludeMms = pkgConfig.exclude.map((p) => new Minimatch(p));
|
|
325
|
+
const isExcluded = (path) => Boolean(path) && excludeMms.some((m) => m.match(path.split(Path.sep).join("/")));
|
|
326
|
+
const skipForAutoSearch = (path) => autoSearch && pkgConfig.autoSearch.respectGitignore && gitignore.ignores(path);
|
|
308
327
|
if (autoSearch) {
|
|
309
328
|
groups = { ".": null };
|
|
310
329
|
}
|
|
311
330
|
else {
|
|
312
|
-
const mms =
|
|
313
|
-
groups =
|
|
331
|
+
const mms = resolved.map((p) => new Minimatch(p));
|
|
332
|
+
groups = groupMM(mms, {});
|
|
314
333
|
}
|
|
315
334
|
const foundInAutoSearch = (path) => {
|
|
316
335
|
if (!autoSearch) {
|
|
317
336
|
return false;
|
|
318
337
|
}
|
|
319
338
|
for (const e of autoSearchFound) {
|
|
320
|
-
if ((
|
|
339
|
+
if (isPathInside(path, e)) {
|
|
321
340
|
return true;
|
|
322
341
|
}
|
|
323
342
|
}
|
|
@@ -325,12 +344,15 @@ class FynpoDepGraph {
|
|
|
325
344
|
};
|
|
326
345
|
const files = [];
|
|
327
346
|
for (const prefix in groups) {
|
|
328
|
-
const scanned = await
|
|
347
|
+
const scanned = await filterScanDir({
|
|
329
348
|
cwd,
|
|
330
349
|
prefix,
|
|
331
350
|
concurrency: 500,
|
|
332
351
|
filter: (file, path, extras) => {
|
|
333
352
|
if (path && path !== "." && file === "package.json") {
|
|
353
|
+
if (isExcluded(path) || skipForAutoSearch(path)) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
334
356
|
if (extras.files.includes("fynpo.json") || foundInAutoSearch(path)) {
|
|
335
357
|
//
|
|
336
358
|
// We ignore dir with package.json if:
|
|
@@ -347,7 +369,7 @@ class FynpoDepGraph {
|
|
|
347
369
|
},
|
|
348
370
|
filterDir: (dir, path, extras) => {
|
|
349
371
|
if (dir !== "node_modules") {
|
|
350
|
-
if (foundInAutoSearch(path)) {
|
|
372
|
+
if (foundInAutoSearch(path) || isExcluded(path) || skipForAutoSearch(path)) {
|
|
351
373
|
return false;
|
|
352
374
|
}
|
|
353
375
|
return prefix === "." && groups[prefix] === null
|
|
@@ -359,7 +381,9 @@ class FynpoDepGraph {
|
|
|
359
381
|
});
|
|
360
382
|
files.push(scanned);
|
|
361
383
|
}
|
|
362
|
-
const allFiles = [].concat(...files)
|
|
384
|
+
const allFiles = [].concat(...files)
|
|
385
|
+
.filter((f) => isIncluded(Path.dirname(f)))
|
|
386
|
+
.sort();
|
|
363
387
|
// Read each package.json and generate PackageInfo for it
|
|
364
388
|
for (const pkgFile of allFiles) {
|
|
365
389
|
await this.addPackageByFile(pkgFile);
|
|
@@ -373,9 +397,9 @@ class FynpoDepGraph {
|
|
|
373
397
|
* @param pkgFile - path to the package.json file
|
|
374
398
|
*/
|
|
375
399
|
async addPackageByFile(pkgFile) {
|
|
376
|
-
const pkgStr = await
|
|
400
|
+
const pkgStr = await Fs.readFile(Path.join(this._options.cwd, pkgFile), "utf-8");
|
|
377
401
|
const pkgJson = JSON.parse(pkgStr);
|
|
378
|
-
this.addPackage(pkgJson,
|
|
402
|
+
this.addPackage(pkgJson, Path.dirname(pkgFile), pkgStr);
|
|
379
403
|
}
|
|
380
404
|
/**
|
|
381
405
|
* Add a package to the graph using the data from its package.json
|
|
@@ -389,17 +413,17 @@ class FynpoDepGraph {
|
|
|
389
413
|
if (pkgJson.fynpo === false) {
|
|
390
414
|
return;
|
|
391
415
|
}
|
|
392
|
-
(
|
|
416
|
+
assert(pkgJson.name, `package at ${pkgPath} doesn't have name`);
|
|
393
417
|
// check for npm scope
|
|
394
418
|
const pkgDir = pkgJson.name[0] === "@" && (pkgPath.endsWith(`/${pkgJson.name}`) || pkgPath === pkgJson.name)
|
|
395
419
|
? pkgJson.name
|
|
396
|
-
:
|
|
420
|
+
: Path.basename(pkgPath);
|
|
397
421
|
const pkgInfo = {
|
|
398
422
|
name: pkgJson.name,
|
|
399
423
|
version: pkgJson.version,
|
|
400
424
|
path: pkgPath,
|
|
401
425
|
pkgDir,
|
|
402
|
-
...
|
|
426
|
+
..._.pick(pkgJson, [
|
|
403
427
|
"private",
|
|
404
428
|
"dependencies",
|
|
405
429
|
"devDependencies",
|
|
@@ -441,7 +465,7 @@ class FynpoDepGraph {
|
|
|
441
465
|
});
|
|
442
466
|
// sort package with multiple versions from latest to oldest
|
|
443
467
|
if (byName[name].length > 1) {
|
|
444
|
-
byName[name].sort((a, b) =>
|
|
468
|
+
byName[name].sort((a, b) => Semver.compare(b.version, a.version));
|
|
445
469
|
}
|
|
446
470
|
}
|
|
447
471
|
}
|
|
@@ -459,6 +483,38 @@ class FynpoDepGraph {
|
|
|
459
483
|
}
|
|
460
484
|
return undefined;
|
|
461
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* Check if a dependency should NOT be resolved as a local package.
|
|
488
|
+
*
|
|
489
|
+
* Checks both:
|
|
490
|
+
* 1. Monorepo-wide `noFynLocal` option
|
|
491
|
+
* 2. Per-package `fyn.dependencies[name]` setting (false or "no-fyn-local")
|
|
492
|
+
*
|
|
493
|
+
* @param pkgInfo - the package that has the dependency
|
|
494
|
+
* @param depName - name of the dependency to check
|
|
495
|
+
* @returns true if the dependency should NOT be resolved locally
|
|
496
|
+
*/
|
|
497
|
+
checkNoFynLocal(pkgInfo, depName) {
|
|
498
|
+
var _a, _b;
|
|
499
|
+
// Check monorepo-wide noFynLocal list
|
|
500
|
+
if ((_a = this._options.noFynLocal) === null || _a === void 0 ? void 0 : _a.includes(depName)) {
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
// Check per-package fyn.dependencies setting
|
|
504
|
+
const fynConfig = (_b = pkgInfo.pkgJson) === null || _b === void 0 ? void 0 : _b.fyn;
|
|
505
|
+
if (fynConfig) {
|
|
506
|
+
for (const section of ["dependencies", "devDependencies", "optionalDependencies"]) {
|
|
507
|
+
const deps = fynConfig[section];
|
|
508
|
+
if (deps) {
|
|
509
|
+
const val = deps[depName];
|
|
510
|
+
if (val === false || (typeof val === "string" && val.includes("no-fyn-local"))) {
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
462
518
|
/**
|
|
463
519
|
* Figure out all the packages' direct dependencies on other local packages
|
|
464
520
|
*
|
|
@@ -468,12 +524,16 @@ class FynpoDepGraph {
|
|
|
468
524
|
const depMapByPath = this.depMapByPath;
|
|
469
525
|
const doResolve = (depData, deps, section) => {
|
|
470
526
|
const { pkgInfo } = depData;
|
|
471
|
-
|
|
527
|
+
_.each(deps, (semver, name) => {
|
|
472
528
|
// dep is not a local package in the monorepo, nothing to do
|
|
473
529
|
/* istanbul ignore if */
|
|
474
530
|
if (!byName[name]) {
|
|
475
531
|
return;
|
|
476
532
|
}
|
|
533
|
+
// check if this dep should not be resolved as local package
|
|
534
|
+
if (this.checkNoFynLocal(pkgInfo, name)) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
477
537
|
const semId = pkgId(name, semver);
|
|
478
538
|
const resolveId = this.resolvedCache[semId];
|
|
479
539
|
const depPkg = (resolveId && byId[resolveId]) || resolvePackage(semver, byName[name]);
|
|
@@ -551,7 +611,7 @@ class FynpoDepGraph {
|
|
|
551
611
|
}
|
|
552
612
|
return true;
|
|
553
613
|
}
|
|
554
|
-
return !
|
|
614
|
+
return !_.isEmpty(dataDep.pathOfCirculars);
|
|
555
615
|
}
|
|
556
616
|
/**
|
|
557
617
|
* Add depdencies from a list of dep relations
|
|
@@ -605,7 +665,7 @@ class FynpoDepGraph {
|
|
|
605
665
|
* @param dir - directory of package to get
|
|
606
666
|
*/
|
|
607
667
|
getPackageAtDir(dir) {
|
|
608
|
-
const path =
|
|
668
|
+
const path = posixify(Path.isAbsolute(dir) ? Path.relative(this._options.cwd, dir) : dir);
|
|
609
669
|
return this.packages.byPath[path];
|
|
610
670
|
}
|
|
611
671
|
/**
|
|
@@ -614,7 +674,7 @@ class FynpoDepGraph {
|
|
|
614
674
|
* @returns
|
|
615
675
|
*/
|
|
616
676
|
getPackageByName(name) {
|
|
617
|
-
return
|
|
677
|
+
return _.first(this.packages.byName[name]);
|
|
618
678
|
}
|
|
619
679
|
/**
|
|
620
680
|
* Figure out all the packages' indirect dependencies on other local packages
|
|
@@ -628,7 +688,7 @@ class FynpoDepGraph {
|
|
|
628
688
|
const doResolve = (dataPkg, localDeps, steps, section) => {
|
|
629
689
|
const { pkgInfo } = dataPkg;
|
|
630
690
|
// go through all found deps
|
|
631
|
-
|
|
691
|
+
_.each(localDeps, (depRef) => {
|
|
632
692
|
const sec = section || depRef.depSection;
|
|
633
693
|
const depInfo = byPath[depRef.path];
|
|
634
694
|
const dataDep = depMapByPath[depRef.path];
|
|
@@ -654,10 +714,8 @@ class FynpoDepGraph {
|
|
|
654
714
|
doResolve(depData, depData.localDepsByPath, [pkgInfoId(depData.pkgInfo)]);
|
|
655
715
|
}
|
|
656
716
|
if (change > 0) {
|
|
657
|
-
(
|
|
717
|
+
assert(nestedLevel < 50, "FynpoDepGraph.resolveIndirectDeps nested too deep - there may be circular deps that's not detected");
|
|
658
718
|
this.resolveIndirectDeps(nestedLevel + 1);
|
|
659
719
|
}
|
|
660
720
|
}
|
|
661
721
|
}
|
|
662
|
-
exports.FynpoDepGraph = FynpoDepGraph;
|
|
663
|
-
//# sourceMappingURL=fynpo-dep-graph.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** matches paths against a repo's gitignore rules */
|
|
2
|
+
export type GitignoreMatcher = {
|
|
3
|
+
/** true if the given repo-relative path is ignored by git */
|
|
4
|
+
ignores(relPath: string): boolean;
|
|
5
|
+
/** true if any rule was actually loaded - false means every check is a no-op */
|
|
6
|
+
hasRules: boolean;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Build a gitignore matcher for a repo root.
|
|
10
|
+
*
|
|
11
|
+
* Never throws for a missing or unreadable ignore file - a repo with no rules simply matches
|
|
12
|
+
* nothing.
|
|
13
|
+
*
|
|
14
|
+
* @param cwd - repo root to read ignore rules from
|
|
15
|
+
* @returns a matcher; {@link GitignoreMatcher.hasRules} is false when nothing was loaded
|
|
16
|
+
*/
|
|
17
|
+
export declare function makeGitignoreMatcher(cwd: string): GitignoreMatcher;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import Fs from "fs";
|
|
2
|
+
import Path from "path";
|
|
3
|
+
import ignore from "ignore";
|
|
4
|
+
//
|
|
5
|
+
// Gitignore matching, used for two separate things (FPO-17):
|
|
6
|
+
//
|
|
7
|
+
// 1. `packages.autoSearch.respectGitignore` - opt-in, default off. When on, auto-search skips
|
|
8
|
+
// gitignored paths.
|
|
9
|
+
// 2. The publish veto - ALWAYS on. A gitignored package is never in publish jurisdiction, even
|
|
10
|
+
// when respectGitignore is off and even if `publishInclude` names it. A gitignored package
|
|
11
|
+
// is typically a nested clone of some other repo; publishing it from here is never right.
|
|
12
|
+
//
|
|
13
|
+
// Because of (2) the matcher is built regardless of the flag. In a directory with no gitignore
|
|
14
|
+
// rules - or no git at all - nothing matches and both behaviors are no-ops.
|
|
15
|
+
//
|
|
16
|
+
// Scope: the repo root `.gitignore` and `.git/info/exclude`. Nested `.gitignore` files deeper
|
|
17
|
+
// in the tree are NOT consulted, nor is the user's global excludesfile. That covers the case
|
|
18
|
+
// this exists for (a top-level ignored directory holding cloned repos) without shelling out to
|
|
19
|
+
// git, at the cost of missing rules declared further down.
|
|
20
|
+
//
|
|
21
|
+
const IGNORE_SOURCES = [".gitignore", Path.join(".git", "info", "exclude")];
|
|
22
|
+
const NO_RULES = {
|
|
23
|
+
ignores: () => false,
|
|
24
|
+
hasRules: false,
|
|
25
|
+
};
|
|
26
|
+
const readIfPresent = (file) => {
|
|
27
|
+
try {
|
|
28
|
+
return Fs.readFileSync(file, "utf8");
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if ((err === null || err === void 0 ? void 0 : err.code) !== "ENOENT" && (err === null || err === void 0 ? void 0 : err.code) !== "ENOTDIR") {
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Build a gitignore matcher for a repo root.
|
|
39
|
+
*
|
|
40
|
+
* Never throws for a missing or unreadable ignore file - a repo with no rules simply matches
|
|
41
|
+
* nothing.
|
|
42
|
+
*
|
|
43
|
+
* @param cwd - repo root to read ignore rules from
|
|
44
|
+
* @returns a matcher; {@link GitignoreMatcher.hasRules} is false when nothing was loaded
|
|
45
|
+
*/
|
|
46
|
+
export function makeGitignoreMatcher(cwd) {
|
|
47
|
+
const sources = IGNORE_SOURCES.map((f) => readIfPresent(Path.join(cwd, f))).filter(Boolean);
|
|
48
|
+
if (sources.length === 0) {
|
|
49
|
+
return NO_RULES;
|
|
50
|
+
}
|
|
51
|
+
const ig = ignore().add(sources.join("\n"));
|
|
52
|
+
return {
|
|
53
|
+
hasRules: true,
|
|
54
|
+
ignores(relPath) {
|
|
55
|
+
// `ignore` rejects absolute paths and anything outside the root, and refuses "."
|
|
56
|
+
if (!relPath || relPath === "." || Path.isAbsolute(relPath)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
// it wants posix separators relative to the root
|
|
60
|
+
const normalized = relPath.split(Path.sep).join("/").replace(/^\.\//, "");
|
|
61
|
+
if (!normalized || normalized.startsWith("..")) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return ig.ignores(normalized);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export * from "./fynpo-dep-graph";
|
|
2
|
-
export * from "./fynpo-config";
|
|
3
|
-
export * from "./
|
|
4
|
-
export *
|
|
1
|
+
export * from "./fynpo-dep-graph.js";
|
|
2
|
+
export * from "./fynpo-config.js";
|
|
3
|
+
export * from "./packages-config.js";
|
|
4
|
+
export * from "./gitignore.js";
|
|
5
|
+
export * from "./util.js";
|
|
6
|
+
export * as caching from "./caching.js";
|
|
5
7
|
/**
|
|
6
8
|
* Information about a package within the mono-repo
|
|
7
9
|
*/
|
|
@@ -57,12 +59,19 @@ export type PackageInfo = {
|
|
|
57
59
|
/**
|
|
58
60
|
* Read the packages of a fynpo mono-repo
|
|
59
61
|
*
|
|
60
|
-
* @
|
|
62
|
+
* Honors the same `packages` config as {@link FynpoDepGraph}, so both discovery paths agree.
|
|
63
|
+
* Passing `patterns` directly still works and takes precedence, for callers that already know
|
|
64
|
+
* what they want.
|
|
65
|
+
*
|
|
66
|
+
* @param patterns - explicit minimatch patterns. Overrides whatever `packages` config says.
|
|
67
|
+
* @param cwd - repo root
|
|
68
|
+
* @param packages - raw `packages` config, resolved via {@link resolvePackagesConfig}
|
|
61
69
|
* @returns - packages from the fynpo mono-repo
|
|
62
70
|
*/
|
|
63
|
-
export declare function readFynpoPackages({ patterns, cwd, }?: {
|
|
71
|
+
export declare function readFynpoPackages({ patterns, cwd, packages, }?: {
|
|
64
72
|
patterns?: string[];
|
|
65
73
|
cwd?: string;
|
|
74
|
+
packages?: unknown;
|
|
66
75
|
}): Promise<Record<string, PackageInfo>>;
|
|
67
76
|
/**
|
|
68
77
|
* calculate dep graphs for packages under the mono-repo
|
|
@@ -73,7 +82,9 @@ export declare function readFynpoPackages({ patterns, cwd, }?: {
|
|
|
73
82
|
*/
|
|
74
83
|
export declare function makePkgDeps(packages: any, opts: any): {
|
|
75
84
|
packages: any;
|
|
76
|
-
depMap:
|
|
85
|
+
depMap: {
|
|
86
|
+
[x: string]: Pick<any, string>;
|
|
87
|
+
};
|
|
77
88
|
circulars: any[];
|
|
78
89
|
warnings: any[];
|
|
79
90
|
only: any;
|