@effected/walker 0.20.1 → 0.22.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/Confine.js +19 -10
- package/ConfineReal.js +123 -0
- package/Descend.js +60 -126
- package/DescendSync.js +79 -0
- package/Walker.js +193 -38
- package/index.d.ts +591 -19
- package/index.js +4 -2
- package/internal/absolute.js +19 -0
- package/internal/descendMachine.js +282 -0
- package/internal/trimTrailing.js +13 -0
- package/internal/upwardDrivers.js +71 -0
- package/internal/upwardMachine.js +239 -0
- package/node-sync.d.ts +102 -0
- package/node-sync.js +61 -0
- package/package.json +7 -2
package/index.d.ts
CHANGED
|
@@ -20,10 +20,16 @@ import { GlobPattern, GlobPatternError, GlobPatternOptions } from "@effected/glo
|
|
|
20
20
|
* reserved device name (`CON`, `PRN`, `AUX`, `NUL`, `COM1`–`COM9`,
|
|
21
21
|
* `LPT1`–`LPT9`), in any case and with or without an extension
|
|
22
22
|
* (`nul.txt`).
|
|
23
|
+
* - `outside` — `confineReal` only: the candidate's real path, links
|
|
24
|
+
* resolved, lies outside the base's real path.
|
|
25
|
+
* - `unresolvable` — `confineReal` only: resolving the candidate or the base
|
|
26
|
+
* failed for a reason other than absence (a permission error, a link loop,
|
|
27
|
+
* a file used as a directory, a dangling link), so containment cannot be
|
|
28
|
+
* verified. The failure rides in the error's `cause`.
|
|
23
29
|
*
|
|
24
30
|
* @public
|
|
25
31
|
*/
|
|
26
|
-
export declare const PathEscapeReason: Schema.Literals<readonly ["nulByte", "absolute", "traversal", "empty", "reservedName"]>;
|
|
32
|
+
export declare const PathEscapeReason: Schema.Literals<readonly ["nulByte", "absolute", "traversal", "empty", "reservedName", "outside", "unresolvable"]>;
|
|
27
33
|
/**
|
|
28
34
|
* The decoded type of {@link (PathEscapeReason:variable)}.
|
|
29
35
|
*
|
|
@@ -34,7 +40,9 @@ declare const PathEscapeError_base: Schema.Class<PathEscapeError, Schema.TaggedS
|
|
|
34
40
|
/** The candidate path, exactly as the caller passed it. */
|
|
35
41
|
readonly candidate: Schema.String;
|
|
36
42
|
/** Why the candidate was refused. */
|
|
37
|
-
readonly reason: Schema.Literals<readonly ["nulByte", "absolute", "traversal", "empty", "reservedName"]>;
|
|
43
|
+
readonly reason: Schema.Literals<readonly ["nulByte", "absolute", "traversal", "empty", "reservedName", "outside", "unresolvable"]>;
|
|
44
|
+
/** The resolution failure, present when `reason` is `"unresolvable"`. */
|
|
45
|
+
readonly cause: Schema.optionalKey<Schema.Defect>;
|
|
38
46
|
}>, import("effect/Cause").YieldableError>;
|
|
39
47
|
/**
|
|
40
48
|
* An untrusted relative path would leave, or does not name anything under,
|
|
@@ -82,7 +90,7 @@ export declare class PathEscapeError extends PathEscapeError_base {
|
|
|
82
90
|
* base yields the normalised relative path alone. The check is lexical, not
|
|
83
91
|
* physical, and symlinks are out of scope: a symlink already inside the
|
|
84
92
|
* base can still point out of it, so a caller extracting into a directory
|
|
85
|
-
* it does not own
|
|
93
|
+
* it does not own checks the result with `confineReal` as well.
|
|
86
94
|
*
|
|
87
95
|
* {@link confineRelative} is defined in terms of this function and adds
|
|
88
96
|
* only the tracing span.
|
|
@@ -139,12 +147,70 @@ export declare const confineRelative: (base: string, candidate: string) => Effec
|
|
|
139
147
|
* @public
|
|
140
148
|
*/
|
|
141
149
|
interface DescendOptions {
|
|
142
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* Absolute directory the pattern is resolved against. Required — walker
|
|
152
|
+
* never reads `process.cwd()`.
|
|
153
|
+
*
|
|
154
|
+
* @remarks
|
|
155
|
+
* **A missing `cwd` is an empty result, never a failure**: when `cwd` does
|
|
156
|
+
* not exist, is a file, or is a dangling link, every pattern — literal or
|
|
157
|
+
* magic — answers zero matches (`[]`, or `{ matches: [], unreadable: [] }`
|
|
158
|
+
* under `"record"`), in the `Effect` and the sync forms alike. Zero
|
|
159
|
+
* matches is a normal glob answer, so a caller that must tell "nothing
|
|
160
|
+
* matched" from "there was nothing to look in" checks `cwd` itself first.
|
|
161
|
+
* The same holds for a pattern's literal base below `cwd`. Only an
|
|
162
|
+
* unreadable directory the walk does reach fails, under `"fail"`.
|
|
163
|
+
*
|
|
164
|
+
* **A relative `cwd` — the empty string included — is a defect**: the
|
|
165
|
+
* `Effect` forms die and the sync forms throw. A relative directory would
|
|
166
|
+
* resolve against the process working directory, so the same call would
|
|
167
|
+
* walk different trees from a hook, a CLI and a test runner, and on win32
|
|
168
|
+
* an empty `cwd` joined with a pattern spelled `C:/x` is the drive path
|
|
169
|
+
* `C:\x`. Absoluteness is judged by the injected `Path` (or the sync port's
|
|
170
|
+
* `isAbsolute`), so win32 accepts `C:\repo` and `\\server\share`; a
|
|
171
|
+
* win32 `\repo` names the root of whichever drive the process is on, so
|
|
172
|
+
* it dies as a relative `cwd` does.
|
|
173
|
+
*/
|
|
143
174
|
readonly cwd: string;
|
|
175
|
+
/**
|
|
176
|
+
* Which entry kinds match. `"file"` (the default) answers files only, as
|
|
177
|
+
* `descend` always has; `"directory"` answers directories only; `"any"`
|
|
178
|
+
* answers both.
|
|
179
|
+
*
|
|
180
|
+
* @remarks
|
|
181
|
+
* The kind is the RESOLVED one — links followed, as for files — so a link
|
|
182
|
+
* to a directory matches as a directory, even where `followSymlinks: false`
|
|
183
|
+
* keeps the walk from entering it, and even when its target lies outside
|
|
184
|
+
* `cwd`. Check such an entry with `confineReal` before acting on it. A
|
|
185
|
+
* directory matches as an entry of its parent: `prune`, a boundary and an
|
|
186
|
+
* unentered link withhold what lies below a directory, never the
|
|
187
|
+
* directory itself, so a globstar pattern for `node_modules` finds every
|
|
188
|
+
* `node_modules` under the default `prune` without reading inside one. A directory is tested bare
|
|
189
|
+
* and with a trailing `/`, so the directory-only glob form `dist/`
|
|
190
|
+
* matches, answered as spelled. `cwd` itself is never a match.
|
|
191
|
+
*/
|
|
192
|
+
readonly match?: "file" | "directory" | "any";
|
|
144
193
|
/** Hard cap on directory depth below the pattern's literal prefix. Defaults to 256. */
|
|
145
194
|
readonly maxDepth?: number;
|
|
146
195
|
/** Directory names never descended into. Defaults to `["node_modules", ".git"]`; a custom list replaces the default. */
|
|
147
196
|
readonly prune?: ReadonlyArray<string>;
|
|
197
|
+
/**
|
|
198
|
+
* Marker FILE names that make a directory a boundary — a nested unit (another
|
|
199
|
+
* package, say: `["package.json"]`) whose contents belong to a separate walk.
|
|
200
|
+
*
|
|
201
|
+
* @remarks
|
|
202
|
+
* A directory strictly below `cwd` holding a FILE with one of these names
|
|
203
|
+
* contributes nothing: none of its files match and its subtree is never
|
|
204
|
+
* descended. `cwd` itself is never a boundary, and a DIRECTORY named like a
|
|
205
|
+
* marker does not count. The rule is about where a file sits, not how the
|
|
206
|
+
* walk reached it, so it applies to a walk that starts below `cwd` (the
|
|
207
|
+
* pattern's literal prefix) and to a literal pattern alike: a boundary
|
|
208
|
+
* between `cwd` and the walk base, or between `cwd` and a literal file,
|
|
209
|
+
* also answers zero matches. Each directory pays one stat per marker it
|
|
210
|
+
* actually lists. Defaults to none. Not to be confused with
|
|
211
|
+
* `Walker.ascend`'s `stopAt`, an inclusive upward ceiling.
|
|
212
|
+
*/
|
|
213
|
+
readonly boundaries?: ReadonlyArray<string>;
|
|
148
214
|
/**
|
|
149
215
|
* What an unreadable directory mid-walk does. `"fail"` (the default) fails
|
|
150
216
|
* typed — downward enumeration must not silently swallow a subtree, or the
|
|
@@ -158,7 +224,9 @@ interface DescendOptions {
|
|
|
158
224
|
readonly onUnreadable?: "fail" | "skip";
|
|
159
225
|
/**
|
|
160
226
|
* Whether to descend into symlinked directories. Defaults to `false`: a
|
|
161
|
-
* symlinked directory is never entered (cycle safety)
|
|
227
|
+
* symlinked directory is never entered (cycle safety) — the walk base, and
|
|
228
|
+
* every directory on the way to it, included: a base reached through a link
|
|
229
|
+
* is an empty result. Under `true` links
|
|
162
230
|
* are followed with the cycle guard kept underneath, in `@actions/glob`'s
|
|
163
231
|
* `traversalChain` semantics: each descended directory records its real
|
|
164
232
|
* path on its own branch's ancestor chain (only the base and each link pay
|
|
@@ -208,7 +276,7 @@ interface DescendRecordOptions extends Omit<DescendOptions, "onUnreadable"> {
|
|
|
208
276
|
*
|
|
209
277
|
* @public
|
|
210
278
|
*/
|
|
211
|
-
interface UnreadableDirectory {
|
|
279
|
+
interface UnreadableDirectory<C = PlatformError.PlatformError> {
|
|
212
280
|
/**
|
|
213
281
|
* The directory's path relative to `cwd`, POSIX separators.
|
|
214
282
|
*
|
|
@@ -220,7 +288,7 @@ interface UnreadableDirectory {
|
|
|
220
288
|
*/
|
|
221
289
|
readonly path: string;
|
|
222
290
|
/** The `readDirectory` (or, for a link under `followSymlinks`, `realPath`) failure, never `NotFound` (a vanished directory is a benign race and is not recorded). */
|
|
223
|
-
readonly cause:
|
|
291
|
+
readonly cause: C;
|
|
224
292
|
}
|
|
225
293
|
/**
|
|
226
294
|
* `descend`'s success value under `onUnreadable: "record"`: the matched
|
|
@@ -232,11 +300,11 @@ interface UnreadableDirectory {
|
|
|
232
300
|
*
|
|
233
301
|
* @public
|
|
234
302
|
*/
|
|
235
|
-
interface DescendResult {
|
|
303
|
+
interface DescendResult<C = PlatformError.PlatformError> {
|
|
236
304
|
/** Matching FILE paths relative to `cwd`, POSIX separators, sorted — identical in shape to the `"fail"`/`"skip"` success value. */
|
|
237
305
|
readonly matches: ReadonlyArray<string>;
|
|
238
306
|
/** Directories that could not be read, each with its cause, in walk order. */
|
|
239
|
-
readonly unreadable: ReadonlyArray<UnreadableDirectory
|
|
307
|
+
readonly unreadable: ReadonlyArray<UnreadableDirectory<C>>;
|
|
240
308
|
}
|
|
241
309
|
declare const DescendError_base: Schema.Class<DescendError, Schema.TaggedStruct<"DescendError", {
|
|
242
310
|
/** The glob pattern's source text. */
|
|
@@ -259,6 +327,35 @@ declare const DescendError_base: Schema.Class<DescendError, Schema.TaggedStruct<
|
|
|
259
327
|
export declare class DescendError extends DescendError_base {
|
|
260
328
|
get message(): string;
|
|
261
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* One matched entry — a file, or under `match` a directory — with the stat
|
|
332
|
+
* the walk already read for it: `descendEntries`' element. Costs no syscall beyond `descend`'s: the walk stats every entry to
|
|
333
|
+
* classify it, and this keeps the answer instead of discarding it.
|
|
334
|
+
*
|
|
335
|
+
* The type parameter is the stat's type, so the sync walk reuses this shape
|
|
336
|
+
* with its port's stats.
|
|
337
|
+
*
|
|
338
|
+
* @public
|
|
339
|
+
*/
|
|
340
|
+
interface DescendEntry<I = FileSystem.File.Info> {
|
|
341
|
+
/** The entry's path relative to `cwd`, POSIX separators. */
|
|
342
|
+
readonly path: string;
|
|
343
|
+
/** `FileSystem.stat` of the file — links followed, so a symlinked file reports its target. */
|
|
344
|
+
readonly info: I;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* `descendEntries`' success value under `onUnreadable: "record"`: the matched
|
|
348
|
+
* {@link DescendEntry} values plus every {@link UnreadableDirectory}, exactly
|
|
349
|
+
* as {@link DescendResult} carries them for `descend`.
|
|
350
|
+
*
|
|
351
|
+
* @public
|
|
352
|
+
*/
|
|
353
|
+
interface DescendEntriesResult<I = FileSystem.File.Info, C = PlatformError.PlatformError> {
|
|
354
|
+
/** Matching files with their stats, sorted by path. */
|
|
355
|
+
readonly matches: ReadonlyArray<DescendEntry<I>>;
|
|
356
|
+
/** Directories that could not be read, each with its cause, in walk order. */
|
|
357
|
+
readonly unreadable: ReadonlyArray<UnreadableDirectory<C>>;
|
|
358
|
+
}
|
|
262
359
|
/**
|
|
263
360
|
* Expand a compiled glob pattern against the filesystem under
|
|
264
361
|
* `onUnreadable: "record"`, resolving to a {@link DescendResult} — the
|
|
@@ -274,15 +371,22 @@ export declare class DescendError extends DescendError_base {
|
|
|
274
371
|
export declare function descend(pattern: GlobPattern, options: DescendRecordOptions): Effect.Effect<DescendResult, DescendError, FileSystem.FileSystem | Path.Path>;
|
|
275
372
|
/**
|
|
276
373
|
* Expand a compiled glob pattern against the filesystem, returning matching
|
|
277
|
-
* FILE paths relative to `cwd` (POSIX separators), sorted by relative path
|
|
374
|
+
* FILE paths relative to `cwd` (POSIX separators), sorted by relative path —
|
|
375
|
+
* or, under `match: "directory"` or `"any"`, directory paths too.
|
|
278
376
|
*
|
|
279
377
|
* @remarks
|
|
280
|
-
* A
|
|
378
|
+
* A path is answered in the spelling the pattern matched it under: `./src/*.ts`
|
|
379
|
+
* answers `./src/a.ts`, and `src/*.ts` answers `src/a.ts`. A file several
|
|
380
|
+
* brace alternatives match under different spellings (`{src,./src}/*.ts`) is
|
|
381
|
+
* answered once, in the spelling of the earliest of them in pattern order. A
|
|
382
|
+
* literal pattern (no magic, not negated) fast-paths to a single stat: the
|
|
281
383
|
* result is `[source]` when it resolves to a file, `[]` otherwise — a missing
|
|
282
|
-
* path is zero matches, not an error. A magic pattern walks
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
384
|
+
* path is zero matches, not an error. A magic pattern walks each of its
|
|
385
|
+
* `GlobPattern.enumerationRoots`, reading each directory once however many
|
|
386
|
+
* alternatives spell it; a NEGATED pattern can match paths outside those
|
|
387
|
+
* roots, so it walks from `cwd` itself. A missing `cwd` or
|
|
388
|
+
* base directory (absent, a file, a dangling link) is likewise an empty
|
|
389
|
+
* result — see `DescendOptions.cwd` — because zero matches is a
|
|
286
390
|
* normal glob answer — as is any pattern that lexically climbs above `cwd`
|
|
287
391
|
* via `..` segments (walked paths never contain `..`). "Never reads outside
|
|
288
392
|
* its documented root" holds lexically always, and physically only while
|
|
@@ -292,9 +396,10 @@ export declare function descend(pattern: GlobPattern, options: DescendRecordOpti
|
|
|
292
396
|
* (under the default `onUnreadable: "fail"`) or a walk past `maxDepth` fails,
|
|
293
397
|
* typed as {@link DescendError}.
|
|
294
398
|
*
|
|
295
|
-
* Only files match
|
|
399
|
+
* Only files match by default (`match` widens that to directories). A symlink
|
|
400
|
+
* counts when it stat-resolves to a file
|
|
296
401
|
* (`FileSystem.stat` follows links, as node's does); a symlinked directory is
|
|
297
|
-
* never descended into by default (cycle safety — detected by
|
|
402
|
+
* never descended into by default (cycle safety — detected by an `lstat`
|
|
298
403
|
* probe), unless `followSymlinks: true` asks for it, which follows links under
|
|
299
404
|
* `@actions/glob`'s `traversalChain` cycle guard: a directory is a cycle only
|
|
300
405
|
* when its real path is already an ancestor of the current branch, so sibling
|
|
@@ -332,6 +437,276 @@ export declare function descend(pattern: GlobPattern, options: DescendRecordOpti
|
|
|
332
437
|
* @public
|
|
333
438
|
*/
|
|
334
439
|
export declare function descend(pattern: GlobPattern, options: DescendOptions): Effect.Effect<ReadonlyArray<string>, DescendError, FileSystem.FileSystem | Path.Path>;
|
|
440
|
+
/**
|
|
441
|
+
* `descend` under `onUnreadable: "record"`, keeping each match's stat:
|
|
442
|
+
* resolves to a {@link DescendEntriesResult}.
|
|
443
|
+
*
|
|
444
|
+
* @public
|
|
445
|
+
*/
|
|
446
|
+
export declare function descendEntries(pattern: GlobPattern, options: DescendRecordOptions): Effect.Effect<DescendEntriesResult, DescendError, FileSystem.FileSystem | Path.Path>;
|
|
447
|
+
/**
|
|
448
|
+
* `descend`, keeping the stat the walk already read for each matched
|
|
449
|
+
* file: resolves to {@link DescendEntry} values sorted by path.
|
|
450
|
+
*
|
|
451
|
+
* @remarks
|
|
452
|
+
* The same walk, the same matches in the same order, the same errors — only
|
|
453
|
+
* the element type differs, and at no extra syscall (the walk stats every
|
|
454
|
+
* entry to classify it). For a cache signature over a tree, map each entry's
|
|
455
|
+
* `path` and `info.mtime` (or `info.size`) into whatever key the cache needs;
|
|
456
|
+
* the kit does not choose the fingerprint.
|
|
457
|
+
*
|
|
458
|
+
* @example
|
|
459
|
+
* ```ts
|
|
460
|
+
* import { GlobPattern, GlobPatternOptions } from "@effected/glob";
|
|
461
|
+
* import { descendEntries } from "@effected/walker";
|
|
462
|
+
* import { Effect, Option } from "effect";
|
|
463
|
+
*
|
|
464
|
+
* const signature = Effect.gen(function* () {
|
|
465
|
+
* const pattern = yield* GlobPattern.compile("**", GlobPatternOptions.make({ dot: true }));
|
|
466
|
+
* const entries = yield* descendEntries(pattern, { cwd: "/repo/src", boundaries: ["package.json"] });
|
|
467
|
+
* return entries.map((e) => `${e.path}:${Option.match(e.info.mtime, { onNone: () => "", onSome: (d) => d.getTime() })}`).join("|");
|
|
468
|
+
* });
|
|
469
|
+
* ```
|
|
470
|
+
*
|
|
471
|
+
* @public
|
|
472
|
+
*/
|
|
473
|
+
export declare function descendEntries(pattern: GlobPattern, options: DescendOptions): Effect.Effect<ReadonlyArray<DescendEntry>, DescendError, FileSystem.FileSystem | Path.Path>;
|
|
474
|
+
/**
|
|
475
|
+
* The stats {@link WalkerSyncFileSystem} answers — a structural subset of
|
|
476
|
+
* `node:fs` `Stats`, so `statSync` / `lstatSync` satisfy it verbatim.
|
|
477
|
+
*
|
|
478
|
+
* @public
|
|
479
|
+
*/
|
|
480
|
+
interface WalkerSyncStats {
|
|
481
|
+
/** Whether the entry is a regular file. */
|
|
482
|
+
isFile(): boolean;
|
|
483
|
+
/** Whether the entry is a directory. */
|
|
484
|
+
isDirectory(): boolean;
|
|
485
|
+
/** Whether the entry is a symbolic link (only ever true for `lstat`). */
|
|
486
|
+
isSymbolicLink(): boolean;
|
|
487
|
+
/** Modification time, epoch milliseconds. */
|
|
488
|
+
readonly mtimeMs: number;
|
|
489
|
+
/** Size in bytes. */
|
|
490
|
+
readonly size: number;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* The synchronous file operations the sync walk needs, supplied by the
|
|
494
|
+
* consumer — `node:fs` satisfies it (`nodeWalkerFileSystem` from
|
|
495
|
+
* `@effected/walker/node-sync`).
|
|
496
|
+
*
|
|
497
|
+
* @remarks
|
|
498
|
+
* Every member reports failure by throwing a node-shaped error. A `code` of
|
|
499
|
+
* `"ENOENT"` is the benign vanished-path race (empty, never recorded); any
|
|
500
|
+
* other throw from `readDirectory` or `realPath` is an unreadable directory,
|
|
501
|
+
* handled per `onUnreadable`. A throwing `stat` or `lstat` reads as "no
|
|
502
|
+
* entry", exactly as the `Effect` walk reads its failed `stat` and `lstat`.
|
|
503
|
+
*
|
|
504
|
+
* @public
|
|
505
|
+
*/
|
|
506
|
+
interface WalkerSyncFileSystem {
|
|
507
|
+
/** The entry names inside the directory at `path` (`readdirSync`). */
|
|
508
|
+
readonly readDirectory: (path: string) => ReadonlyArray<string>;
|
|
509
|
+
/** Stats of `path`, following links (`statSync`). */
|
|
510
|
+
readonly stat: (path: string) => WalkerSyncStats;
|
|
511
|
+
/** Stats of `path` itself, not following a final link (`lstatSync`). */
|
|
512
|
+
readonly lstat: (path: string) => WalkerSyncStats;
|
|
513
|
+
/** The real path of `path`, links resolved (`realpathSync`). */
|
|
514
|
+
readonly realPath: (path: string) => string;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* The synchronous path operations the sync forms need — a structural subset
|
|
518
|
+
* of `node:path`, so the module itself (or its `win32` / `posix` variant)
|
|
519
|
+
* satisfies it. It shapes only the absolute paths handed to the
|
|
520
|
+
* {@link WalkerSyncFileSystem}; matching is POSIX-relative by the glob
|
|
521
|
+
* contract.
|
|
522
|
+
*
|
|
523
|
+
* @remarks
|
|
524
|
+
* The members mirror core's `Path` service, so a sync form judges
|
|
525
|
+
* absoluteness, ascends and compares ceilings exactly as its `Effect` twin
|
|
526
|
+
* does under the `Path` layer of the same platform.
|
|
527
|
+
*
|
|
528
|
+
* @public
|
|
529
|
+
*/
|
|
530
|
+
interface WalkerSyncPath {
|
|
531
|
+
/** The implementation's separator (`path.sep`). */
|
|
532
|
+
readonly sep: string;
|
|
533
|
+
/** Join segments with the implementation's separator (like `path.join`). */
|
|
534
|
+
readonly join: (...segments: ReadonlyArray<string>) => string;
|
|
535
|
+
/** The parent directory of a path (like `path.dirname`); a fixpoint at the root. */
|
|
536
|
+
readonly dirname: (path: string) => string;
|
|
537
|
+
/** Resolve segments to a normalized path (like `path.resolve`). */
|
|
538
|
+
readonly resolve: (...segments: ReadonlyArray<string>) => string;
|
|
539
|
+
/** Whether a path is absolute under this implementation (like `path.isAbsolute`). */
|
|
540
|
+
readonly isAbsolute: (path: string) => boolean;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* The platform half of every sync walk.
|
|
544
|
+
*
|
|
545
|
+
* @public
|
|
546
|
+
*/
|
|
547
|
+
interface WalkerSyncOps {
|
|
548
|
+
/** File operations. */
|
|
549
|
+
readonly fileSystem: WalkerSyncFileSystem;
|
|
550
|
+
/** Path joining. */
|
|
551
|
+
readonly path: WalkerSyncPath;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Options for `descendSync` / `descendEntriesSync`: every `DescendOptions`
|
|
555
|
+
* field, plus the platform.
|
|
556
|
+
*
|
|
557
|
+
* @public
|
|
558
|
+
*/
|
|
559
|
+
interface DescendSyncOptions extends DescendOptions, WalkerSyncOps {}
|
|
560
|
+
/**
|
|
561
|
+
* {@link DescendSyncOptions} under `onUnreadable: "record"`.
|
|
562
|
+
*
|
|
563
|
+
* @public
|
|
564
|
+
*/
|
|
565
|
+
interface DescendSyncRecordOptions extends DescendRecordOptions, WalkerSyncOps {}
|
|
566
|
+
/**
|
|
567
|
+
* `descend` under `onUnreadable: "record"`, synchronously over a caller-supplied port.
|
|
568
|
+
*
|
|
569
|
+
* @public
|
|
570
|
+
*/
|
|
571
|
+
export declare function descendSync(pattern: GlobPattern, options: DescendSyncRecordOptions): Result.Result<DescendResult<unknown>, DescendError>;
|
|
572
|
+
/**
|
|
573
|
+
* `descend`, synchronously, over a caller-supplied file port: matching FILE
|
|
574
|
+
* paths relative to `cwd` (POSIX separators), sorted.
|
|
575
|
+
*
|
|
576
|
+
* @remarks
|
|
577
|
+
* The same walk as `descend` — it drives the same traversal, so every rule
|
|
578
|
+
* holds identically: the literal fast path, the enumeration prefix, `prune`,
|
|
579
|
+
* `boundaries`, the symlink posture and per-branch cycle guard under
|
|
580
|
+
* `followSymlinks`, `onUnreadable` and the `maxDepth` failure. Failures are a
|
|
581
|
+
* `Result` failure typed as `DescendError`; an invalid `maxDepth` is a defect
|
|
582
|
+
* and throws. For a caller with no Effect runtime (config evaluation, a Node
|
|
583
|
+
* SEA sidecar); inside Effect, use `descend`.
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```ts
|
|
587
|
+
* import { GlobPattern } from "@effected/glob";
|
|
588
|
+
* import { descendSync } from "@effected/walker";
|
|
589
|
+
* import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
|
|
590
|
+
* import { Result } from "effect";
|
|
591
|
+
*
|
|
592
|
+
* const pattern = Result.getOrThrow(GlobPattern.compileResult("src/**"));
|
|
593
|
+
* const files = descendSync(pattern, { cwd: "/repo", boundaries: ["package.json"], ...nodeWalkerSyncOps });
|
|
594
|
+
* ```
|
|
595
|
+
*
|
|
596
|
+
* @public
|
|
597
|
+
*/
|
|
598
|
+
export declare function descendSync(pattern: GlobPattern, options: DescendSyncOptions): Result.Result<ReadonlyArray<string>, DescendError>;
|
|
599
|
+
/**
|
|
600
|
+
* `descendEntries` under `onUnreadable: "record"`, synchronously over a caller-supplied port.
|
|
601
|
+
*
|
|
602
|
+
* @public
|
|
603
|
+
*/
|
|
604
|
+
export declare function descendEntriesSync(pattern: GlobPattern, options: DescendSyncRecordOptions): Result.Result<DescendEntriesResult<WalkerSyncStats, unknown>, DescendError>;
|
|
605
|
+
/**
|
|
606
|
+
* `descendEntries`, synchronously: `descendSync`'s matches, each with
|
|
607
|
+
* the stat the walk already read for it.
|
|
608
|
+
*
|
|
609
|
+
* @public
|
|
610
|
+
*/
|
|
611
|
+
export declare function descendEntriesSync(pattern: GlobPattern, options: DescendSyncOptions): Result.Result<ReadonlyArray<DescendEntry<WalkerSyncStats>>, DescendError>;
|
|
612
|
+
/**
|
|
613
|
+
* Confine a path to a base directory PHYSICALLY: resolve links in both, and
|
|
614
|
+
* succeed with the candidate's real path only when it lies strictly inside
|
|
615
|
+
* the base's real path.
|
|
616
|
+
*
|
|
617
|
+
* @remarks
|
|
618
|
+
* Reach for it where `confineRelative` stops: a link inside the base that
|
|
619
|
+
* points out of it (a symlinked `dist`, a planted `node_modules` entry), an
|
|
620
|
+
* absolute path an agent or a tool handed over, a `descend` match — a
|
|
621
|
+
* matched link is answered even when its target lies outside `cwd`.
|
|
622
|
+
*
|
|
623
|
+
* The candidate may be absolute (checked as it is) or relative (taken
|
|
624
|
+
* against `base`). It is resolved the way the operating system resolves it:
|
|
625
|
+
* segment by segment, so a `..` after a link climbs out of the link's
|
|
626
|
+
* TARGET — `base/link/../x` is outside when `link` points outside — rather
|
|
627
|
+
* than being collapsed lexically first, as `path.resolve` and node's JS
|
|
628
|
+
* `fs.realpath` would. A path, or the tail of one, that does not exist yet
|
|
629
|
+
* is resolved lexically from its real existing ancestor, so a write target
|
|
630
|
+
* can be checked before it is created — but only once absence is proved: a
|
|
631
|
+
* segment whose real path is not found is checked again without following
|
|
632
|
+
* links, because a dangling link is "not found" too, and a write through one
|
|
633
|
+
* creates its target wherever it points. The base is resolved the same way.
|
|
634
|
+
*
|
|
635
|
+
* Refused, typed as {@link PathEscapeError}: a NUL character (`nulByte`);
|
|
636
|
+
* the empty string or any path whose real location IS the base (`empty`,
|
|
637
|
+
* the same ruling `confineRelative` makes — a caller confining a path names
|
|
638
|
+
* an entry under the base); on win32 a drive-relative `C:x` or a driveless
|
|
639
|
+
* rooted `\x`, which names the current drive (`absolute`), or a segment
|
|
640
|
+
* win32 reads as something else, such as a device name or `.. `
|
|
641
|
+
* (`reservedName`); a real path outside the base's (`outside`); and a
|
|
642
|
+
* resolution that fails for a reason other than absence, such as a
|
|
643
|
+
* permission error, a link loop, or a dangling link — a link whose target
|
|
644
|
+
* does not exist, refused even when that target would lie inside the base
|
|
645
|
+
* (`unresolvable`, with the failure in `cause`) — containment that cannot be
|
|
646
|
+
* verified is refused, never assumed.
|
|
647
|
+
*
|
|
648
|
+
* A relative `base` — the empty string included — is a **defect**: it would
|
|
649
|
+
* be resolved against the process working directory, the silent wrong-root
|
|
650
|
+
* walk `ascend` refuses for a relative `stopAt`. Absoluteness is judged by
|
|
651
|
+
* the injected `Path`, so win32 accepts `C:\repo` and `\\server\share`;
|
|
652
|
+
* a win32 `\repo`, rooted on whichever drive the process is on, is a defect
|
|
653
|
+
* too.
|
|
654
|
+
*
|
|
655
|
+
* Use the returned path, not the candidate: it is the location that was
|
|
656
|
+
* checked. Comparison is exact on the real paths, so on a case-insensitive
|
|
657
|
+
* filesystem a base and a candidate spelled in different case may be refused
|
|
658
|
+
* — the check fails closed. As with any check-then-use on a live filesystem,
|
|
659
|
+
* a link swapped in between the check and the use is not covered.
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```ts
|
|
663
|
+
* import { confineReal } from "@effected/walker";
|
|
664
|
+
* import { Effect } from "effect";
|
|
665
|
+
*
|
|
666
|
+
* const target = confineReal("/repo", "packages/app/dist").pipe(
|
|
667
|
+
* Effect.catchTag("PathEscapeError", (error) => Effect.die(error)),
|
|
668
|
+
* );
|
|
669
|
+
* // Requires `FileSystem` and `Path` from the platform layer.
|
|
670
|
+
* ```
|
|
671
|
+
*
|
|
672
|
+
* @param base - The absolute directory the candidate must stay under.
|
|
673
|
+
* @param candidate - The path to check: absolute, or relative to `base`.
|
|
674
|
+
* @returns An `Effect` succeeding with the candidate's real path, or failing
|
|
675
|
+
* with {@link PathEscapeError}.
|
|
676
|
+
*
|
|
677
|
+
* @public
|
|
678
|
+
*/
|
|
679
|
+
export declare const confineReal: (base: string, candidate: string) => Effect.Effect<string, PathEscapeError, FileSystem.FileSystem | Path.Path>;
|
|
680
|
+
/**
|
|
681
|
+
* {@link confineReal}, synchronously, over a caller-supplied port.
|
|
682
|
+
*
|
|
683
|
+
* @remarks
|
|
684
|
+
* The same resolution from the same code, through the port's `realPath`; a
|
|
685
|
+
* `realPath` throwing `code: "ENOENT"` is absence only when the port's
|
|
686
|
+
* `lstat` throws `ENOENT` too (otherwise a dangling link is there); anything
|
|
687
|
+
* else is `unresolvable`, with the thrown value as the `cause`. A relative `base`
|
|
688
|
+
* throws. For a caller with no Effect runtime; inside Effect, use
|
|
689
|
+
* `confineReal`.
|
|
690
|
+
*
|
|
691
|
+
* @example
|
|
692
|
+
* ```ts
|
|
693
|
+
* import { confineRealSync } from "@effected/walker";
|
|
694
|
+
* import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
|
|
695
|
+
* import { Result } from "effect";
|
|
696
|
+
*
|
|
697
|
+
* const checked = confineRealSync("/repo", "/repo/packages/app/dist", nodeWalkerSyncOps);
|
|
698
|
+
* if (Result.isFailure(checked)) console.error(checked.failure.message);
|
|
699
|
+
* ```
|
|
700
|
+
*
|
|
701
|
+
* @param base - The absolute directory the candidate must stay under.
|
|
702
|
+
* @param candidate - The path to check: absolute, or relative to `base`.
|
|
703
|
+
* @param ops - The platform: spread or pass `nodeWalkerSyncOps`.
|
|
704
|
+
* @returns A `Result` succeeding with the candidate's real path, or failing
|
|
705
|
+
* with {@link PathEscapeError}.
|
|
706
|
+
*
|
|
707
|
+
* @public
|
|
708
|
+
*/
|
|
709
|
+
export declare const confineRealSync: (base: string, candidate: string, ops: WalkerSyncOps) => Result.Result<string, PathEscapeError>;
|
|
335
710
|
/**
|
|
336
711
|
* Options for {@link compileAndExpand}: every {@link DescendOptions} field,
|
|
337
712
|
* plus the glob options the pattern compiles under.
|
|
@@ -472,7 +847,8 @@ interface AscendOptions {
|
|
|
472
847
|
*
|
|
473
848
|
* Only the CEILING is constrained — a relative `start` is fine and ascends
|
|
474
849
|
* to the relative root. Absoluteness is judged by the injected `Path`
|
|
475
|
-
* service, so the win32 layer accepts `C:\repo` and posix does not
|
|
850
|
+
* service, so the win32 layer accepts `C:\repo` and posix does not; a
|
|
851
|
+
* win32 `\repo`, rooted on whichever drive the process is on, dies too.
|
|
476
852
|
*
|
|
477
853
|
* Normalization governs the comparison only: the chain `ascend` returns is
|
|
478
854
|
* still the lexical one derived from `start`, unrewritten. A ceiling naming
|
|
@@ -488,6 +864,37 @@ interface AscendOptions {
|
|
|
488
864
|
/** Hard cap on chain length. Defaults to 256. */
|
|
489
865
|
readonly maxDepth?: number;
|
|
490
866
|
}
|
|
867
|
+
/**
|
|
868
|
+
* Options for {@link Walker.ascendSync}: every {@link AscendOptions} field,
|
|
869
|
+
* plus the path implementation the chain is computed with.
|
|
870
|
+
*
|
|
871
|
+
* @public
|
|
872
|
+
*/
|
|
873
|
+
interface AscendSyncOptions extends AscendOptions {
|
|
874
|
+
/** Path arithmetic — `node:path` satisfies it (`nodeWalkerPath` from `@effected/walker/node-sync`). */
|
|
875
|
+
readonly path: WalkerSyncPath;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Options for the synchronous upward forms that touch the filesystem —
|
|
879
|
+
* {@link Walker.ascendWithinSync} and {@link Walker.ascendToMarkerSync}: the
|
|
880
|
+
* depth cap, plus the platform (spread `nodeWalkerSyncOps` from
|
|
881
|
+
* `@effected/walker/node-sync`).
|
|
882
|
+
*
|
|
883
|
+
* @public
|
|
884
|
+
*/
|
|
885
|
+
interface AscendWithinSyncOptions extends Pick<AscendOptions, "maxDepth">, WalkerSyncOps {}
|
|
886
|
+
/**
|
|
887
|
+
* {@link Walker.findUpwardAll}'s answer: the nearest directory holding any
|
|
888
|
+
* candidate, and every candidate that exists there.
|
|
889
|
+
*
|
|
890
|
+
* @public
|
|
891
|
+
*/
|
|
892
|
+
interface UpwardMatches {
|
|
893
|
+
/** The directory whose candidates produced the hits. */
|
|
894
|
+
readonly dir: string;
|
|
895
|
+
/** Every existing candidate of `dir`, in the order `candidatesFor` gave them. Never empty. */
|
|
896
|
+
readonly found: readonly [string, ...Array<string>];
|
|
897
|
+
}
|
|
491
898
|
/**
|
|
492
899
|
* Upward path traversal primitives: the directory chain from a start path to the
|
|
493
900
|
* root, and first-match scans over it.
|
|
@@ -592,6 +999,171 @@ export declare class Walker {
|
|
|
592
999
|
* `pnpm-workspace.yaml`), and its failures are absorbed per directory.
|
|
593
1000
|
*/
|
|
594
1001
|
static findRoot<E, R>(dirs: ReadonlyArray<string>, isRoot: (dir: string) => Effect.Effect<boolean, E, R>): Effect.Effect<Option.Option<string>, never, R>;
|
|
1002
|
+
/**
|
|
1003
|
+
* {@link Walker.ascend} stopped at the nearest directory that holds any of
|
|
1004
|
+
* `markers`, inclusive: the chain from `start` up to and including the
|
|
1005
|
+
* first directory with a `.git` (or whatever the markers name) entry.
|
|
1006
|
+
*
|
|
1007
|
+
* @remarks
|
|
1008
|
+
* A marker is an entry NAME probed with `FileSystem.exists` in each
|
|
1009
|
+
* directory, nearest first, so any entry kind counts — a `.git` directory,
|
|
1010
|
+
* or the `.git` FILE of a worktree or submodule — and a link counts when it
|
|
1011
|
+
* resolves. The probes stop at the hit: nothing above the directory that
|
|
1012
|
+
* holds a marker is ever touched. With no marker anywhere the chain runs to
|
|
1013
|
+
* the filesystem root, exactly as `ascend(start)` gives it.
|
|
1014
|
+
*
|
|
1015
|
+
* A failed probe is absorbed as "no marker here", as
|
|
1016
|
+
* {@link Walker.firstMatch} absorbs one, so one unreadable directory never
|
|
1017
|
+
* hides a marker above it. An empty `markers` list, or an empty marker
|
|
1018
|
+
* name, is a **defect**: the first would silently ask for the unbounded
|
|
1019
|
+
* walk and the second would match every directory, and both are
|
|
1020
|
+
* statically wrong at the call site. An invalid `maxDepth` dies exactly as
|
|
1021
|
+
* `ascend`'s does.
|
|
1022
|
+
*
|
|
1023
|
+
* There is no `stopAt` here: a marker stop and a lexical ceiling answer the
|
|
1024
|
+
* same question two ways. To bound a marker walk by a ceiling as well,
|
|
1025
|
+
* take the shorter of the two chains.
|
|
1026
|
+
*
|
|
1027
|
+
* @example
|
|
1028
|
+
* ```ts
|
|
1029
|
+
* import { Walker } from "@effected/walker";
|
|
1030
|
+
* import { Effect } from "effect";
|
|
1031
|
+
*
|
|
1032
|
+
* const program = Effect.gen(function* () {
|
|
1033
|
+
* // With `.git` in /repo: ["/repo/packages/app", "/repo/packages", "/repo"]
|
|
1034
|
+
* return yield* Walker.ascendToMarker("/repo/packages/app", [".git"]);
|
|
1035
|
+
* });
|
|
1036
|
+
* // Requires `FileSystem` and `Path` from the platform layer.
|
|
1037
|
+
* ```
|
|
1038
|
+
*/
|
|
1039
|
+
static ascendToMarker(start: string, markers: ReadonlyArray<string>, options?: Pick<AscendOptions, "maxDepth">): Effect.Effect<ReadonlyArray<string>, never, FileSystem.FileSystem | Path.Path>;
|
|
1040
|
+
/**
|
|
1041
|
+
* Every existing candidate of the NEAREST directory in `dirs` that has any,
|
|
1042
|
+
* or `Option.none()` — {@link Walker.findUpward} for a caller that must see
|
|
1043
|
+
* a second hit (an ambiguity) rather than have the first one chosen.
|
|
1044
|
+
*
|
|
1045
|
+
* @remarks
|
|
1046
|
+
* Directories are scanned in order, and every candidate of a directory is
|
|
1047
|
+
* probed before the scan ascends; the scan stops after the first directory
|
|
1048
|
+
* with a hit, so nothing above it is probed. `found` keeps the order
|
|
1049
|
+
* `candidatesFor` produced and is never empty. A failed probe is absorbed
|
|
1050
|
+
* as "not there", as in `findUpward`, so not-found and cannot-look are
|
|
1051
|
+
* indistinguishable here too.
|
|
1052
|
+
*
|
|
1053
|
+
* @example
|
|
1054
|
+
* ```ts
|
|
1055
|
+
* import { Walker } from "@effected/walker";
|
|
1056
|
+
* import { Effect, Option } from "effect";
|
|
1057
|
+
*
|
|
1058
|
+
* const program = Effect.gen(function* () {
|
|
1059
|
+
* const dirs = yield* Walker.ascend("/repo/packages/app");
|
|
1060
|
+
* const hits = yield* Walker.findUpwardAll(dirs, (dir) => [`${dir}/tool.config.ts`, `${dir}/tool.config.js`]);
|
|
1061
|
+
* // Two config files in one directory is the caller's ambiguity to report.
|
|
1062
|
+
* return Option.map(hits, ({ found }) => found.length > 1);
|
|
1063
|
+
* });
|
|
1064
|
+
* ```
|
|
1065
|
+
*/
|
|
1066
|
+
static findUpwardAll(dirs: ReadonlyArray<string>, candidatesFor: (dir: string) => ReadonlyArray<string>): Effect.Effect<Option.Option<UpwardMatches>, never, FileSystem.FileSystem>;
|
|
1067
|
+
/**
|
|
1068
|
+
* {@link Walker.ascend}, synchronously, over a caller-supplied path
|
|
1069
|
+
* implementation.
|
|
1070
|
+
*
|
|
1071
|
+
* @remarks
|
|
1072
|
+
* The same chain from the same code: lexical, nearest first, `stopAt`
|
|
1073
|
+
* inclusive and compared in resolved form. A relative `stopAt` or an
|
|
1074
|
+
* invalid `maxDepth` is a defect, which here THROWS, since there is no
|
|
1075
|
+
* error channel to die through. For a caller with no Effect runtime (a CLI
|
|
1076
|
+
* helper that runs before one, a bundler-plugin hook); inside Effect, use
|
|
1077
|
+
* `ascend`.
|
|
1078
|
+
*
|
|
1079
|
+
* @example
|
|
1080
|
+
* ```ts
|
|
1081
|
+
* import { Walker } from "@effected/walker";
|
|
1082
|
+
* import { nodeWalkerPath } from "@effected/walker/node-sync";
|
|
1083
|
+
*
|
|
1084
|
+
* const dirs = Walker.ascendSync("/repo/packages/app", { stopAt: "/repo", path: nodeWalkerPath });
|
|
1085
|
+
* // => ["/repo/packages/app", "/repo/packages", "/repo"]
|
|
1086
|
+
* ```
|
|
1087
|
+
*/
|
|
1088
|
+
static ascendSync(start: string, options: AscendSyncOptions): ReadonlyArray<string>;
|
|
1089
|
+
/**
|
|
1090
|
+
* {@link Walker.ascendWithin}, synchronously, over a caller-supplied port:
|
|
1091
|
+
* the lexical chain stopped at the nearest directory whose `realPath` is
|
|
1092
|
+
* the ceiling's.
|
|
1093
|
+
*
|
|
1094
|
+
* @remarks
|
|
1095
|
+
* The same walk from the same code as `ascendWithin`: `Option.none()` is
|
|
1096
|
+
* exactly `ascendSync(start)`, a ceiling the chain already spells costs no
|
|
1097
|
+
* `realPath`, a `realPath` that throws is absorbed as "not the ceiling",
|
|
1098
|
+
* and an unresolvable ceiling leaves the lexical chain standing. A
|
|
1099
|
+
* relative ceiling or an invalid `maxDepth` throws.
|
|
1100
|
+
*
|
|
1101
|
+
* @example
|
|
1102
|
+
* ```ts
|
|
1103
|
+
* import { Walker } from "@effected/walker";
|
|
1104
|
+
* import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
|
|
1105
|
+
* import { Option } from "effect";
|
|
1106
|
+
*
|
|
1107
|
+
* const dirs = Walker.ascendWithinSync("/repo/packages/app", Option.some("/repo"), nodeWalkerSyncOps);
|
|
1108
|
+
* ```
|
|
1109
|
+
*/
|
|
1110
|
+
static ascendWithinSync(start: string, ceiling: Option.Option<string>, options: AscendWithinSyncOptions): ReadonlyArray<string>;
|
|
1111
|
+
/**
|
|
1112
|
+
* {@link Walker.ascendToMarker}, synchronously, over a caller-supplied port.
|
|
1113
|
+
*
|
|
1114
|
+
* @remarks
|
|
1115
|
+
* The same walk from the same code. A marker exists when the port's `stat`
|
|
1116
|
+
* (links followed) answers for it; a `stat` that throws, for any reason,
|
|
1117
|
+
* is "no marker here", as the `Effect` form absorbs a failed probe. An
|
|
1118
|
+
* empty `markers` list, an empty marker name or an invalid `maxDepth`
|
|
1119
|
+
* throws.
|
|
1120
|
+
*
|
|
1121
|
+
* @example
|
|
1122
|
+
* ```ts
|
|
1123
|
+
* import { Walker } from "@effected/walker";
|
|
1124
|
+
* import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
|
|
1125
|
+
*
|
|
1126
|
+
* const dirs = Walker.ascendToMarkerSync("/repo/packages/app", [".git"], nodeWalkerSyncOps);
|
|
1127
|
+
* ```
|
|
1128
|
+
*/
|
|
1129
|
+
static ascendToMarkerSync(start: string, markers: ReadonlyArray<string>, options: AscendWithinSyncOptions): ReadonlyArray<string>;
|
|
1130
|
+
/**
|
|
1131
|
+
* {@link Walker.findUpward}, synchronously, over a caller-supplied port: the
|
|
1132
|
+
* first existing candidate, directory-major, or `Option.none()`.
|
|
1133
|
+
*
|
|
1134
|
+
* @remarks
|
|
1135
|
+
* The same scan from the same code. A candidate exists when the port's
|
|
1136
|
+
* `stat` (links followed) answers for it; a `stat` that throws is "not
|
|
1137
|
+
* there". A throwing `candidatesFor` throws before any probe.
|
|
1138
|
+
*
|
|
1139
|
+
* @example
|
|
1140
|
+
* ```ts
|
|
1141
|
+
* import { Walker } from "@effected/walker";
|
|
1142
|
+
* import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
|
|
1143
|
+
*
|
|
1144
|
+
* const dirs = Walker.ascendSync("/repo/packages/app", { path: nodeWalkerSyncOps.path });
|
|
1145
|
+
* const workspace = Walker.findUpwardSync(dirs, (dir) => [`${dir}/pnpm-workspace.yaml`], nodeWalkerSyncOps);
|
|
1146
|
+
* ```
|
|
1147
|
+
*/
|
|
1148
|
+
static findUpwardSync(dirs: ReadonlyArray<string>, candidatesFor: (dir: string) => ReadonlyArray<string>, ops: WalkerSyncOps): Option.Option<string>;
|
|
1149
|
+
/**
|
|
1150
|
+
* {@link Walker.findUpwardAll}, synchronously, over a caller-supplied port.
|
|
1151
|
+
*
|
|
1152
|
+
* @remarks
|
|
1153
|
+
* The same scan from the same code: every existing candidate of the
|
|
1154
|
+
* nearest directory with any, in candidate order, and nothing above it
|
|
1155
|
+
* probed. A candidate exists when the port's `stat` answers for it.
|
|
1156
|
+
*
|
|
1157
|
+
* @example
|
|
1158
|
+
* ```ts
|
|
1159
|
+
* import { Walker } from "@effected/walker";
|
|
1160
|
+
* import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
|
|
1161
|
+
*
|
|
1162
|
+
* const dirs = Walker.ascendSync("/repo/packages/app", { path: nodeWalkerSyncOps.path });
|
|
1163
|
+
* const hits = Walker.findUpwardAllSync(dirs, (dir) => [`${dir}/a.config.ts`, `${dir}/a.config.js`], nodeWalkerSyncOps);
|
|
1164
|
+
* ```
|
|
1165
|
+
*/
|
|
1166
|
+
static findUpwardAllSync(dirs: ReadonlyArray<string>, candidatesFor: (dir: string) => ReadonlyArray<string>, ops: WalkerSyncOps): Option.Option<UpwardMatches>;
|
|
595
1167
|
}
|
|
596
|
-
export type { AscendOptions, CompileAndExpandOptions, DescendOptions, DescendRecordOptions, DescendResult, UnreadableDirectory };
|
|
1168
|
+
export type { AscendOptions, AscendSyncOptions, AscendWithinSyncOptions, CompileAndExpandOptions, DescendEntriesResult, DescendEntry, DescendOptions, DescendRecordOptions, DescendResult, DescendSyncOptions, DescendSyncRecordOptions, UnreadableDirectory, UpwardMatches, WalkerSyncFileSystem, WalkerSyncOps, WalkerSyncPath, WalkerSyncStats };
|
|
597
1169
|
//# sourceMappingURL=index.d.ts.map
|