@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/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,22 +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;
|
|
321
|
+
this.autoSearched = autoSearch;
|
|
306
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);
|
|
307
327
|
if (autoSearch) {
|
|
308
328
|
groups = { ".": null };
|
|
309
329
|
}
|
|
310
330
|
else {
|
|
311
|
-
const mms =
|
|
312
|
-
groups =
|
|
331
|
+
const mms = resolved.map((p) => new Minimatch(p));
|
|
332
|
+
groups = groupMM(mms, {});
|
|
313
333
|
}
|
|
314
334
|
const foundInAutoSearch = (path) => {
|
|
315
335
|
if (!autoSearch) {
|
|
316
336
|
return false;
|
|
317
337
|
}
|
|
318
338
|
for (const e of autoSearchFound) {
|
|
319
|
-
if ((
|
|
339
|
+
if (isPathInside(path, e)) {
|
|
320
340
|
return true;
|
|
321
341
|
}
|
|
322
342
|
}
|
|
@@ -324,12 +344,15 @@ class FynpoDepGraph {
|
|
|
324
344
|
};
|
|
325
345
|
const files = [];
|
|
326
346
|
for (const prefix in groups) {
|
|
327
|
-
const scanned = await
|
|
347
|
+
const scanned = await filterScanDir({
|
|
328
348
|
cwd,
|
|
329
349
|
prefix,
|
|
330
350
|
concurrency: 500,
|
|
331
351
|
filter: (file, path, extras) => {
|
|
332
352
|
if (path && path !== "." && file === "package.json") {
|
|
353
|
+
if (isExcluded(path) || skipForAutoSearch(path)) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
333
356
|
if (extras.files.includes("fynpo.json") || foundInAutoSearch(path)) {
|
|
334
357
|
//
|
|
335
358
|
// We ignore dir with package.json if:
|
|
@@ -346,7 +369,7 @@ class FynpoDepGraph {
|
|
|
346
369
|
},
|
|
347
370
|
filterDir: (dir, path, extras) => {
|
|
348
371
|
if (dir !== "node_modules") {
|
|
349
|
-
if (foundInAutoSearch(path)) {
|
|
372
|
+
if (foundInAutoSearch(path) || isExcluded(path) || skipForAutoSearch(path)) {
|
|
350
373
|
return false;
|
|
351
374
|
}
|
|
352
375
|
return prefix === "." && groups[prefix] === null
|
|
@@ -358,7 +381,9 @@ class FynpoDepGraph {
|
|
|
358
381
|
});
|
|
359
382
|
files.push(scanned);
|
|
360
383
|
}
|
|
361
|
-
const allFiles = [].concat(...files)
|
|
384
|
+
const allFiles = [].concat(...files)
|
|
385
|
+
.filter((f) => isIncluded(Path.dirname(f)))
|
|
386
|
+
.sort();
|
|
362
387
|
// Read each package.json and generate PackageInfo for it
|
|
363
388
|
for (const pkgFile of allFiles) {
|
|
364
389
|
await this.addPackageByFile(pkgFile);
|
|
@@ -372,9 +397,9 @@ class FynpoDepGraph {
|
|
|
372
397
|
* @param pkgFile - path to the package.json file
|
|
373
398
|
*/
|
|
374
399
|
async addPackageByFile(pkgFile) {
|
|
375
|
-
const pkgStr = await
|
|
400
|
+
const pkgStr = await Fs.readFile(Path.join(this._options.cwd, pkgFile), "utf-8");
|
|
376
401
|
const pkgJson = JSON.parse(pkgStr);
|
|
377
|
-
this.addPackage(pkgJson,
|
|
402
|
+
this.addPackage(pkgJson, Path.dirname(pkgFile), pkgStr);
|
|
378
403
|
}
|
|
379
404
|
/**
|
|
380
405
|
* Add a package to the graph using the data from its package.json
|
|
@@ -388,17 +413,17 @@ class FynpoDepGraph {
|
|
|
388
413
|
if (pkgJson.fynpo === false) {
|
|
389
414
|
return;
|
|
390
415
|
}
|
|
391
|
-
(
|
|
416
|
+
assert(pkgJson.name, `package at ${pkgPath} doesn't have name`);
|
|
392
417
|
// check for npm scope
|
|
393
418
|
const pkgDir = pkgJson.name[0] === "@" && (pkgPath.endsWith(`/${pkgJson.name}`) || pkgPath === pkgJson.name)
|
|
394
419
|
? pkgJson.name
|
|
395
|
-
:
|
|
420
|
+
: Path.basename(pkgPath);
|
|
396
421
|
const pkgInfo = {
|
|
397
422
|
name: pkgJson.name,
|
|
398
423
|
version: pkgJson.version,
|
|
399
424
|
path: pkgPath,
|
|
400
425
|
pkgDir,
|
|
401
|
-
...
|
|
426
|
+
..._.pick(pkgJson, [
|
|
402
427
|
"private",
|
|
403
428
|
"dependencies",
|
|
404
429
|
"devDependencies",
|
|
@@ -440,7 +465,7 @@ class FynpoDepGraph {
|
|
|
440
465
|
});
|
|
441
466
|
// sort package with multiple versions from latest to oldest
|
|
442
467
|
if (byName[name].length > 1) {
|
|
443
|
-
byName[name].sort((a, b) =>
|
|
468
|
+
byName[name].sort((a, b) => Semver.compare(b.version, a.version));
|
|
444
469
|
}
|
|
445
470
|
}
|
|
446
471
|
}
|
|
@@ -458,6 +483,38 @@ class FynpoDepGraph {
|
|
|
458
483
|
}
|
|
459
484
|
return undefined;
|
|
460
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
|
+
}
|
|
461
518
|
/**
|
|
462
519
|
* Figure out all the packages' direct dependencies on other local packages
|
|
463
520
|
*
|
|
@@ -467,12 +524,16 @@ class FynpoDepGraph {
|
|
|
467
524
|
const depMapByPath = this.depMapByPath;
|
|
468
525
|
const doResolve = (depData, deps, section) => {
|
|
469
526
|
const { pkgInfo } = depData;
|
|
470
|
-
|
|
527
|
+
_.each(deps, (semver, name) => {
|
|
471
528
|
// dep is not a local package in the monorepo, nothing to do
|
|
472
529
|
/* istanbul ignore if */
|
|
473
530
|
if (!byName[name]) {
|
|
474
531
|
return;
|
|
475
532
|
}
|
|
533
|
+
// check if this dep should not be resolved as local package
|
|
534
|
+
if (this.checkNoFynLocal(pkgInfo, name)) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
476
537
|
const semId = pkgId(name, semver);
|
|
477
538
|
const resolveId = this.resolvedCache[semId];
|
|
478
539
|
const depPkg = (resolveId && byId[resolveId]) || resolvePackage(semver, byName[name]);
|
|
@@ -550,7 +611,7 @@ class FynpoDepGraph {
|
|
|
550
611
|
}
|
|
551
612
|
return true;
|
|
552
613
|
}
|
|
553
|
-
return !
|
|
614
|
+
return !_.isEmpty(dataDep.pathOfCirculars);
|
|
554
615
|
}
|
|
555
616
|
/**
|
|
556
617
|
* Add depdencies from a list of dep relations
|
|
@@ -604,7 +665,7 @@ class FynpoDepGraph {
|
|
|
604
665
|
* @param dir - directory of package to get
|
|
605
666
|
*/
|
|
606
667
|
getPackageAtDir(dir) {
|
|
607
|
-
const path =
|
|
668
|
+
const path = posixify(Path.isAbsolute(dir) ? Path.relative(this._options.cwd, dir) : dir);
|
|
608
669
|
return this.packages.byPath[path];
|
|
609
670
|
}
|
|
610
671
|
/**
|
|
@@ -613,7 +674,7 @@ class FynpoDepGraph {
|
|
|
613
674
|
* @returns
|
|
614
675
|
*/
|
|
615
676
|
getPackageByName(name) {
|
|
616
|
-
return
|
|
677
|
+
return _.first(this.packages.byName[name]);
|
|
617
678
|
}
|
|
618
679
|
/**
|
|
619
680
|
* Figure out all the packages' indirect dependencies on other local packages
|
|
@@ -627,7 +688,7 @@ class FynpoDepGraph {
|
|
|
627
688
|
const doResolve = (dataPkg, localDeps, steps, section) => {
|
|
628
689
|
const { pkgInfo } = dataPkg;
|
|
629
690
|
// go through all found deps
|
|
630
|
-
|
|
691
|
+
_.each(localDeps, (depRef) => {
|
|
631
692
|
const sec = section || depRef.depSection;
|
|
632
693
|
const depInfo = byPath[depRef.path];
|
|
633
694
|
const dataDep = depMapByPath[depRef.path];
|
|
@@ -653,10 +714,8 @@ class FynpoDepGraph {
|
|
|
653
714
|
doResolve(depData, depData.localDepsByPath, [pkgInfoId(depData.pkgInfo)]);
|
|
654
715
|
}
|
|
655
716
|
if (change > 0) {
|
|
656
|
-
(
|
|
717
|
+
assert(nestedLevel < 50, "FynpoDepGraph.resolveIndirectDeps nested too deep - there may be circular deps that's not detected");
|
|
657
718
|
this.resolveIndirectDeps(nestedLevel + 1);
|
|
658
719
|
}
|
|
659
720
|
}
|
|
660
721
|
}
|
|
661
|
-
exports.FynpoDepGraph = FynpoDepGraph;
|
|
662
|
-
//# 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;
|