@effected/walker 0.20.0 → 0.20.1
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/Walker.js +45 -40
- package/index.d.ts +5 -5
- package/package.json +1 -1
- package/tsdoc-metadata.json +1 -1
package/Walker.js
CHANGED
|
@@ -1,32 +1,11 @@
|
|
|
1
1
|
import { Effect, FileSystem, Option, Path } from "effect";
|
|
2
2
|
|
|
3
3
|
// src/Walker.ts
|
|
4
|
-
const ascend = (start, options) => Effect.gen(function* () {
|
|
5
|
-
const path = yield* Path.Path;
|
|
6
|
-
const maxDepth = options?.maxDepth ?? 256;
|
|
7
|
-
if (!Number.isInteger(maxDepth) || maxDepth < 1) return yield* Effect.die(/* @__PURE__ */ new Error(`Walker.ascend: maxDepth must be a positive integer, received ${maxDepth}`));
|
|
8
|
-
if (options?.stopAt !== void 0 && !path.isAbsolute(options.stopAt)) return yield* Effect.die(/* @__PURE__ */ new Error(`Walker.ascend: stopAt must be an absolute path, received ${JSON.stringify(options.stopAt)} (ascending from ${JSON.stringify(start)})`));
|
|
9
|
-
const ceiling = options?.stopAt === void 0 ? void 0 : path.resolve(options.stopAt);
|
|
10
|
-
const dirs = [];
|
|
11
|
-
let current = start;
|
|
12
|
-
for (let depth = 0; depth < maxDepth; depth++) {
|
|
13
|
-
dirs.push(current);
|
|
14
|
-
if (ceiling !== void 0 && (current === ceiling || path.resolve(current) === ceiling)) break;
|
|
15
|
-
const parent = path.dirname(current);
|
|
16
|
-
if (parent === current) break;
|
|
17
|
-
current = parent;
|
|
18
|
-
}
|
|
19
|
-
return dirs;
|
|
20
|
-
});
|
|
21
|
-
const ascendWithin = (start, ceiling, options) => Effect.gen(function* () {
|
|
22
|
-
if (Option.isNone(ceiling)) return yield* ascend(start, options);
|
|
23
|
-
return yield* ascendToPhysical(start, ceiling.value, options);
|
|
24
|
-
});
|
|
25
4
|
const ascendToPhysical = (start, ceiling, options) => Effect.gen(function* () {
|
|
26
5
|
const fs = yield* FileSystem.FileSystem;
|
|
27
6
|
const path = yield* Path.Path;
|
|
28
7
|
if (!path.isAbsolute(ceiling)) return yield* Effect.die(/* @__PURE__ */ new Error(`Walker.ascendWithin: ceiling must be an absolute path, received ${JSON.stringify(ceiling)} (ascending from ${JSON.stringify(start)})`));
|
|
29
|
-
const dirs = yield* ascend(start, {
|
|
8
|
+
const dirs = yield* Walker.ascend(start, {
|
|
30
9
|
...options,
|
|
31
10
|
stopAt: ceiling
|
|
32
11
|
});
|
|
@@ -34,27 +13,16 @@ const ascendToPhysical = (start, ceiling, options) => Effect.gen(function* () {
|
|
|
34
13
|
if (last !== void 0 && path.resolve(last) === path.resolve(ceiling)) return dirs;
|
|
35
14
|
const physical = yield* Effect.option(fs.realPath(ceiling));
|
|
36
15
|
if (Option.isNone(physical)) return dirs;
|
|
37
|
-
const hit = yield* findRoot(dirs, (dir) => Effect.map(fs.realPath(dir), (real) => real === physical.value));
|
|
16
|
+
const hit = yield* Walker.findRoot(dirs, (dir) => Effect.map(fs.realPath(dir), (real) => real === physical.value));
|
|
38
17
|
return Option.isSome(hit) ? dirs.slice(0, dirs.indexOf(hit.value) + 1) : dirs;
|
|
39
18
|
});
|
|
40
|
-
const firstMatch = (candidates, predicate) => Effect.gen(function* () {
|
|
41
|
-
for (const candidate of candidates) if (yield* Effect.catch(predicate(candidate), () => Effect.succeed(false))) return Option.some(candidate);
|
|
42
|
-
return Option.none();
|
|
43
|
-
});
|
|
44
|
-
const findUpward = (dirs, candidatesFor) => Effect.gen(function* () {
|
|
45
|
-
const fs = yield* FileSystem.FileSystem;
|
|
46
|
-
const candidates = [];
|
|
47
|
-
for (const dir of dirs) candidates.push(...candidatesFor(dir));
|
|
48
|
-
return yield* firstMatch(candidates, (candidate) => fs.exists(candidate));
|
|
49
|
-
});
|
|
50
|
-
const findRoot = (dirs, isRoot) => firstMatch(dirs, isRoot);
|
|
51
19
|
/**
|
|
52
20
|
* Upward path traversal primitives: the directory chain from a start path to the
|
|
53
21
|
* root, and first-match scans over it.
|
|
54
22
|
*
|
|
55
23
|
* @public
|
|
56
24
|
*/
|
|
57
|
-
var Walker = class {
|
|
25
|
+
var Walker = class Walker {
|
|
58
26
|
constructor() {}
|
|
59
27
|
/**
|
|
60
28
|
* Ascend from `start` toward the filesystem root, yielding each directory,
|
|
@@ -90,7 +58,25 @@ var Walker = class {
|
|
|
90
58
|
* // Requires `Path` from the platform layer.
|
|
91
59
|
* ```
|
|
92
60
|
*/
|
|
93
|
-
static ascend
|
|
61
|
+
static ascend(start, options) {
|
|
62
|
+
return Effect.gen(function* () {
|
|
63
|
+
const path = yield* Path.Path;
|
|
64
|
+
const maxDepth = options?.maxDepth ?? 256;
|
|
65
|
+
if (!Number.isInteger(maxDepth) || maxDepth < 1) return yield* Effect.die(/* @__PURE__ */ new Error(`Walker.ascend: maxDepth must be a positive integer, received ${maxDepth}`));
|
|
66
|
+
if (options?.stopAt !== void 0 && !path.isAbsolute(options.stopAt)) return yield* Effect.die(/* @__PURE__ */ new Error(`Walker.ascend: stopAt must be an absolute path, received ${JSON.stringify(options.stopAt)} (ascending from ${JSON.stringify(start)})`));
|
|
67
|
+
const ceiling = options?.stopAt === void 0 ? void 0 : path.resolve(options.stopAt);
|
|
68
|
+
const dirs = [];
|
|
69
|
+
let current = start;
|
|
70
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
71
|
+
dirs.push(current);
|
|
72
|
+
if (ceiling !== void 0 && (current === ceiling || path.resolve(current) === ceiling)) break;
|
|
73
|
+
const parent = path.dirname(current);
|
|
74
|
+
if (parent === current) break;
|
|
75
|
+
current = parent;
|
|
76
|
+
}
|
|
77
|
+
return dirs;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
94
80
|
/**
|
|
95
81
|
* {@link Walker.ascend} bounded by a PHYSICAL ceiling: stops at the nearest
|
|
96
82
|
* directory whose real path is the ceiling's real path, inclusive.
|
|
@@ -118,7 +104,12 @@ var Walker = class {
|
|
|
118
104
|
* A present ceiling must be absolute; a relative one **dies**, for the
|
|
119
105
|
* reasons {@link AscendOptions.stopAt} gives.
|
|
120
106
|
*/
|
|
121
|
-
static ascendWithin
|
|
107
|
+
static ascendWithin(start, ceiling, options) {
|
|
108
|
+
return Effect.gen(function* () {
|
|
109
|
+
if (Option.isNone(ceiling)) return yield* Walker.ascend(start, options);
|
|
110
|
+
return yield* ascendToPhysical(start, ceiling.value, options);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
122
113
|
/**
|
|
123
114
|
* The first candidate whose `predicate` reports true, or `Option.none()`.
|
|
124
115
|
*
|
|
@@ -133,7 +124,12 @@ var Walker = class {
|
|
|
133
124
|
* programmer error and surfaces as a defect. Do not change this to
|
|
134
125
|
* `Effect.catchCause` — the distinction is load-bearing.
|
|
135
126
|
*/
|
|
136
|
-
static firstMatch
|
|
127
|
+
static firstMatch(candidates, predicate) {
|
|
128
|
+
return Effect.gen(function* () {
|
|
129
|
+
for (const candidate of candidates) if (yield* Effect.catch(predicate(candidate), () => Effect.succeed(false))) return Option.some(candidate);
|
|
130
|
+
return Option.none();
|
|
131
|
+
});
|
|
132
|
+
}
|
|
137
133
|
/**
|
|
138
134
|
* The first existing path among the candidates `candidatesFor` produces for each
|
|
139
135
|
* directory in `dirs`, scanned in order. Nearer directories win.
|
|
@@ -142,7 +138,14 @@ var Walker = class {
|
|
|
142
138
|
* Candidates materialize up front, bounded by `dirs.length × candidatesFor`'s
|
|
143
139
|
* output — a few hundred strings under the default `maxDepth`.
|
|
144
140
|
*/
|
|
145
|
-
static findUpward
|
|
141
|
+
static findUpward(dirs, candidatesFor) {
|
|
142
|
+
return Effect.gen(function* () {
|
|
143
|
+
const fs = yield* FileSystem.FileSystem;
|
|
144
|
+
const candidates = [];
|
|
145
|
+
for (const dir of dirs) candidates.push(...candidatesFor(dir));
|
|
146
|
+
return yield* Walker.firstMatch(candidates, (candidate) => fs.exists(candidate));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
146
149
|
/**
|
|
147
150
|
* The first directory in `dirs` that `isRoot` accepts.
|
|
148
151
|
*
|
|
@@ -151,7 +154,9 @@ var Walker = class {
|
|
|
151
154
|
* identity. `isRoot` is a caller-supplied marker test (a `.git` entry, a
|
|
152
155
|
* `pnpm-workspace.yaml`), and its failures are absorbed per directory.
|
|
153
156
|
*/
|
|
154
|
-
static findRoot
|
|
157
|
+
static findRoot(dirs, isRoot) {
|
|
158
|
+
return Walker.firstMatch(dirs, isRoot);
|
|
159
|
+
}
|
|
155
160
|
};
|
|
156
161
|
|
|
157
162
|
export { Walker };
|
package/index.d.ts
CHANGED
|
@@ -530,7 +530,7 @@ export declare class Walker {
|
|
|
530
530
|
* // Requires `Path` from the platform layer.
|
|
531
531
|
* ```
|
|
532
532
|
*/
|
|
533
|
-
static
|
|
533
|
+
static ascend(start: string, options?: AscendOptions): Effect.Effect<ReadonlyArray<string>, never, Path.Path>;
|
|
534
534
|
/**
|
|
535
535
|
* {@link Walker.ascend} bounded by a PHYSICAL ceiling: stops at the nearest
|
|
536
536
|
* directory whose real path is the ceiling's real path, inclusive.
|
|
@@ -558,7 +558,7 @@ export declare class Walker {
|
|
|
558
558
|
* A present ceiling must be absolute; a relative one **dies**, for the
|
|
559
559
|
* reasons {@link AscendOptions.stopAt} gives.
|
|
560
560
|
*/
|
|
561
|
-
static
|
|
561
|
+
static ascendWithin(start: string, ceiling: Option.Option<string>, options?: Pick<AscendOptions, "maxDepth">): Effect.Effect<ReadonlyArray<string>, never, FileSystem.FileSystem | Path.Path>;
|
|
562
562
|
/**
|
|
563
563
|
* The first candidate whose `predicate` reports true, or `Option.none()`.
|
|
564
564
|
*
|
|
@@ -573,7 +573,7 @@ export declare class Walker {
|
|
|
573
573
|
* programmer error and surfaces as a defect. Do not change this to
|
|
574
574
|
* `Effect.catchCause` — the distinction is load-bearing.
|
|
575
575
|
*/
|
|
576
|
-
static
|
|
576
|
+
static firstMatch<E, R>(candidates: ReadonlyArray<string>, predicate: (candidate: string) => Effect.Effect<boolean, E, R>): Effect.Effect<Option.Option<string>, never, R>;
|
|
577
577
|
/**
|
|
578
578
|
* The first existing path among the candidates `candidatesFor` produces for each
|
|
579
579
|
* directory in `dirs`, scanned in order. Nearer directories win.
|
|
@@ -582,7 +582,7 @@ export declare class Walker {
|
|
|
582
582
|
* Candidates materialize up front, bounded by `dirs.length × candidatesFor`'s
|
|
583
583
|
* output — a few hundred strings under the default `maxDepth`.
|
|
584
584
|
*/
|
|
585
|
-
static
|
|
585
|
+
static findUpward(dirs: ReadonlyArray<string>, candidatesFor: (dir: string) => ReadonlyArray<string>): Effect.Effect<Option.Option<string>, never, FileSystem.FileSystem>;
|
|
586
586
|
/**
|
|
587
587
|
* The first directory in `dirs` that `isRoot` accepts.
|
|
588
588
|
*
|
|
@@ -591,7 +591,7 @@ export declare class Walker {
|
|
|
591
591
|
* identity. `isRoot` is a caller-supplied marker test (a `.git` entry, a
|
|
592
592
|
* `pnpm-workspace.yaml`), and its failures are absorbed per directory.
|
|
593
593
|
*/
|
|
594
|
-
static
|
|
594
|
+
static findRoot<E, R>(dirs: ReadonlyArray<string>, isRoot: (dir: string) => Effect.Effect<boolean, E, R>): Effect.Effect<Option.Option<string>, never, R>;
|
|
595
595
|
}
|
|
596
596
|
export type { AscendOptions, CompileAndExpandOptions, DescendOptions, DescendRecordOptions, DescendResult, UnreadableDirectory };
|
|
597
597
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/walker",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Path traversal as Effect primitives: ascend a directory chain to the first matching candidate, or descend a tree expanding a glob against the filesystem.",
|
|
6
6
|
"keywords": [
|