@zthun/crumbtrail-fs 2.4.12 → 3.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/dist/index.cjs +214 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.js +193 -11
- package/dist/index.js.map +1 -1
- package/dist/job-nudge/job-nudge.d.mts +52 -0
- package/dist/job-watch/job-watch.d.mts +101 -0
- package/package.json +11 -8
- package/dist/vite.config.d.mts +0 -2
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
2
24
|
let node_path = require("node:path");
|
|
3
25
|
let _zthun_helpful_fn = require("@zthun/helpful-fn");
|
|
4
26
|
let _zthun_helpful_query = require("@zthun/helpful-query");
|
|
@@ -9,6 +31,9 @@ let node_process = require("node:process");
|
|
|
9
31
|
let glob = require("glob");
|
|
10
32
|
let chokidar = require("chokidar");
|
|
11
33
|
let rxjs = require("rxjs");
|
|
34
|
+
let _zthun_lumberjacky_log = require("@zthun/lumberjacky-log");
|
|
35
|
+
let fast_glob = require("fast-glob");
|
|
36
|
+
fast_glob = __toESM(fast_glob, 1);
|
|
12
37
|
let node_url = require("node:url");
|
|
13
38
|
let path = require("path");
|
|
14
39
|
let fs_promises = require("fs/promises");
|
|
@@ -285,13 +310,6 @@ let fs_promises = require("fs/promises");
|
|
|
285
310
|
}
|
|
286
311
|
};
|
|
287
312
|
//#endregion
|
|
288
|
-
//#region src/resolve-path-like/resolve-path-like.ts
|
|
289
|
-
function resolvePathLike(path) {
|
|
290
|
-
if (typeof path === "string") return (0, node_path.resolve)(path);
|
|
291
|
-
if (path instanceof URL) return (0, node_url.fileURLToPath)(path);
|
|
292
|
-
return (0, node_path.resolve)(path.toString());
|
|
293
|
-
}
|
|
294
|
-
//#endregion
|
|
295
313
|
//#region src/sleep-watch-delay/sleep-watch-delay.mts
|
|
296
314
|
/**
|
|
297
315
|
* The actual delay time that you should wait for a watch
|
|
@@ -309,6 +327,193 @@ function resolvePathLike(path) {
|
|
|
309
327
|
return (0, _zthun_helpful_fn.sleep)(ZWatchDelay);
|
|
310
328
|
}
|
|
311
329
|
//#endregion
|
|
330
|
+
//#region src/job-nudge/job-nudge.mts
|
|
331
|
+
/**
|
|
332
|
+
* An operation to continuously nudge a directory.
|
|
333
|
+
*
|
|
334
|
+
* This is a special operation that lists the contents of a targeted parent directory.
|
|
335
|
+
* The main reason for this is to work around an issue when you are running inside of
|
|
336
|
+
* a container and your host is not linux.
|
|
337
|
+
*
|
|
338
|
+
* A lot of times, you will not receive events in this situation for add and update
|
|
339
|
+
* until the virtual file bridge is refreshed by listing the outer directory contents.
|
|
340
|
+
* This command helps to force the bridge to send file change events. You should
|
|
341
|
+
* only need this if you are running on a non linux host inside a docker container.
|
|
342
|
+
*
|
|
343
|
+
* Run a separate container in the background and just nudge the directory
|
|
344
|
+
* for however long you need.
|
|
345
|
+
*/ var ZCrumbtrailJobNudge = class {
|
|
346
|
+
_controller;
|
|
347
|
+
_resolve;
|
|
348
|
+
_promise;
|
|
349
|
+
_logger;
|
|
350
|
+
constructor(logger) {
|
|
351
|
+
this._logger = new _zthun_lumberjacky_log.ZLoggerContext("ZCrumbtrailNudge", logger);
|
|
352
|
+
}
|
|
353
|
+
async kill() {
|
|
354
|
+
this._controller?.abort();
|
|
355
|
+
delete this._controller;
|
|
356
|
+
await this._promise;
|
|
357
|
+
delete this._promise;
|
|
358
|
+
}
|
|
359
|
+
async run(options = {}) {
|
|
360
|
+
await this.kill();
|
|
361
|
+
const controller = new AbortController();
|
|
362
|
+
this._controller = controller;
|
|
363
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
364
|
+
this._promise = promise;
|
|
365
|
+
this._resolve = resolve;
|
|
366
|
+
const { directory = process.cwd(), recursive, every = ZWatchDelay } = options;
|
|
367
|
+
const ms = (0, _zthun_helpful_fn.firstTruthy)(ZWatchDelay, every);
|
|
368
|
+
this._logger.log(new _zthun_lumberjacky_log.ZLogEntryBuilder().info().message(`Starting a nudge loop every ${ms} milliseconds`).build());
|
|
369
|
+
if (recursive) this._logger.log(new _zthun_lumberjacky_log.ZLogEntryBuilder().warning().message("Nudging is recursive. Child folders will be nudged too.").build());
|
|
370
|
+
do {
|
|
371
|
+
this._logger.log(new _zthun_lumberjacky_log.ZLogEntryBuilder().info().message(`Nudging ${directory} to refresh`).build());
|
|
372
|
+
await (0, node_fs_promises.readdir)((0, node_path.dirname)(directory)).catch(lodash_es.noop);
|
|
373
|
+
if (recursive) await (0, fast_glob.default)(`${directory}/**`, { onlyDirectories: true }).catch(lodash_es.noop);
|
|
374
|
+
await (0, _zthun_helpful_fn.sleep)(ms);
|
|
375
|
+
} while (!controller.signal.aborted);
|
|
376
|
+
resolve(0);
|
|
377
|
+
delete this._resolve;
|
|
378
|
+
return this._promise;
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region src/job-watch/job-watch.mts
|
|
383
|
+
/**
|
|
384
|
+
* The root application for the crumbtrail cli.
|
|
385
|
+
*/ var ZCrumbtrailJobWatch = class ZCrumbtrailJobWatch {
|
|
386
|
+
_logger;
|
|
387
|
+
_globs;
|
|
388
|
+
_watch;
|
|
389
|
+
_ready = Promise.resolve();
|
|
390
|
+
_promise;
|
|
391
|
+
_resolve;
|
|
392
|
+
/**
|
|
393
|
+
* Gets the entry for a basic information message.
|
|
394
|
+
*
|
|
395
|
+
* @returns
|
|
396
|
+
* The log entry for a basic information message.
|
|
397
|
+
*/ static msg(msg) {
|
|
398
|
+
return new _zthun_lumberjacky_log.ZLogEntryBuilder().info().message(msg).build();
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Gets the message for when a file is added.
|
|
402
|
+
*
|
|
403
|
+
* @returns
|
|
404
|
+
* The message for when a file is added.
|
|
405
|
+
*/ static add(path) {
|
|
406
|
+
return new _zthun_lumberjacky_log.ZLogEntryBuilder().info().message(`Node added: ${path}`).build();
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Gets the message for when a file/folder is removed.
|
|
410
|
+
*
|
|
411
|
+
* @returns
|
|
412
|
+
* The message for when a file/folder is added.
|
|
413
|
+
*/ static remove(path) {
|
|
414
|
+
return new _zthun_lumberjacky_log.ZLogEntryBuilder().warning().message(`Node removed: ${path}`).build();
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Gets the message for when a file is updated.
|
|
418
|
+
*
|
|
419
|
+
* @returns
|
|
420
|
+
* The message for when a file is updated.
|
|
421
|
+
*/ static update(path) {
|
|
422
|
+
return new _zthun_lumberjacky_log.ZLogEntryBuilder().info().message(`Node updated: ${path}`).build();
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Gets the current directory being watched.
|
|
426
|
+
*
|
|
427
|
+
* @returns
|
|
428
|
+
* The directory that is watching for events.
|
|
429
|
+
*/ watching() {
|
|
430
|
+
return Promise.resolve(this._watch?.path);
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Gets the list of globs that filter the directory contents.
|
|
434
|
+
*
|
|
435
|
+
* @returns
|
|
436
|
+
* The list of globs that filter the directory contents.
|
|
437
|
+
*/ globs() {
|
|
438
|
+
return Promise.resolve(this._globs?.slice());
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Returns a promise that can be awaited on to
|
|
442
|
+
* make sure the watch is initialized.
|
|
443
|
+
*/ async ready() {
|
|
444
|
+
return this._ready;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Initializes a new instance of this object.
|
|
448
|
+
*
|
|
449
|
+
* @param logger -
|
|
450
|
+
* The logger to use to output events.
|
|
451
|
+
*/ constructor(logger) {
|
|
452
|
+
this._logger = new _zthun_lumberjacky_log.ZLoggerContext("ZCrumbtrailApp", logger);
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Kills the application.
|
|
456
|
+
*/ async kill() {
|
|
457
|
+
await this._watch?.stop();
|
|
458
|
+
delete this._watch;
|
|
459
|
+
delete this._globs;
|
|
460
|
+
this._ready = Promise.resolve();
|
|
461
|
+
this._resolve?.(0);
|
|
462
|
+
await this._promise;
|
|
463
|
+
delete this._promise;
|
|
464
|
+
}
|
|
465
|
+
_handleFsEvent(path, entry) {
|
|
466
|
+
const globs = (0, _zthun_helpful_fn.firstDefined)(["**"], this._globs);
|
|
467
|
+
const directory = (0, _zthun_helpful_fn.firstDefined)((0, node_process.cwd)(), this._watch?.path);
|
|
468
|
+
if (globs?.some((g) => (0, minimatch.minimatch)(path, (0, node_path.resolve)(directory, g)))) this._logger.log(entry);
|
|
469
|
+
}
|
|
470
|
+
_handleAdd(node) {
|
|
471
|
+
this._handleFsEvent(node.path, ZCrumbtrailJobWatch.add(node.path));
|
|
472
|
+
}
|
|
473
|
+
_handleRemove(node) {
|
|
474
|
+
this._handleFsEvent(node.path, ZCrumbtrailJobWatch.remove(node.path));
|
|
475
|
+
}
|
|
476
|
+
_handleUpdate(node) {
|
|
477
|
+
this._handleFsEvent(node.path, ZCrumbtrailJobWatch.update(node.path));
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Runs the application.
|
|
481
|
+
*
|
|
482
|
+
* @param args -
|
|
483
|
+
* The application arguments.
|
|
484
|
+
*
|
|
485
|
+
* @returns
|
|
486
|
+
* The process exit code.
|
|
487
|
+
*/ async run(args = {}) {
|
|
488
|
+
if (this._promise) return this._promise;
|
|
489
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
490
|
+
this._resolve = resolve;
|
|
491
|
+
this._promise = promise;
|
|
492
|
+
const { directory = (0, node_process.cwd)(), globs = ["**"] } = args;
|
|
493
|
+
this._globs = (0, lodash_es.uniq)(globs.slice());
|
|
494
|
+
this._globs = this._globs.length ? this._globs : ["**"];
|
|
495
|
+
this._watch = new ZFileWatch(directory);
|
|
496
|
+
const filter = globs.join(",");
|
|
497
|
+
this._logger.log(ZCrumbtrailJobWatch.msg("Welcome to Crumbtrail CLI"));
|
|
498
|
+
this._logger.log(ZCrumbtrailJobWatch.msg(`You are now watching ${directory}`));
|
|
499
|
+
this._logger.log(ZCrumbtrailJobWatch.msg(`Logging files matching ${filter}.`));
|
|
500
|
+
this._logger.log(ZCrumbtrailJobWatch.msg("Press Ctrl+C to stop watching"));
|
|
501
|
+
this._watch.add().subscribe(this._handleAdd.bind(this));
|
|
502
|
+
this._watch.remove().subscribe(this._handleRemove.bind(this));
|
|
503
|
+
this._watch.update().subscribe(this._handleUpdate.bind(this));
|
|
504
|
+
this._ready = this._watch.start();
|
|
505
|
+
await this._ready;
|
|
506
|
+
return this._promise;
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
//#endregion
|
|
510
|
+
//#region src/resolve-path-like/resolve-path-like.ts
|
|
511
|
+
function resolvePathLike(path) {
|
|
512
|
+
if (typeof path === "string") return (0, node_path.resolve)(path);
|
|
513
|
+
if (path instanceof URL) return (0, node_url.fileURLToPath)(path);
|
|
514
|
+
return (0, node_path.resolve)(path.toString());
|
|
515
|
+
}
|
|
516
|
+
//#endregion
|
|
312
517
|
//#region src/stream/stream-folder.mts
|
|
313
518
|
/**
|
|
314
519
|
* A stream that writes folders.
|
|
@@ -378,6 +583,8 @@ function resolvePathLike(path) {
|
|
|
378
583
|
}
|
|
379
584
|
};
|
|
380
585
|
//#endregion
|
|
586
|
+
exports.ZCrumbtrailJobNudge = ZCrumbtrailJobNudge;
|
|
587
|
+
exports.ZCrumbtrailJobWatch = ZCrumbtrailJobWatch;
|
|
381
588
|
exports.ZFileRepository = ZFileRepository;
|
|
382
589
|
exports.ZFileSystemNodeBuilder = ZFileSystemNodeBuilder;
|
|
383
590
|
exports.ZFileSystemNodeType = ZFileSystemNodeType;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["basename","dirname","extname","isUndefined","omitBy","ZFileSystemNodeType","ZFileSystemNodeBuilder","_node","path","type","extension","name","parent","title","created","at","Date","toJSON","updated","size","bytes","BigInt","decorate","file","bind","folder","stats","s","builder","birthtime","mtime","isFile","build","clone","structuredClone","access","dirname","isAbsolute","resolve","cwd","glob","ZFileSystemNodeBuilder","ZFileSystemService","info","path","file","search","pattern","options","paths","stat","withFileTypes","map","fullpath","created","birthtime","updated","atime","size","isFile","folder","undefined","build","walk","start","stop","mode","_test","dir","exists","length","resolve","watch","Subject","ZFileSystemNodeBuilder","ZFileWatch","_add","_update","_remove","_watcher","path","start","stop","usePolling","alwaysStat","ignoreInitial","awaitWriteFinish","stabilityThreshold","pollInterval","next","observable","file","stats","node","build","on","bind","Promise","close","add","asObservable","update","remove","resolve","sep","firstDefined","sleep","ZDataSourceStatic","find","findIndex","flatten","trimEnd","uniqBy","minimatch","ZFileSystemNodeType","ZFileSystemService","ZFileWatch","ZFileRepository","_service","_watcher","_nodes","Promise","_globs","_path","_add","_remove","_update","path","globs","slice","initialize","reset","matches","map","g","search","cwd","stat","all","then","nodes","flat","uniq","n","filter","type","File","files","add","subscribe","node","some","insert","remove","next","items","startsWith","substring","length","charAt","index","removeAt","update","start","stop","unsubscribe","get","f","count","request","source","retrieve","resolve","fileURLToPath","resolvePathLike","path","URL","toString","sleep","ZWatchDelay","sleepWatchDelay","mkdir","ZStreamFolder","write","path","recursive","readFile","stat","writeFile","dirname","resolvePathLike","ZStreamFolder","ZStreamFile","FileSizeDefault","MaxFilesDefault","_cache","Map","options","read","path","_path","stats","cached","get","buffer","mtimeMs","_addToCache","write","Buffer","from","directory","flush","delete","length","item","cache","fileSize","maxFiles","size","set","itr","keys","next","value"],"sources":["../src/file-system/file-system-node.mts","../src/file-system/file-system-service.mts","../src/file-watch/file-watch.mts","../src/file-repository/file-repository.mts","../src/resolve-path-like/resolve-path-like.ts","../src/sleep-watch-delay/sleep-watch-delay.mts","../src/stream/stream-folder.mts","../src/stream/stream-file.mts"],"sourcesContent":["import type { Stats } from \"node:fs\";\nimport { basename, dirname, extname } from \"node:path\";\n\nimport { type ZMutable } from \"@zthun/helpful-fn\";\nimport { isUndefined, omitBy } from \"lodash-es\";\n\n/**\n * Represents a type of a file system node.\n */\nexport enum ZFileSystemNodeType {\n File = \"file\",\n Folder = \"folder\",\n}\n\nexport interface IZFileSystemNode {\n /**\n * The absolute path of the node.\n */\n path: string;\n\n /**\n * The type of the node (file or folder).\n */\n type: ZFileSystemNodeType;\n\n /**\n * The creation date of the node.\n */\n created?: string;\n\n /**\n * The modification date of the node.\n */\n updated?: string;\n\n /**\n * The size of the node in bytes.\n */\n size?: bigint;\n\n /**\n * The file or folder name with the extension.\n *\n * Calculated from the path.\n */\n readonly name: string;\n\n /**\n * The file extension.\n *\n * Calculated from the path.\n */\n readonly extension: string;\n\n /**\n * File title.\n *\n * The name without the extension.\n * Calculated from the path.\n */\n readonly title: string;\n\n /**\n * Parent directory path.\n */\n readonly parent: string;\n}\n\n/**\n * Represents a builder for a file system node.\n */\nexport class ZFileSystemNodeBuilder {\n private _node: ZMutable<IZFileSystemNode> = {\n path: \"/\",\n type: ZFileSystemNodeType.Folder,\n extension: \"\",\n name: \"\",\n parent: \"\",\n title: \"\",\n };\n\n public created(at?: Date | string) {\n this._node.created = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public updated(at?: Date | string) {\n this._node.updated = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public size(bytes: bigint | number | undefined) {\n this._node.size = typeof bytes == \"number\" ? BigInt(bytes) : bytes;\n\n return this;\n }\n\n public path(path: string) {\n this._node.path = path;\n\n return this.decorate();\n }\n\n public type(type: ZFileSystemNodeType) {\n this._node.type = type;\n\n return this.decorate();\n }\n\n public file = this.type.bind(this, ZFileSystemNodeType.File);\n public folder = this.type.bind(this, ZFileSystemNodeType.Folder);\n\n public stats(s: Stats) {\n const builder = this.size(s.size).created(s.birthtime).updated(s.mtime);\n\n return s.isFile() ? builder.file() : builder.folder();\n }\n\n public build() {\n const clone = structuredClone(this._node);\n\n return omitBy(clone, isUndefined) as IZFileSystemNode;\n }\n\n private decorate() {\n const { path, type } = this._node;\n\n this._node.name = basename(path);\n this._node.extension = \"\";\n this._node.title = this._node.name;\n this._node.parent = dirname(path);\n\n if (type === ZFileSystemNodeType.File) {\n const extension = extname(path);\n this._node.extension = extension;\n this._node.title = basename(path, extension);\n }\n\n if (!path || path === \"/\" || this._node.parent === \".\") {\n this._node.parent = \"\";\n }\n\n return this;\n }\n}\n","import { access } from \"node:fs/promises\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { cwd } from \"node:process\";\n\nimport { glob } from \"glob\";\n\nimport type { IZFileSystemNode } from \"./file-system-node.mjs\";\nimport { ZFileSystemNodeBuilder } from \"./file-system-node.mjs\";\n\n/**\n * Represents options for searches.\n */\nexport interface IZFileSystemSearchOptions {\n /**\n * The directory to search in.\n *\n * If this is not set, then the cwd of the application is used.\n */\n cwd?: string;\n\n /**\n * A flag that determines whether or not to load the\n * file system information.\n *\n * This is true by default.\n */\n stat?: boolean;\n}\n\n/**\n * Represents options for directory walking.\n */\nexport interface IZFileSystemWalkOptions {\n /**\n * The starting directory.\n *\n * The default is the current working directory\n *\n * @see process.cwd for more information.\n */\n start?: string;\n\n /**\n * The directory to stop at.\n *\n * The default is the root of the file system.\n */\n stop?: string;\n\n /**\n * The type of mode that the path must support in order\n * to be approved.\n *\n * The default is undefined and left up to the node api.\n */\n mode?: number;\n}\n\n/**\n * Represents a service to enumerate the file system.\n */\nexport interface IZFileSystemService {\n /**\n * Gets information about a node.\n *\n * @param path -\n * The path to get information for.\n *\n * @returns\n * Information about the node.\n */\n info(path: string): Promise<IZFileSystemNode>;\n\n /**\n * Reads all nodes that match a pattern.\n *\n * @param pattern -\n * The pattern string to match against or a list\n * of patterns to match.\n * @param options -\n * The options for the search.\n *\n * @returns\n * A list of path strings that match the given patterns.\n */\n search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]>;\n\n /**\n * Walks up a directory tree to search for existence of a given path.\n *\n * @param search -\n * The path to search for. This is the candidate folder path that\n * may or may not exist somewhere from the start directory all the\n * way up the directory tree.\n * @param options -\n * The given options for the search.\n *\n * @returns\n * The fully qualified path to the first path that matches the search\n * starting at the options start or the current working directory if not\n * specified. Returns null if no such directory exists.\n *\n * @example\n *\n * ```ts\n * import { resolve } from 'path'\n *\n * // Find any folder named .vscode from the current working directory all the way\n * // up the directory tree. Returns null if no vscode directory can be found.\n * const service = new ZFileSystemService();\n * const vscode = service.walk('.vscode');\n *\n * // Walk the directory tree from the current script and find the .config folder.\n * const config = service.walk('.config', { start: __dirname });\n *\n * // Walk the directory tree from the current script and stop when we reach\n * // at most 2 directories up.\n * const start = __dirname;\n * const stop = resolve(__dirname, '../..');\n * const file = service.walk('path/to/file.json', { start, stop });\n * ```\n */\n walk(\n search: string,\n options?: IZFileSystemWalkOptions,\n ): Promise<string | null>;\n}\n\n/**\n * Represents a node implementation of a file system service.\n */\nexport class ZFileSystemService implements IZFileSystemService {\n public async info(path: string): Promise<IZFileSystemNode> {\n const [file] = await this.search(path);\n return file;\n }\n\n public async search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]> {\n const paths = await glob(pattern, {\n stat: true,\n ...options,\n withFileTypes: true,\n });\n\n return paths.map((path) => {\n let info = new ZFileSystemNodeBuilder()\n .path(path.fullpath())\n .created(path.birthtime)\n .updated(path.atime)\n .size(path.size);\n\n // Note that for folders, node will return the size of the underlying OS metadata,\n // hence, why we remove the size on the folder here.\n info = path.isFile() ? info.file() : info.folder().size(undefined);\n\n return info.build();\n });\n }\n\n public async walk(search: string, options?: IZFileSystemWalkOptions) {\n const start = options?.start || cwd();\n const stop = options?.stop || \"/\";\n const mode = options?.mode;\n\n const _test = async (path: string) => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n };\n\n if (isAbsolute(search)) {\n return (await _test(search)) ? search : null;\n }\n\n let dir = start;\n do {\n const path = resolve(dir, search);\n const exists = await _test(path);\n\n if (exists) {\n return path;\n }\n\n dir = dir === stop ? \"\" : dirname(dir);\n } while (dir.length);\n\n return null;\n }\n}\n","import { type Stats } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport type { FSWatcher } from \"chokidar\";\nimport { watch } from \"chokidar\";\nimport type { Observable } from \"rxjs\";\nimport { Subject } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeBuilder,\n} from \"../file-system/file-system-node.mjs\";\n\n/**\n * Represents and object that can watch a folder or file on the file system.\n */\nexport interface IZFileWatch {\n /**\n * Starts the watch operation.\n */\n start(): Promise<void>;\n\n /**\n * Stops the watch operation.\n */\n stop(): Promise<void>;\n\n /**\n * The stream for files being added.\n *\n * This can only occur if the target being watched\n * is a folder.\n *\n * @returns\n * The observable that will publish files that\n * get added.\n */\n add(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files being updated.\n *\n * If this watcher points to a folder, then all files\n * recursively will send when they get updated. If this\n * watcher points to a file, then this will only invoke\n * when the file is updated.\n *\n * @returns\n * The observable that will publish files and folders\n * that are updated.\n */\n update(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files and folders being deleted.\n *\n * If this watcher points to a folder, then all files under the\n * folder will be sent through this observable, including the\n * folder being watched. If this points to a file, then\n * this will only receive when the file is unlinked.\n *\n * @returns\n * The observable that will publish file and folders\n * that are unlinked and removed respectively. Note\n * that files and folders streamed this way will not\n * have their stats set.\n */\n remove(): Observable<IZFileSystemNode>;\n}\n\n/**\n * An implementation of the IZFileWatch.\n */\nexport class ZFileWatch implements IZFileWatch {\n private _add: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _update: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _remove: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _watcher: FSWatcher | undefined;\n\n /**\n * Initializes a new instance of this object.\n *\n * @param path -\n * The path to watch.\n */\n public constructor(public readonly path: string) {}\n\n public async start() {\n await this.stop();\n\n this._watcher = watch(this.path, {\n usePolling: true,\n alwaysStat: true,\n ignoreInitial: true,\n\n awaitWriteFinish: {\n stabilityThreshold: 500,\n pollInterval: 50,\n },\n });\n\n function next(\n observable: Subject<IZFileSystemNode>,\n file: string,\n stats: Stats | undefined,\n ) {\n const node = new ZFileSystemNodeBuilder().path(resolve(this.path, file));\n observable.next(stats ? node.stats(stats).build() : node.build());\n }\n\n this._watcher\n .on(\"add\", next.bind(this, this._add))\n .on(\"addDir\", next.bind(this, this._add))\n .on(\"change\", next.bind(this, this._update))\n .on(\"unlink\", next.bind(this, this._remove))\n .on(\"unlinkDir\", next.bind(this, this._remove));\n\n return new Promise<void>((resolve) =>\n this._watcher?.on(\"ready\", () => resolve()),\n );\n }\n\n public async stop() {\n await this._watcher?.close();\n delete this._watcher;\n }\n\n public add() {\n return this._add.asObservable();\n }\n\n public update() {\n return this._update.asObservable();\n }\n\n public remove() {\n return this._remove.asObservable();\n }\n}\n","import { resolve, sep } from \"node:path\";\n\nimport { firstDefined, sleep } from \"@zthun/helpful-fn\";\nimport type { IZDataRequest, IZDataSource } from \"@zthun/helpful-query\";\nimport { ZDataSourceStatic } from \"@zthun/helpful-query\";\nimport { find, findIndex, flatten, trimEnd, uniqBy } from \"lodash-es\";\nimport { minimatch } from \"minimatch\";\nimport type { Subscription } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeType,\n} from \"../file-system/file-system-node.mjs\";\nimport {\n type IZFileSystemService,\n ZFileSystemService,\n} from \"../file-system/file-system-service.mjs\";\nimport { type IZFileWatch, ZFileWatch } from \"../file-watch/file-watch.mjs\";\n\n/**\n * Represents a repository for the file system.\n */\nexport interface IZFileRepository extends IZDataSource<IZFileSystemNode> {\n /**\n * Retrieves a single file from the repository.\n *\n * @param path -\n * The fully qualified path to the file.\n *\n * @returns\n * The node that represents the file. Returns null if no\n * such file exists.\n */\n get(path: string): Promise<IZFileSystemNode | null>;\n}\n\n/**\n * Represents an implementation of a ZFileRepository that watches\n * a given path scope.\n *\n * This repository is only concerned about files. Folders\n * will not be retrieved from this repository.\n */\nexport class ZFileRepository implements IZFileRepository {\n private _service: IZFileSystemService = new ZFileSystemService();\n private _watcher: IZFileWatch | undefined;\n private _nodes: Promise<ZDataSourceStatic<IZFileSystemNode>> =\n Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n private _globs: string[] = [\"**\"];\n private _path: string = \"\";\n private _add: Subscription | undefined;\n private _remove: Subscription | undefined;\n private _update: Subscription | undefined;\n\n /**\n * Gets the path that this repository is watching.\n */\n public get path() {\n return this._path;\n }\n\n /**\n * Gets the globs matchers that this repository is matching against.\n */\n public get globs() {\n return this._globs.slice();\n }\n\n /**\n * Initializes the repository with the given root and glob filter.\n *\n * This will initially scan the file system and setup watches.\n * If you call this method again, then the repository will be\n * {@link reset} and a new set of files will be added to the\n * repository.\n *\n * @param path -\n * The root path of the repository.\n * @param globs -\n * The optional relative globs of the repository. If this is falsy,\n * then ** is used. You can achieve the same kind of operation\n * using filters, but filtering out unwanted files frees up the internal\n * memory being used.\n */\n public async initialize(path: string, globs: string[] = [\"**\"]) {\n await this.reset();\n\n this._path = path;\n this._globs = globs;\n\n // Note that this all happens in the background and should\n // only be awaited later. So the search should not be\n // required to finish when existing this method. The only\n // requirement is that the repository is reset and the path +\n // glob scope is updated. Everything beyond here should not\n // be awaited - it will be awaited later once the caller\n // tries to retrieve the files using retrieve, get, or\n // count.\n const matches = globs.map((g) =>\n this._service.search(g, {\n cwd: path,\n stat: true,\n }),\n );\n\n this._nodes = Promise.all(matches)\n .then((nodes) => {\n const flat = flatten(nodes);\n const uniq = uniqBy(flat, (n) => n.path);\n return uniq.filter((n) => n.type === ZFileSystemNodeType.File);\n })\n .then((files) => {\n return new ZDataSourceStatic(files);\n });\n\n this._watcher = new ZFileWatch(path);\n\n this._add = this._watcher.add().subscribe((node: IZFileSystemNode) => {\n void (async () => {\n if (\n node.type === ZFileSystemNodeType.File &&\n this._globs.some((g) => minimatch(node.path, resolve(this._path, g)))\n ) {\n const nodes = await this._nodes;\n this._nodes = nodes.insert(node);\n }\n })();\n });\n\n this._remove = this._watcher\n .remove()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n let nodes = await this._nodes;\n const path = trimEnd(node.path, sep);\n\n // It's possible that the node given was a folder. If that happens,\n // we need to remove all files that start with the given path.\n // If the node does point to a file, then there is no possibility that\n // more than 1 item would be removed.\n\n const next = async () =>\n findIndex(await nodes.items(), (n) => {\n return (\n n.path === path ||\n (n.path.startsWith(path) &&\n n.path.substring(path.length).charAt(0) === sep)\n );\n });\n\n for (let index = await next(); index >= 0; index = await next()) {\n nodes = await nodes.removeAt(index);\n }\n\n this._nodes = Promise.resolve(nodes);\n })();\n });\n\n this._update = this._watcher\n .update()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n const nodes = await this._nodes;\n const index = findIndex(\n await nodes.items(),\n (n) => n.path === node.path,\n );\n\n // It's possible node was filtered out by the globs, or\n // it is a directory. If so, then we won't have it in our\n // list.\n if (index >= 0) {\n const next = await nodes.removeAt(index);\n this._nodes = next.insert(node, index);\n }\n })();\n });\n\n // Kick off the initial seed operation with an even loop\n // invocation.\n await sleep(100);\n\n await this._watcher?.start();\n }\n\n /**\n * Resets the repository as if it was initially created.\n */\n public async reset(): Promise<void> {\n await this._watcher?.stop();\n\n this._add?.unsubscribe();\n this._remove?.unsubscribe();\n this._update?.unsubscribe();\n\n delete this._add;\n delete this._remove;\n delete this._update;\n delete this._watcher;\n\n this._path = \"\";\n this._globs = [\"**\"];\n this._nodes = Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n }\n\n public async get(path: string): Promise<IZFileSystemNode | null> {\n const nodes = await this._nodes;\n const items = await nodes.items();\n const node = find(items, (f) => f.path === path);\n\n return firstDefined(null, node);\n }\n\n public async count(request: IZDataRequest): Promise<number> {\n const source = await this._nodes;\n return source.count(request);\n }\n\n public async retrieve(request: IZDataRequest): Promise<IZFileSystemNode[]> {\n const source = await this._nodes;\n return source.retrieve(request);\n }\n}\n","import type { PathLike } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function resolvePathLike(path: PathLike): string {\n if (typeof path === \"string\") {\n return resolve(path);\n }\n\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n\n return resolve(path.toString());\n}\n","import { sleep } from \"@zthun/helpful-fn\";\n\n/**\n * The actual delay time that you should wait for a watch\n * operation to pick up your file changes.\n */\nexport const ZWatchDelay = 1500;\n\n/**\n * Performs a sleep long enough to allow a watch operation\n * to pick up a change.\n *\n * You should never really need this. Where it is useful\n * is for unit testing with IO operations and you want to\n * wait for your write operations to get picked up by\n * a file watch operation.\n */\nexport function sleepWatchDelay() {\n return sleep(ZWatchDelay);\n}\n","import type { PathLike } from \"fs\";\nimport { mkdir } from \"fs/promises\";\n\nimport type { IZStreamWrite } from \"./stream-write.mjs\";\n\n/**\n * A stream that writes folders.\n *\n * Writing folders is idempotent. If the folder you\n * are trying to write already exists, then the write\n * operation still succeeds\n */\nexport class ZStreamFolder implements IZStreamWrite {\n public async write(path: PathLike): Promise<number> {\n await mkdir(path, { recursive: true });\n\n return 0;\n }\n}\n","import type { PathLike, Stats } from \"node:fs\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\n\nimport { dirname } from \"path\";\n\nimport { resolvePathLike } from \"../resolve-path-like/resolve-path-like.js\";\nimport { ZStreamFolder } from \"./stream-folder.mjs\";\nimport type { IZStreamRead, IZStreamReadOptions } from \"./stream-read.mjs\";\nimport type { IZStreamWrite, IZStreamWriteOptions } from \"./stream-write.mjs\";\n\n/**\n * Options for the stream file object.\n */\nexport interface IZStreamFileOptions {\n /**\n * Cache options.\n *\n * A warning that file content caching will take up significant memory\n * if the file size is too big or the max files is too big. Make sure\n * you know what you're doing when you change the default values of this.\n */\n cache?: {\n /**\n * Maximum number of bytes a file can be before it will not be cached.\n * The default is 100 Kib (102400 bytes)\n *\n * @default 102400\n */\n fileSize?: bigint;\n /**\n * The maximum number of files that are to be cached. The cache order\n * is first in, first out. Set this to 0 to not cache anything. The\n * default is 1000.\n *\n * @default 1000\n */\n maxFiles?: number;\n };\n}\n\n/**\n * A stream that can read and write to files.\n *\n * This is mostly a wrapper to readFile and writeFile from node, but\n * with some optimizations.\n *\n * First, this class supports file content caching so reading in a file\n * that's under a certain size threshold will store it in memory for\n * later retrieval.\n */\nexport class ZStreamFile implements IZStreamWrite, IZStreamRead {\n private static readonly FileSizeDefault = 102400; // One Hundred KibiBytes\n private static readonly MaxFilesDefault = 1000;\n\n private _cache = new Map<string, { stats: Stats; buffer: Promise<Buffer> }>();\n\n /**\n * Initializes a new instance of this object.\n *\n * @param options -\n * The options for file read and writes.\n */\n public constructor(public readonly options: IZStreamFileOptions = {}) {}\n\n public async read(\n path: PathLike,\n options?: IZStreamReadOptions,\n ): Promise<Buffer> {\n const _path = resolvePathLike(path);\n\n const stats = await stat(_path);\n const cached = this._cache.get(_path);\n\n const buffer =\n cached && cached.stats.mtimeMs >= stats.mtimeMs\n ? cached.buffer\n : readFile(_path, options);\n\n return this._addToCache(_path, { stats, buffer });\n }\n\n public async write(\n path: PathLike,\n { buffer = Buffer.from(\"\") }: IZStreamWriteOptions = {},\n ): Promise<number> {\n const _path = resolvePathLike(path);\n const directory = dirname(_path);\n\n await new ZStreamFolder().write(directory);\n await writeFile(_path, buffer, { flush: true });\n\n // If this file specifically was cached earlier,\n // we can just remove it now so we make room for\n // another file. Consumers can just read the\n // file again to recache it.\n this._cache.delete(_path);\n\n return buffer.length;\n }\n\n private _addToCache(\n path: string,\n item: { stats: Stats; buffer: Promise<Buffer> },\n ) {\n const { cache = {} } = this.options;\n const {\n fileSize = ZStreamFile.FileSizeDefault,\n maxFiles = ZStreamFile.MaxFilesDefault,\n } = cache;\n\n if (item.stats.size > fileSize) {\n // In this case, the file size is too big to cache in memory,\n // so we're bowing out here.\n return item.buffer;\n }\n\n // We will remove this path from the cache first since\n // we want it to be the most recent file (at the end)\n // of the key list. The removal does nothing if the\n // file was not cached.\n this._cache.delete(path);\n this._cache.set(path, item);\n\n if (this._cache.size > maxFiles) {\n // Retrieving the keys from a javascript map is order\n // by the time in which the keys are created. So\n // we are going to remove the first key which is the\n // oldest.\n const itr = this._cache.keys();\n this._cache.delete(itr.next().value);\n }\n\n return item.buffer;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["basename","dirname","extname","isUndefined","omitBy","ZFileSystemNodeType","ZFileSystemNodeBuilder","_node","path","type","extension","name","parent","title","created","at","Date","toJSON","updated","size","bytes","BigInt","decorate","file","bind","folder","stats","s","builder","birthtime","mtime","isFile","build","clone","structuredClone","access","dirname","isAbsolute","resolve","cwd","glob","ZFileSystemNodeBuilder","ZFileSystemService","info","path","file","search","pattern","options","paths","stat","withFileTypes","map","fullpath","created","birthtime","updated","atime","size","isFile","folder","undefined","build","walk","start","stop","mode","_test","dir","exists","length","resolve","watch","Subject","ZFileSystemNodeBuilder","ZFileWatch","_add","_update","_remove","_watcher","path","start","stop","usePolling","alwaysStat","ignoreInitial","awaitWriteFinish","stabilityThreshold","pollInterval","next","observable","file","stats","node","build","on","bind","Promise","close","add","asObservable","update","remove","resolve","sep","firstDefined","sleep","ZDataSourceStatic","find","findIndex","flatten","trimEnd","uniqBy","minimatch","ZFileSystemNodeType","ZFileSystemService","ZFileWatch","ZFileRepository","_service","_watcher","_nodes","Promise","_globs","_path","_add","_remove","_update","path","globs","slice","initialize","reset","matches","map","g","search","cwd","stat","all","then","nodes","flat","uniq","n","filter","type","File","files","add","subscribe","node","some","insert","remove","next","items","startsWith","substring","length","charAt","index","removeAt","update","start","stop","unsubscribe","get","f","count","request","source","retrieve","sleep","ZWatchDelay","sleepWatchDelay","readdir","dirname","firstTruthy","sleep","ZLogEntryBuilder","ZLoggerContext","glob","noop","ZWatchDelay","ZCrumbtrailJobNudge","_controller","_resolve","_promise","_logger","logger","kill","abort","run","options","controller","AbortController","promise","resolve","Promise","withResolvers","directory","process","cwd","recursive","every","ms","log","info","message","build","warning","catch","onlyDirectories","signal","aborted","resolve","cwd","firstDefined","ZLogEntryBuilder","ZLoggerContext","uniq","minimatch","ZFileWatch","ZCrumbtrailJobWatch","_logger","_globs","_watch","_ready","Promise","_promise","_resolve","msg","info","message","build","add","path","remove","warning","update","watching","globs","slice","ready","logger","kill","stop","_handleFsEvent","entry","directory","some","g","log","_handleAdd","node","_handleRemove","_handleUpdate","run","args","promise","withResolvers","length","filter","join","subscribe","bind","start","resolve","fileURLToPath","resolvePathLike","path","URL","toString","mkdir","ZStreamFolder","write","path","recursive","readFile","stat","writeFile","dirname","resolvePathLike","ZStreamFolder","ZStreamFile","FileSizeDefault","MaxFilesDefault","_cache","Map","options","read","path","_path","stats","cached","get","buffer","mtimeMs","_addToCache","write","Buffer","from","directory","flush","delete","length","item","cache","fileSize","maxFiles","size","set","itr","keys","next","value"],"sources":["../src/file-system/file-system-node.mts","../src/file-system/file-system-service.mts","../src/file-watch/file-watch.mts","../src/file-repository/file-repository.mts","../src/sleep-watch-delay/sleep-watch-delay.mts","../src/job-nudge/job-nudge.mts","../src/job-watch/job-watch.mts","../src/resolve-path-like/resolve-path-like.ts","../src/stream/stream-folder.mts","../src/stream/stream-file.mts"],"sourcesContent":["import type { Stats } from \"node:fs\";\nimport { basename, dirname, extname } from \"node:path\";\n\nimport { type ZMutable } from \"@zthun/helpful-fn\";\nimport { isUndefined, omitBy } from \"lodash-es\";\n\n/**\n * Represents a type of a file system node.\n */\nexport enum ZFileSystemNodeType {\n File = \"file\",\n Folder = \"folder\",\n}\n\nexport interface IZFileSystemNode {\n /**\n * The absolute path of the node.\n */\n path: string;\n\n /**\n * The type of the node (file or folder).\n */\n type: ZFileSystemNodeType;\n\n /**\n * The creation date of the node.\n */\n created?: string;\n\n /**\n * The modification date of the node.\n */\n updated?: string;\n\n /**\n * The size of the node in bytes.\n */\n size?: bigint;\n\n /**\n * The file or folder name with the extension.\n *\n * Calculated from the path.\n */\n readonly name: string;\n\n /**\n * The file extension.\n *\n * Calculated from the path.\n */\n readonly extension: string;\n\n /**\n * File title.\n *\n * The name without the extension.\n * Calculated from the path.\n */\n readonly title: string;\n\n /**\n * Parent directory path.\n */\n readonly parent: string;\n}\n\n/**\n * Represents a builder for a file system node.\n */\nexport class ZFileSystemNodeBuilder {\n private _node: ZMutable<IZFileSystemNode> = {\n path: \"/\",\n type: ZFileSystemNodeType.Folder,\n extension: \"\",\n name: \"\",\n parent: \"\",\n title: \"\",\n };\n\n public created(at?: Date | string) {\n this._node.created = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public updated(at?: Date | string) {\n this._node.updated = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public size(bytes: bigint | number | undefined) {\n this._node.size = typeof bytes == \"number\" ? BigInt(bytes) : bytes;\n\n return this;\n }\n\n public path(path: string) {\n this._node.path = path;\n\n return this.decorate();\n }\n\n public type(type: ZFileSystemNodeType) {\n this._node.type = type;\n\n return this.decorate();\n }\n\n public file = this.type.bind(this, ZFileSystemNodeType.File);\n public folder = this.type.bind(this, ZFileSystemNodeType.Folder);\n\n public stats(s: Stats) {\n const builder = this.size(s.size).created(s.birthtime).updated(s.mtime);\n\n return s.isFile() ? builder.file() : builder.folder();\n }\n\n public build() {\n const clone = structuredClone(this._node);\n\n return omitBy(clone, isUndefined) as IZFileSystemNode;\n }\n\n private decorate() {\n const { path, type } = this._node;\n\n this._node.name = basename(path);\n this._node.extension = \"\";\n this._node.title = this._node.name;\n this._node.parent = dirname(path);\n\n if (type === ZFileSystemNodeType.File) {\n const extension = extname(path);\n this._node.extension = extension;\n this._node.title = basename(path, extension);\n }\n\n if (!path || path === \"/\" || this._node.parent === \".\") {\n this._node.parent = \"\";\n }\n\n return this;\n }\n}\n","import { access } from \"node:fs/promises\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { cwd } from \"node:process\";\n\nimport { glob } from \"glob\";\n\nimport type { IZFileSystemNode } from \"./file-system-node.mjs\";\nimport { ZFileSystemNodeBuilder } from \"./file-system-node.mjs\";\n\n/**\n * Represents options for searches.\n */\nexport interface IZFileSystemSearchOptions {\n /**\n * The directory to search in.\n *\n * If this is not set, then the cwd of the application is used.\n */\n cwd?: string;\n\n /**\n * A flag that determines whether or not to load the\n * file system information.\n *\n * This is true by default.\n */\n stat?: boolean;\n}\n\n/**\n * Represents options for directory walking.\n */\nexport interface IZFileSystemWalkOptions {\n /**\n * The starting directory.\n *\n * The default is the current working directory\n *\n * @see process.cwd for more information.\n */\n start?: string;\n\n /**\n * The directory to stop at.\n *\n * The default is the root of the file system.\n */\n stop?: string;\n\n /**\n * The type of mode that the path must support in order\n * to be approved.\n *\n * The default is undefined and left up to the node api.\n */\n mode?: number;\n}\n\n/**\n * Represents a service to enumerate the file system.\n */\nexport interface IZFileSystemService {\n /**\n * Gets information about a node.\n *\n * @param path -\n * The path to get information for.\n *\n * @returns\n * Information about the node.\n */\n info(path: string): Promise<IZFileSystemNode>;\n\n /**\n * Reads all nodes that match a pattern.\n *\n * @param pattern -\n * The pattern string to match against or a list\n * of patterns to match.\n * @param options -\n * The options for the search.\n *\n * @returns\n * A list of path strings that match the given patterns.\n */\n search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]>;\n\n /**\n * Walks up a directory tree to search for existence of a given path.\n *\n * @param search -\n * The path to search for. This is the candidate folder path that\n * may or may not exist somewhere from the start directory all the\n * way up the directory tree.\n * @param options -\n * The given options for the search.\n *\n * @returns\n * The fully qualified path to the first path that matches the search\n * starting at the options start or the current working directory if not\n * specified. Returns null if no such directory exists.\n *\n * @example\n *\n * ```ts\n * import { resolve } from 'path'\n *\n * // Find any folder named .vscode from the current working directory all the way\n * // up the directory tree. Returns null if no vscode directory can be found.\n * const service = new ZFileSystemService();\n * const vscode = service.walk('.vscode');\n *\n * // Walk the directory tree from the current script and find the .config folder.\n * const config = service.walk('.config', { start: __dirname });\n *\n * // Walk the directory tree from the current script and stop when we reach\n * // at most 2 directories up.\n * const start = __dirname;\n * const stop = resolve(__dirname, '../..');\n * const file = service.walk('path/to/file.json', { start, stop });\n * ```\n */\n walk(\n search: string,\n options?: IZFileSystemWalkOptions,\n ): Promise<string | null>;\n}\n\n/**\n * Represents a node implementation of a file system service.\n */\nexport class ZFileSystemService implements IZFileSystemService {\n public async info(path: string): Promise<IZFileSystemNode> {\n const [file] = await this.search(path);\n return file;\n }\n\n public async search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]> {\n const paths = await glob(pattern, {\n stat: true,\n ...options,\n withFileTypes: true,\n });\n\n return paths.map((path) => {\n let info = new ZFileSystemNodeBuilder()\n .path(path.fullpath())\n .created(path.birthtime)\n .updated(path.atime)\n .size(path.size);\n\n // Note that for folders, node will return the size of the underlying OS metadata,\n // hence, why we remove the size on the folder here.\n info = path.isFile() ? info.file() : info.folder().size(undefined);\n\n return info.build();\n });\n }\n\n public async walk(search: string, options?: IZFileSystemWalkOptions) {\n const start = options?.start || cwd();\n const stop = options?.stop || \"/\";\n const mode = options?.mode;\n\n const _test = async (path: string) => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n };\n\n if (isAbsolute(search)) {\n return (await _test(search)) ? search : null;\n }\n\n let dir = start;\n do {\n const path = resolve(dir, search);\n const exists = await _test(path);\n\n if (exists) {\n return path;\n }\n\n dir = dir === stop ? \"\" : dirname(dir);\n } while (dir.length);\n\n return null;\n }\n}\n","import { type Stats } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport type { FSWatcher } from \"chokidar\";\nimport { watch } from \"chokidar\";\nimport type { Observable } from \"rxjs\";\nimport { Subject } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeBuilder,\n} from \"../file-system/file-system-node.mjs\";\n\n/**\n * Represents and object that can watch a folder or file on the file system.\n */\nexport interface IZFileWatch {\n /**\n * Starts the watch operation.\n */\n start(): Promise<void>;\n\n /**\n * Stops the watch operation.\n */\n stop(): Promise<void>;\n\n /**\n * The stream for files being added.\n *\n * This can only occur if the target being watched\n * is a folder.\n *\n * @returns\n * The observable that will publish files that\n * get added.\n */\n add(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files being updated.\n *\n * If this watcher points to a folder, then all files\n * recursively will send when they get updated. If this\n * watcher points to a file, then this will only invoke\n * when the file is updated.\n *\n * @returns\n * The observable that will publish files and folders\n * that are updated.\n */\n update(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files and folders being deleted.\n *\n * If this watcher points to a folder, then all files under the\n * folder will be sent through this observable, including the\n * folder being watched. If this points to a file, then\n * this will only receive when the file is unlinked.\n *\n * @returns\n * The observable that will publish file and folders\n * that are unlinked and removed respectively. Note\n * that files and folders streamed this way will not\n * have their stats set.\n */\n remove(): Observable<IZFileSystemNode>;\n}\n\n/**\n * An implementation of the IZFileWatch.\n */\nexport class ZFileWatch implements IZFileWatch {\n private _add: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _update: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _remove: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _watcher: FSWatcher | undefined;\n\n /**\n * Initializes a new instance of this object.\n *\n * @param path -\n * The path to watch.\n */\n public constructor(public readonly path: string) {}\n\n public async start() {\n await this.stop();\n\n this._watcher = watch(this.path, {\n usePolling: true,\n alwaysStat: true,\n ignoreInitial: true,\n\n awaitWriteFinish: {\n stabilityThreshold: 500,\n pollInterval: 50,\n },\n });\n\n function next(\n observable: Subject<IZFileSystemNode>,\n file: string,\n stats: Stats | undefined,\n ) {\n const node = new ZFileSystemNodeBuilder().path(resolve(this.path, file));\n observable.next(stats ? node.stats(stats).build() : node.build());\n }\n\n this._watcher\n .on(\"add\", next.bind(this, this._add))\n .on(\"addDir\", next.bind(this, this._add))\n .on(\"change\", next.bind(this, this._update))\n .on(\"unlink\", next.bind(this, this._remove))\n .on(\"unlinkDir\", next.bind(this, this._remove));\n\n return new Promise<void>((resolve) =>\n this._watcher?.on(\"ready\", () => resolve()),\n );\n }\n\n public async stop() {\n await this._watcher?.close();\n delete this._watcher;\n }\n\n public add() {\n return this._add.asObservable();\n }\n\n public update() {\n return this._update.asObservable();\n }\n\n public remove() {\n return this._remove.asObservable();\n }\n}\n","import { resolve, sep } from \"node:path\";\n\nimport { firstDefined, sleep } from \"@zthun/helpful-fn\";\nimport type { IZDataRequest, IZDataSource } from \"@zthun/helpful-query\";\nimport { ZDataSourceStatic } from \"@zthun/helpful-query\";\nimport { find, findIndex, flatten, trimEnd, uniqBy } from \"lodash-es\";\nimport { minimatch } from \"minimatch\";\nimport type { Subscription } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeType,\n} from \"../file-system/file-system-node.mjs\";\nimport {\n type IZFileSystemService,\n ZFileSystemService,\n} from \"../file-system/file-system-service.mjs\";\nimport { type IZFileWatch, ZFileWatch } from \"../file-watch/file-watch.mjs\";\n\n/**\n * Represents a repository for the file system.\n */\nexport interface IZFileRepository extends IZDataSource<IZFileSystemNode> {\n /**\n * Retrieves a single file from the repository.\n *\n * @param path -\n * The fully qualified path to the file.\n *\n * @returns\n * The node that represents the file. Returns null if no\n * such file exists.\n */\n get(path: string): Promise<IZFileSystemNode | null>;\n}\n\n/**\n * Represents an implementation of a ZFileRepository that watches\n * a given path scope.\n *\n * This repository is only concerned about files. Folders\n * will not be retrieved from this repository.\n */\nexport class ZFileRepository implements IZFileRepository {\n private _service: IZFileSystemService = new ZFileSystemService();\n private _watcher: IZFileWatch | undefined;\n private _nodes: Promise<ZDataSourceStatic<IZFileSystemNode>> =\n Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n private _globs: string[] = [\"**\"];\n private _path: string = \"\";\n private _add: Subscription | undefined;\n private _remove: Subscription | undefined;\n private _update: Subscription | undefined;\n\n /**\n * Gets the path that this repository is watching.\n */\n public get path() {\n return this._path;\n }\n\n /**\n * Gets the globs matchers that this repository is matching against.\n */\n public get globs() {\n return this._globs.slice();\n }\n\n /**\n * Initializes the repository with the given root and glob filter.\n *\n * This will initially scan the file system and setup watches.\n * If you call this method again, then the repository will be\n * {@link reset} and a new set of files will be added to the\n * repository.\n *\n * @param path -\n * The root path of the repository.\n * @param globs -\n * The optional relative globs of the repository. If this is falsy,\n * then ** is used. You can achieve the same kind of operation\n * using filters, but filtering out unwanted files frees up the internal\n * memory being used.\n */\n public async initialize(path: string, globs: string[] = [\"**\"]) {\n await this.reset();\n\n this._path = path;\n this._globs = globs;\n\n // Note that this all happens in the background and should\n // only be awaited later. So the search should not be\n // required to finish when existing this method. The only\n // requirement is that the repository is reset and the path +\n // glob scope is updated. Everything beyond here should not\n // be awaited - it will be awaited later once the caller\n // tries to retrieve the files using retrieve, get, or\n // count.\n const matches = globs.map((g) =>\n this._service.search(g, {\n cwd: path,\n stat: true,\n }),\n );\n\n this._nodes = Promise.all(matches)\n .then((nodes) => {\n const flat = flatten(nodes);\n const uniq = uniqBy(flat, (n) => n.path);\n return uniq.filter((n) => n.type === ZFileSystemNodeType.File);\n })\n .then((files) => {\n return new ZDataSourceStatic(files);\n });\n\n this._watcher = new ZFileWatch(path);\n\n this._add = this._watcher.add().subscribe((node: IZFileSystemNode) => {\n void (async () => {\n if (\n node.type === ZFileSystemNodeType.File &&\n this._globs.some((g) => minimatch(node.path, resolve(this._path, g)))\n ) {\n const nodes = await this._nodes;\n this._nodes = nodes.insert(node);\n }\n })();\n });\n\n this._remove = this._watcher\n .remove()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n let nodes = await this._nodes;\n const path = trimEnd(node.path, sep);\n\n // It's possible that the node given was a folder. If that happens,\n // we need to remove all files that start with the given path.\n // If the node does point to a file, then there is no possibility that\n // more than 1 item would be removed.\n\n const next = async () =>\n findIndex(await nodes.items(), (n) => {\n return (\n n.path === path ||\n (n.path.startsWith(path) &&\n n.path.substring(path.length).charAt(0) === sep)\n );\n });\n\n for (let index = await next(); index >= 0; index = await next()) {\n nodes = await nodes.removeAt(index);\n }\n\n this._nodes = Promise.resolve(nodes);\n })();\n });\n\n this._update = this._watcher\n .update()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n const nodes = await this._nodes;\n const index = findIndex(\n await nodes.items(),\n (n) => n.path === node.path,\n );\n\n // It's possible node was filtered out by the globs, or\n // it is a directory. If so, then we won't have it in our\n // list.\n if (index >= 0) {\n const next = await nodes.removeAt(index);\n this._nodes = next.insert(node, index);\n }\n })();\n });\n\n // Kick off the initial seed operation with an even loop\n // invocation.\n await sleep(100);\n\n await this._watcher?.start();\n }\n\n /**\n * Resets the repository as if it was initially created.\n */\n public async reset(): Promise<void> {\n await this._watcher?.stop();\n\n this._add?.unsubscribe();\n this._remove?.unsubscribe();\n this._update?.unsubscribe();\n\n delete this._add;\n delete this._remove;\n delete this._update;\n delete this._watcher;\n\n this._path = \"\";\n this._globs = [\"**\"];\n this._nodes = Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n }\n\n public async get(path: string): Promise<IZFileSystemNode | null> {\n const nodes = await this._nodes;\n const items = await nodes.items();\n const node = find(items, (f) => f.path === path);\n\n return firstDefined(null, node);\n }\n\n public async count(request: IZDataRequest): Promise<number> {\n const source = await this._nodes;\n return source.count(request);\n }\n\n public async retrieve(request: IZDataRequest): Promise<IZFileSystemNode[]> {\n const source = await this._nodes;\n return source.retrieve(request);\n }\n}\n","import { sleep } from \"@zthun/helpful-fn\";\n\n/**\n * The actual delay time that you should wait for a watch\n * operation to pick up your file changes.\n */\nexport const ZWatchDelay = 1500;\n\n/**\n * Performs a sleep long enough to allow a watch operation\n * to pick up a change.\n *\n * You should never really need this. Where it is useful\n * is for unit testing with IO operations and you want to\n * wait for your write operations to get picked up by\n * a file watch operation.\n */\nexport function sleepWatchDelay() {\n return sleep(ZWatchDelay);\n}\n","import { readdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { firstTruthy, sleep } from \"@zthun/helpful-fn\";\nimport type { IZLogger } from \"@zthun/lumberjacky-log\";\nimport { ZLogEntryBuilder, ZLoggerContext } from \"@zthun/lumberjacky-log\";\nimport glob from \"fast-glob\";\nimport { noop } from \"lodash-es\";\n\nimport { ZWatchDelay } from \"../sleep-watch-delay/sleep-watch-delay.mjs\";\n\n/**\n * Options for the nudge command.\n */\nexport interface IZCrumbtrailJobNudgeOptions {\n /**\n * The directory to nudge.\n *\n * The default if not specified is the current working directory.\n */\n directory?: string;\n\n /**\n * Whether to nudge recursively.\n *\n * Warning: This can have severe CPU\n * usage for deep directories.\n *\n * Default is false.\n */\n recursive?: boolean;\n\n /**\n * The total number of milliseconds to wait\n * between nudges.\n *\n * Default is {@link ZWatchDelay}\n */\n every?: number;\n}\n\n/**\n * An operation to continuously nudge a directory.\n *\n * This is a special operation that lists the contents of a targeted parent directory.\n * The main reason for this is to work around an issue when you are running inside of\n * a container and your host is not linux.\n *\n * A lot of times, you will not receive events in this situation for add and update\n * until the virtual file bridge is refreshed by listing the outer directory contents.\n * This command helps to force the bridge to send file change events. You should\n * only need this if you are running on a non linux host inside a docker container.\n *\n * Run a separate container in the background and just nudge the directory\n * for however long you need.\n */\nexport class ZCrumbtrailJobNudge {\n private _controller?: AbortController;\n private _resolve?: (val: number) => void;\n private _promise?: Promise<number>;\n private readonly _logger: IZLogger;\n\n public constructor(logger: IZLogger) {\n this._logger = new ZLoggerContext(\"ZCrumbtrailNudge\", logger);\n }\n\n public async kill(): Promise<void> {\n this._controller?.abort();\n delete this._controller;\n\n await this._promise;\n delete this._promise;\n }\n\n public async run(options: IZCrumbtrailJobNudgeOptions = {}): Promise<number> {\n await this.kill();\n\n const controller = new AbortController();\n this._controller = controller;\n\n const { promise, resolve } = Promise.withResolvers<number>();\n this._promise = promise;\n this._resolve = resolve;\n\n const {\n directory = process.cwd(),\n recursive,\n every = ZWatchDelay,\n } = options;\n\n const ms = firstTruthy(ZWatchDelay, every);\n\n this._logger.log(\n new ZLogEntryBuilder()\n .info()\n .message(`Starting a nudge loop every ${ms} milliseconds`)\n .build(),\n );\n\n if (recursive) {\n this._logger.log(\n new ZLogEntryBuilder()\n .warning()\n .message(\"Nudging is recursive. Child folders will be nudged too.\")\n .build(),\n );\n }\n\n do {\n this._logger.log(\n new ZLogEntryBuilder()\n .info()\n .message(`Nudging ${directory} to refresh`)\n .build(),\n );\n await readdir(dirname(directory)).catch(noop);\n\n if (recursive) {\n await glob(`${directory}/**`, { onlyDirectories: true }).catch(noop);\n }\n\n await sleep(ms);\n } while (!controller.signal.aborted);\n\n resolve(0);\n delete this._resolve;\n\n return this._promise;\n }\n}\n","import { resolve } from \"node:path\";\nimport { cwd } from \"node:process\";\n\nimport { firstDefined } from \"@zthun/helpful-fn\";\nimport type { IZLogEntry, IZLogger } from \"@zthun/lumberjacky-log\";\nimport { ZLogEntryBuilder, ZLoggerContext } from \"@zthun/lumberjacky-log\";\nimport { uniq } from \"lodash-es\";\nimport { minimatch } from \"minimatch\";\n\nimport type { IZFileSystemNode } from \"../file-system/file-system-node.mjs\";\nimport { ZFileWatch } from \"../file-watch/file-watch.mjs\";\n\n/**\n * Arguments for the crumbtrail app.\n */\nexport interface IZCrumbtrailJobWatchOptions {\n /**\n * The directory to watch.\n *\n * If this is falsy, then the cwd is used.\n */\n directory?: string;\n\n /**\n * The list of file globs to watch.\n *\n * If this is falsy or empty, then '**' is used.\n */\n globs?: string[];\n}\n\n/**\n * The root application for the crumbtrail cli.\n */\nexport class ZCrumbtrailJobWatch {\n private _logger: IZLogger;\n private _globs: string[] | undefined;\n private _watch: ZFileWatch | undefined;\n private _ready: Promise<void> = Promise.resolve();\n private _promise: Promise<number> | undefined;\n private _resolve: ((value: number) => void) | undefined;\n\n /**\n * Gets the entry for a basic information message.\n *\n * @returns\n * The log entry for a basic information message.\n */\n public static msg(msg: string): IZLogEntry {\n return new ZLogEntryBuilder().info().message(msg).build();\n }\n\n /**\n * Gets the message for when a file is added.\n *\n * @returns\n * The message for when a file is added.\n */\n public static add(path: string): IZLogEntry {\n return new ZLogEntryBuilder().info().message(`Node added: ${path}`).build();\n }\n\n /**\n * Gets the message for when a file/folder is removed.\n *\n * @returns\n * The message for when a file/folder is added.\n */\n public static remove(path: string): IZLogEntry {\n return new ZLogEntryBuilder()\n .warning()\n .message(`Node removed: ${path}`)\n .build();\n }\n\n /**\n * Gets the message for when a file is updated.\n *\n * @returns\n * The message for when a file is updated.\n */\n public static update(path: string): IZLogEntry {\n return new ZLogEntryBuilder()\n .info()\n .message(`Node updated: ${path}`)\n .build();\n }\n\n /**\n * Gets the current directory being watched.\n *\n * @returns\n * The directory that is watching for events.\n */\n public watching() {\n return Promise.resolve(this._watch?.path);\n }\n\n /**\n * Gets the list of globs that filter the directory contents.\n *\n * @returns\n * The list of globs that filter the directory contents.\n */\n public globs() {\n return Promise.resolve(this._globs?.slice());\n }\n\n /**\n * Returns a promise that can be awaited on to\n * make sure the watch is initialized.\n */\n public async ready() {\n return this._ready;\n }\n\n /**\n * Initializes a new instance of this object.\n *\n * @param logger -\n * The logger to use to output events.\n */\n public constructor(logger: IZLogger) {\n this._logger = new ZLoggerContext(\"ZCrumbtrailApp\", logger);\n }\n\n /**\n * Kills the application.\n */\n public async kill(): Promise<void> {\n await this._watch?.stop();\n\n delete this._watch;\n delete this._globs;\n this._ready = Promise.resolve();\n\n this._resolve?.(0);\n await this._promise;\n delete this._promise;\n }\n\n private _handleFsEvent(path: string, entry: IZLogEntry) {\n const globs = firstDefined([\"**\"], this._globs);\n const directory = firstDefined(cwd(), this._watch?.path);\n\n if (globs?.some((g) => minimatch(path, resolve(directory, g)))) {\n this._logger.log(entry);\n }\n }\n\n private _handleAdd(node: IZFileSystemNode) {\n this._handleFsEvent(node.path, ZCrumbtrailJobWatch.add(node.path));\n }\n\n private _handleRemove(node: IZFileSystemNode) {\n this._handleFsEvent(node.path, ZCrumbtrailJobWatch.remove(node.path));\n }\n\n private _handleUpdate(node: IZFileSystemNode) {\n this._handleFsEvent(node.path, ZCrumbtrailJobWatch.update(node.path));\n }\n\n /**\n * Runs the application.\n *\n * @param args -\n * The application arguments.\n *\n * @returns\n * The process exit code.\n */\n public async run(args: IZCrumbtrailJobWatchOptions = {}): Promise<number> {\n if (this._promise) {\n return this._promise;\n }\n\n const { promise, resolve } = Promise.withResolvers<number>();\n this._resolve = resolve;\n this._promise = promise;\n\n const { directory = cwd(), globs = [\"**\"] } = args;\n\n this._globs = uniq(globs.slice());\n this._globs = this._globs.length ? this._globs : [\"**\"];\n this._watch = new ZFileWatch(directory);\n\n const filter = globs.join(\",\");\n this._logger.log(ZCrumbtrailJobWatch.msg(\"Welcome to Crumbtrail CLI\"));\n this._logger.log(\n ZCrumbtrailJobWatch.msg(`You are now watching ${directory}`),\n );\n this._logger.log(\n ZCrumbtrailJobWatch.msg(`Logging files matching ${filter}.`),\n );\n this._logger.log(ZCrumbtrailJobWatch.msg(\"Press Ctrl+C to stop watching\"));\n\n this._watch.add().subscribe(this._handleAdd.bind(this));\n this._watch.remove().subscribe(this._handleRemove.bind(this));\n this._watch.update().subscribe(this._handleUpdate.bind(this));\n\n this._ready = this._watch.start();\n await this._ready;\n\n return this._promise;\n }\n}\n","import type { PathLike } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function resolvePathLike(path: PathLike): string {\n if (typeof path === \"string\") {\n return resolve(path);\n }\n\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n\n return resolve(path.toString());\n}\n","import type { PathLike } from \"fs\";\nimport { mkdir } from \"fs/promises\";\n\nimport type { IZStreamWrite } from \"./stream-write.mjs\";\n\n/**\n * A stream that writes folders.\n *\n * Writing folders is idempotent. If the folder you\n * are trying to write already exists, then the write\n * operation still succeeds\n */\nexport class ZStreamFolder implements IZStreamWrite {\n public async write(path: PathLike): Promise<number> {\n await mkdir(path, { recursive: true });\n\n return 0;\n }\n}\n","import type { PathLike, Stats } from \"node:fs\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\n\nimport { dirname } from \"path\";\n\nimport { resolvePathLike } from \"../resolve-path-like/resolve-path-like.js\";\nimport { ZStreamFolder } from \"./stream-folder.mjs\";\nimport type { IZStreamRead, IZStreamReadOptions } from \"./stream-read.mjs\";\nimport type { IZStreamWrite, IZStreamWriteOptions } from \"./stream-write.mjs\";\n\n/**\n * Options for the stream file object.\n */\nexport interface IZStreamFileOptions {\n /**\n * Cache options.\n *\n * A warning that file content caching will take up significant memory\n * if the file size is too big or the max files is too big. Make sure\n * you know what you're doing when you change the default values of this.\n */\n cache?: {\n /**\n * Maximum number of bytes a file can be before it will not be cached.\n * The default is 100 Kib (102400 bytes)\n *\n * @default 102400\n */\n fileSize?: bigint;\n /**\n * The maximum number of files that are to be cached. The cache order\n * is first in, first out. Set this to 0 to not cache anything. The\n * default is 1000.\n *\n * @default 1000\n */\n maxFiles?: number;\n };\n}\n\n/**\n * A stream that can read and write to files.\n *\n * This is mostly a wrapper to readFile and writeFile from node, but\n * with some optimizations.\n *\n * First, this class supports file content caching so reading in a file\n * that's under a certain size threshold will store it in memory for\n * later retrieval.\n */\nexport class ZStreamFile implements IZStreamWrite, IZStreamRead {\n private static readonly FileSizeDefault = 102400; // One Hundred KibiBytes\n private static readonly MaxFilesDefault = 1000;\n\n private _cache = new Map<string, { stats: Stats; buffer: Promise<Buffer> }>();\n\n /**\n * Initializes a new instance of this object.\n *\n * @param options -\n * The options for file read and writes.\n */\n public constructor(public readonly options: IZStreamFileOptions = {}) {}\n\n public async read(\n path: PathLike,\n options?: IZStreamReadOptions,\n ): Promise<Buffer> {\n const _path = resolvePathLike(path);\n\n const stats = await stat(_path);\n const cached = this._cache.get(_path);\n\n const buffer =\n cached && cached.stats.mtimeMs >= stats.mtimeMs\n ? cached.buffer\n : readFile(_path, options);\n\n return this._addToCache(_path, { stats, buffer });\n }\n\n public async write(\n path: PathLike,\n { buffer = Buffer.from(\"\") }: IZStreamWriteOptions = {},\n ): Promise<number> {\n const _path = resolvePathLike(path);\n const directory = dirname(_path);\n\n await new ZStreamFolder().write(directory);\n await writeFile(_path, buffer, { flush: true });\n\n // If this file specifically was cached earlier,\n // we can just remove it now so we make room for\n // another file. Consumers can just read the\n // file again to recache it.\n this._cache.delete(_path);\n\n return buffer.length;\n }\n\n private _addToCache(\n path: string,\n item: { stats: Stats; buffer: Promise<Buffer> },\n ) {\n const { cache = {} } = this.options;\n const {\n fileSize = ZStreamFile.FileSizeDefault,\n maxFiles = ZStreamFile.MaxFilesDefault,\n } = cache;\n\n if (item.stats.size > fileSize) {\n // In this case, the file size is too big to cache in memory,\n // so we're bowing out here.\n return item.buffer;\n }\n\n // We will remove this path from the cache first since\n // we want it to be the most recent file (at the end)\n // of the key list. The removal does nothing if the\n // file was not cached.\n this._cache.delete(path);\n this._cache.set(path, item);\n\n if (this._cache.size > maxFiles) {\n // Retrieving the keys from a javascript map is order\n // by the time in which the keys are created. So\n // we are going to remove the first key which is the\n // oldest.\n const itr = this._cache.keys();\n this._cache.delete(itr.next().value);\n }\n\n return item.buffer;\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -2,6 +2,8 @@ export * from './file-repository/file-repository.mjs';
|
|
|
2
2
|
export * from './file-system/file-system-node.mjs';
|
|
3
3
|
export * from './file-system/file-system-service.mjs';
|
|
4
4
|
export * from './file-watch/file-watch.mjs';
|
|
5
|
+
export * from './job-nudge/job-nudge.mjs';
|
|
6
|
+
export * from './job-watch/job-watch.mjs';
|
|
5
7
|
export * from './resolve-path-like/resolve-path-like.js';
|
|
6
8
|
export * from './sleep-watch-delay/sleep-watch-delay.mjs';
|
|
7
9
|
export * from './stream/stream-file.mjs';
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { basename, dirname, extname, isAbsolute, resolve, sep } from "node:path";
|
|
2
|
-
import { firstDefined, sleep } from "@zthun/helpful-fn";
|
|
2
|
+
import { firstDefined, firstTruthy, sleep } from "@zthun/helpful-fn";
|
|
3
3
|
import { ZDataSourceStatic } from "@zthun/helpful-query";
|
|
4
|
-
import { find, findIndex, flatten, isUndefined, omitBy, trimEnd, uniqBy } from "lodash-es";
|
|
4
|
+
import { find, findIndex, flatten, isUndefined, noop, omitBy, trimEnd, uniq, uniqBy } from "lodash-es";
|
|
5
5
|
import { minimatch } from "minimatch";
|
|
6
|
-
import { access, readFile, stat, writeFile } from "node:fs/promises";
|
|
6
|
+
import { access, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
7
7
|
import { cwd } from "node:process";
|
|
8
8
|
import { glob } from "glob";
|
|
9
9
|
import { watch } from "chokidar";
|
|
10
10
|
import { Subject } from "rxjs";
|
|
11
|
+
import { ZLogEntryBuilder, ZLoggerContext } from "@zthun/lumberjacky-log";
|
|
12
|
+
import glob$1 from "fast-glob";
|
|
11
13
|
import { fileURLToPath } from "node:url";
|
|
12
14
|
import { dirname as dirname$1 } from "path";
|
|
13
15
|
import { mkdir } from "fs/promises";
|
|
@@ -284,13 +286,6 @@ import { mkdir } from "fs/promises";
|
|
|
284
286
|
}
|
|
285
287
|
};
|
|
286
288
|
//#endregion
|
|
287
|
-
//#region src/resolve-path-like/resolve-path-like.ts
|
|
288
|
-
function resolvePathLike(path) {
|
|
289
|
-
if (typeof path === "string") return resolve(path);
|
|
290
|
-
if (path instanceof URL) return fileURLToPath(path);
|
|
291
|
-
return resolve(path.toString());
|
|
292
|
-
}
|
|
293
|
-
//#endregion
|
|
294
289
|
//#region src/sleep-watch-delay/sleep-watch-delay.mts
|
|
295
290
|
/**
|
|
296
291
|
* The actual delay time that you should wait for a watch
|
|
@@ -308,6 +303,193 @@ function resolvePathLike(path) {
|
|
|
308
303
|
return sleep(ZWatchDelay);
|
|
309
304
|
}
|
|
310
305
|
//#endregion
|
|
306
|
+
//#region src/job-nudge/job-nudge.mts
|
|
307
|
+
/**
|
|
308
|
+
* An operation to continuously nudge a directory.
|
|
309
|
+
*
|
|
310
|
+
* This is a special operation that lists the contents of a targeted parent directory.
|
|
311
|
+
* The main reason for this is to work around an issue when you are running inside of
|
|
312
|
+
* a container and your host is not linux.
|
|
313
|
+
*
|
|
314
|
+
* A lot of times, you will not receive events in this situation for add and update
|
|
315
|
+
* until the virtual file bridge is refreshed by listing the outer directory contents.
|
|
316
|
+
* This command helps to force the bridge to send file change events. You should
|
|
317
|
+
* only need this if you are running on a non linux host inside a docker container.
|
|
318
|
+
*
|
|
319
|
+
* Run a separate container in the background and just nudge the directory
|
|
320
|
+
* for however long you need.
|
|
321
|
+
*/ var ZCrumbtrailJobNudge = class {
|
|
322
|
+
_controller;
|
|
323
|
+
_resolve;
|
|
324
|
+
_promise;
|
|
325
|
+
_logger;
|
|
326
|
+
constructor(logger) {
|
|
327
|
+
this._logger = new ZLoggerContext("ZCrumbtrailNudge", logger);
|
|
328
|
+
}
|
|
329
|
+
async kill() {
|
|
330
|
+
this._controller?.abort();
|
|
331
|
+
delete this._controller;
|
|
332
|
+
await this._promise;
|
|
333
|
+
delete this._promise;
|
|
334
|
+
}
|
|
335
|
+
async run(options = {}) {
|
|
336
|
+
await this.kill();
|
|
337
|
+
const controller = new AbortController();
|
|
338
|
+
this._controller = controller;
|
|
339
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
340
|
+
this._promise = promise;
|
|
341
|
+
this._resolve = resolve;
|
|
342
|
+
const { directory = process.cwd(), recursive, every = ZWatchDelay } = options;
|
|
343
|
+
const ms = firstTruthy(ZWatchDelay, every);
|
|
344
|
+
this._logger.log(new ZLogEntryBuilder().info().message(`Starting a nudge loop every ${ms} milliseconds`).build());
|
|
345
|
+
if (recursive) this._logger.log(new ZLogEntryBuilder().warning().message("Nudging is recursive. Child folders will be nudged too.").build());
|
|
346
|
+
do {
|
|
347
|
+
this._logger.log(new ZLogEntryBuilder().info().message(`Nudging ${directory} to refresh`).build());
|
|
348
|
+
await readdir(dirname(directory)).catch(noop);
|
|
349
|
+
if (recursive) await glob$1(`${directory}/**`, { onlyDirectories: true }).catch(noop);
|
|
350
|
+
await sleep(ms);
|
|
351
|
+
} while (!controller.signal.aborted);
|
|
352
|
+
resolve(0);
|
|
353
|
+
delete this._resolve;
|
|
354
|
+
return this._promise;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/job-watch/job-watch.mts
|
|
359
|
+
/**
|
|
360
|
+
* The root application for the crumbtrail cli.
|
|
361
|
+
*/ var ZCrumbtrailJobWatch = class ZCrumbtrailJobWatch {
|
|
362
|
+
_logger;
|
|
363
|
+
_globs;
|
|
364
|
+
_watch;
|
|
365
|
+
_ready = Promise.resolve();
|
|
366
|
+
_promise;
|
|
367
|
+
_resolve;
|
|
368
|
+
/**
|
|
369
|
+
* Gets the entry for a basic information message.
|
|
370
|
+
*
|
|
371
|
+
* @returns
|
|
372
|
+
* The log entry for a basic information message.
|
|
373
|
+
*/ static msg(msg) {
|
|
374
|
+
return new ZLogEntryBuilder().info().message(msg).build();
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Gets the message for when a file is added.
|
|
378
|
+
*
|
|
379
|
+
* @returns
|
|
380
|
+
* The message for when a file is added.
|
|
381
|
+
*/ static add(path) {
|
|
382
|
+
return new ZLogEntryBuilder().info().message(`Node added: ${path}`).build();
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Gets the message for when a file/folder is removed.
|
|
386
|
+
*
|
|
387
|
+
* @returns
|
|
388
|
+
* The message for when a file/folder is added.
|
|
389
|
+
*/ static remove(path) {
|
|
390
|
+
return new ZLogEntryBuilder().warning().message(`Node removed: ${path}`).build();
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Gets the message for when a file is updated.
|
|
394
|
+
*
|
|
395
|
+
* @returns
|
|
396
|
+
* The message for when a file is updated.
|
|
397
|
+
*/ static update(path) {
|
|
398
|
+
return new ZLogEntryBuilder().info().message(`Node updated: ${path}`).build();
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Gets the current directory being watched.
|
|
402
|
+
*
|
|
403
|
+
* @returns
|
|
404
|
+
* The directory that is watching for events.
|
|
405
|
+
*/ watching() {
|
|
406
|
+
return Promise.resolve(this._watch?.path);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Gets the list of globs that filter the directory contents.
|
|
410
|
+
*
|
|
411
|
+
* @returns
|
|
412
|
+
* The list of globs that filter the directory contents.
|
|
413
|
+
*/ globs() {
|
|
414
|
+
return Promise.resolve(this._globs?.slice());
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Returns a promise that can be awaited on to
|
|
418
|
+
* make sure the watch is initialized.
|
|
419
|
+
*/ async ready() {
|
|
420
|
+
return this._ready;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Initializes a new instance of this object.
|
|
424
|
+
*
|
|
425
|
+
* @param logger -
|
|
426
|
+
* The logger to use to output events.
|
|
427
|
+
*/ constructor(logger) {
|
|
428
|
+
this._logger = new ZLoggerContext("ZCrumbtrailApp", logger);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Kills the application.
|
|
432
|
+
*/ async kill() {
|
|
433
|
+
await this._watch?.stop();
|
|
434
|
+
delete this._watch;
|
|
435
|
+
delete this._globs;
|
|
436
|
+
this._ready = Promise.resolve();
|
|
437
|
+
this._resolve?.(0);
|
|
438
|
+
await this._promise;
|
|
439
|
+
delete this._promise;
|
|
440
|
+
}
|
|
441
|
+
_handleFsEvent(path, entry) {
|
|
442
|
+
const globs = firstDefined(["**"], this._globs);
|
|
443
|
+
const directory = firstDefined(cwd(), this._watch?.path);
|
|
444
|
+
if (globs?.some((g) => minimatch(path, resolve(directory, g)))) this._logger.log(entry);
|
|
445
|
+
}
|
|
446
|
+
_handleAdd(node) {
|
|
447
|
+
this._handleFsEvent(node.path, ZCrumbtrailJobWatch.add(node.path));
|
|
448
|
+
}
|
|
449
|
+
_handleRemove(node) {
|
|
450
|
+
this._handleFsEvent(node.path, ZCrumbtrailJobWatch.remove(node.path));
|
|
451
|
+
}
|
|
452
|
+
_handleUpdate(node) {
|
|
453
|
+
this._handleFsEvent(node.path, ZCrumbtrailJobWatch.update(node.path));
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Runs the application.
|
|
457
|
+
*
|
|
458
|
+
* @param args -
|
|
459
|
+
* The application arguments.
|
|
460
|
+
*
|
|
461
|
+
* @returns
|
|
462
|
+
* The process exit code.
|
|
463
|
+
*/ async run(args = {}) {
|
|
464
|
+
if (this._promise) return this._promise;
|
|
465
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
466
|
+
this._resolve = resolve;
|
|
467
|
+
this._promise = promise;
|
|
468
|
+
const { directory = cwd(), globs = ["**"] } = args;
|
|
469
|
+
this._globs = uniq(globs.slice());
|
|
470
|
+
this._globs = this._globs.length ? this._globs : ["**"];
|
|
471
|
+
this._watch = new ZFileWatch(directory);
|
|
472
|
+
const filter = globs.join(",");
|
|
473
|
+
this._logger.log(ZCrumbtrailJobWatch.msg("Welcome to Crumbtrail CLI"));
|
|
474
|
+
this._logger.log(ZCrumbtrailJobWatch.msg(`You are now watching ${directory}`));
|
|
475
|
+
this._logger.log(ZCrumbtrailJobWatch.msg(`Logging files matching ${filter}.`));
|
|
476
|
+
this._logger.log(ZCrumbtrailJobWatch.msg("Press Ctrl+C to stop watching"));
|
|
477
|
+
this._watch.add().subscribe(this._handleAdd.bind(this));
|
|
478
|
+
this._watch.remove().subscribe(this._handleRemove.bind(this));
|
|
479
|
+
this._watch.update().subscribe(this._handleUpdate.bind(this));
|
|
480
|
+
this._ready = this._watch.start();
|
|
481
|
+
await this._ready;
|
|
482
|
+
return this._promise;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
//#endregion
|
|
486
|
+
//#region src/resolve-path-like/resolve-path-like.ts
|
|
487
|
+
function resolvePathLike(path) {
|
|
488
|
+
if (typeof path === "string") return resolve(path);
|
|
489
|
+
if (path instanceof URL) return fileURLToPath(path);
|
|
490
|
+
return resolve(path.toString());
|
|
491
|
+
}
|
|
492
|
+
//#endregion
|
|
311
493
|
//#region src/stream/stream-folder.mts
|
|
312
494
|
/**
|
|
313
495
|
* A stream that writes folders.
|
|
@@ -377,6 +559,6 @@ function resolvePathLike(path) {
|
|
|
377
559
|
}
|
|
378
560
|
};
|
|
379
561
|
//#endregion
|
|
380
|
-
export { ZFileRepository, ZFileSystemNodeBuilder, ZFileSystemNodeType, ZFileSystemService, ZFileWatch, ZStreamFile, ZStreamFolder, ZWatchDelay, resolvePathLike, sleepWatchDelay };
|
|
562
|
+
export { ZCrumbtrailJobNudge, ZCrumbtrailJobWatch, ZFileRepository, ZFileSystemNodeBuilder, ZFileSystemNodeType, ZFileSystemService, ZFileWatch, ZStreamFile, ZStreamFolder, ZWatchDelay, resolvePathLike, sleepWatchDelay };
|
|
381
563
|
|
|
382
564
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["basename","dirname","extname","isUndefined","omitBy","ZFileSystemNodeType","ZFileSystemNodeBuilder","_node","path","type","extension","name","parent","title","created","at","Date","toJSON","updated","size","bytes","BigInt","decorate","file","bind","folder","stats","s","builder","birthtime","mtime","isFile","build","clone","structuredClone","access","dirname","isAbsolute","resolve","cwd","glob","ZFileSystemNodeBuilder","ZFileSystemService","info","path","file","search","pattern","options","paths","stat","withFileTypes","map","fullpath","created","birthtime","updated","atime","size","isFile","folder","undefined","build","walk","start","stop","mode","_test","dir","exists","length","resolve","watch","Subject","ZFileSystemNodeBuilder","ZFileWatch","_add","_update","_remove","_watcher","path","start","stop","usePolling","alwaysStat","ignoreInitial","awaitWriteFinish","stabilityThreshold","pollInterval","next","observable","file","stats","node","build","on","bind","Promise","close","add","asObservable","update","remove","resolve","sep","firstDefined","sleep","ZDataSourceStatic","find","findIndex","flatten","trimEnd","uniqBy","minimatch","ZFileSystemNodeType","ZFileSystemService","ZFileWatch","ZFileRepository","_service","_watcher","_nodes","Promise","_globs","_path","_add","_remove","_update","path","globs","slice","initialize","reset","matches","map","g","search","cwd","stat","all","then","nodes","flat","uniq","n","filter","type","File","files","add","subscribe","node","some","insert","remove","next","items","startsWith","substring","length","charAt","index","removeAt","update","start","stop","unsubscribe","get","f","count","request","source","retrieve","resolve","fileURLToPath","resolvePathLike","path","URL","toString","sleep","ZWatchDelay","sleepWatchDelay","mkdir","ZStreamFolder","write","path","recursive","readFile","stat","writeFile","dirname","resolvePathLike","ZStreamFolder","ZStreamFile","FileSizeDefault","MaxFilesDefault","_cache","Map","options","read","path","_path","stats","cached","get","buffer","mtimeMs","_addToCache","write","Buffer","from","directory","flush","delete","length","item","cache","fileSize","maxFiles","size","set","itr","keys","next","value"],"sources":["../src/file-system/file-system-node.mts","../src/file-system/file-system-service.mts","../src/file-watch/file-watch.mts","../src/file-repository/file-repository.mts","../src/resolve-path-like/resolve-path-like.ts","../src/sleep-watch-delay/sleep-watch-delay.mts","../src/stream/stream-folder.mts","../src/stream/stream-file.mts"],"sourcesContent":["import type { Stats } from \"node:fs\";\nimport { basename, dirname, extname } from \"node:path\";\n\nimport { type ZMutable } from \"@zthun/helpful-fn\";\nimport { isUndefined, omitBy } from \"lodash-es\";\n\n/**\n * Represents a type of a file system node.\n */\nexport enum ZFileSystemNodeType {\n File = \"file\",\n Folder = \"folder\",\n}\n\nexport interface IZFileSystemNode {\n /**\n * The absolute path of the node.\n */\n path: string;\n\n /**\n * The type of the node (file or folder).\n */\n type: ZFileSystemNodeType;\n\n /**\n * The creation date of the node.\n */\n created?: string;\n\n /**\n * The modification date of the node.\n */\n updated?: string;\n\n /**\n * The size of the node in bytes.\n */\n size?: bigint;\n\n /**\n * The file or folder name with the extension.\n *\n * Calculated from the path.\n */\n readonly name: string;\n\n /**\n * The file extension.\n *\n * Calculated from the path.\n */\n readonly extension: string;\n\n /**\n * File title.\n *\n * The name without the extension.\n * Calculated from the path.\n */\n readonly title: string;\n\n /**\n * Parent directory path.\n */\n readonly parent: string;\n}\n\n/**\n * Represents a builder for a file system node.\n */\nexport class ZFileSystemNodeBuilder {\n private _node: ZMutable<IZFileSystemNode> = {\n path: \"/\",\n type: ZFileSystemNodeType.Folder,\n extension: \"\",\n name: \"\",\n parent: \"\",\n title: \"\",\n };\n\n public created(at?: Date | string) {\n this._node.created = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public updated(at?: Date | string) {\n this._node.updated = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public size(bytes: bigint | number | undefined) {\n this._node.size = typeof bytes == \"number\" ? BigInt(bytes) : bytes;\n\n return this;\n }\n\n public path(path: string) {\n this._node.path = path;\n\n return this.decorate();\n }\n\n public type(type: ZFileSystemNodeType) {\n this._node.type = type;\n\n return this.decorate();\n }\n\n public file = this.type.bind(this, ZFileSystemNodeType.File);\n public folder = this.type.bind(this, ZFileSystemNodeType.Folder);\n\n public stats(s: Stats) {\n const builder = this.size(s.size).created(s.birthtime).updated(s.mtime);\n\n return s.isFile() ? builder.file() : builder.folder();\n }\n\n public build() {\n const clone = structuredClone(this._node);\n\n return omitBy(clone, isUndefined) as IZFileSystemNode;\n }\n\n private decorate() {\n const { path, type } = this._node;\n\n this._node.name = basename(path);\n this._node.extension = \"\";\n this._node.title = this._node.name;\n this._node.parent = dirname(path);\n\n if (type === ZFileSystemNodeType.File) {\n const extension = extname(path);\n this._node.extension = extension;\n this._node.title = basename(path, extension);\n }\n\n if (!path || path === \"/\" || this._node.parent === \".\") {\n this._node.parent = \"\";\n }\n\n return this;\n }\n}\n","import { access } from \"node:fs/promises\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { cwd } from \"node:process\";\n\nimport { glob } from \"glob\";\n\nimport type { IZFileSystemNode } from \"./file-system-node.mjs\";\nimport { ZFileSystemNodeBuilder } from \"./file-system-node.mjs\";\n\n/**\n * Represents options for searches.\n */\nexport interface IZFileSystemSearchOptions {\n /**\n * The directory to search in.\n *\n * If this is not set, then the cwd of the application is used.\n */\n cwd?: string;\n\n /**\n * A flag that determines whether or not to load the\n * file system information.\n *\n * This is true by default.\n */\n stat?: boolean;\n}\n\n/**\n * Represents options for directory walking.\n */\nexport interface IZFileSystemWalkOptions {\n /**\n * The starting directory.\n *\n * The default is the current working directory\n *\n * @see process.cwd for more information.\n */\n start?: string;\n\n /**\n * The directory to stop at.\n *\n * The default is the root of the file system.\n */\n stop?: string;\n\n /**\n * The type of mode that the path must support in order\n * to be approved.\n *\n * The default is undefined and left up to the node api.\n */\n mode?: number;\n}\n\n/**\n * Represents a service to enumerate the file system.\n */\nexport interface IZFileSystemService {\n /**\n * Gets information about a node.\n *\n * @param path -\n * The path to get information for.\n *\n * @returns\n * Information about the node.\n */\n info(path: string): Promise<IZFileSystemNode>;\n\n /**\n * Reads all nodes that match a pattern.\n *\n * @param pattern -\n * The pattern string to match against or a list\n * of patterns to match.\n * @param options -\n * The options for the search.\n *\n * @returns\n * A list of path strings that match the given patterns.\n */\n search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]>;\n\n /**\n * Walks up a directory tree to search for existence of a given path.\n *\n * @param search -\n * The path to search for. This is the candidate folder path that\n * may or may not exist somewhere from the start directory all the\n * way up the directory tree.\n * @param options -\n * The given options for the search.\n *\n * @returns\n * The fully qualified path to the first path that matches the search\n * starting at the options start or the current working directory if not\n * specified. Returns null if no such directory exists.\n *\n * @example\n *\n * ```ts\n * import { resolve } from 'path'\n *\n * // Find any folder named .vscode from the current working directory all the way\n * // up the directory tree. Returns null if no vscode directory can be found.\n * const service = new ZFileSystemService();\n * const vscode = service.walk('.vscode');\n *\n * // Walk the directory tree from the current script and find the .config folder.\n * const config = service.walk('.config', { start: __dirname });\n *\n * // Walk the directory tree from the current script and stop when we reach\n * // at most 2 directories up.\n * const start = __dirname;\n * const stop = resolve(__dirname, '../..');\n * const file = service.walk('path/to/file.json', { start, stop });\n * ```\n */\n walk(\n search: string,\n options?: IZFileSystemWalkOptions,\n ): Promise<string | null>;\n}\n\n/**\n * Represents a node implementation of a file system service.\n */\nexport class ZFileSystemService implements IZFileSystemService {\n public async info(path: string): Promise<IZFileSystemNode> {\n const [file] = await this.search(path);\n return file;\n }\n\n public async search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]> {\n const paths = await glob(pattern, {\n stat: true,\n ...options,\n withFileTypes: true,\n });\n\n return paths.map((path) => {\n let info = new ZFileSystemNodeBuilder()\n .path(path.fullpath())\n .created(path.birthtime)\n .updated(path.atime)\n .size(path.size);\n\n // Note that for folders, node will return the size of the underlying OS metadata,\n // hence, why we remove the size on the folder here.\n info = path.isFile() ? info.file() : info.folder().size(undefined);\n\n return info.build();\n });\n }\n\n public async walk(search: string, options?: IZFileSystemWalkOptions) {\n const start = options?.start || cwd();\n const stop = options?.stop || \"/\";\n const mode = options?.mode;\n\n const _test = async (path: string) => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n };\n\n if (isAbsolute(search)) {\n return (await _test(search)) ? search : null;\n }\n\n let dir = start;\n do {\n const path = resolve(dir, search);\n const exists = await _test(path);\n\n if (exists) {\n return path;\n }\n\n dir = dir === stop ? \"\" : dirname(dir);\n } while (dir.length);\n\n return null;\n }\n}\n","import { type Stats } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport type { FSWatcher } from \"chokidar\";\nimport { watch } from \"chokidar\";\nimport type { Observable } from \"rxjs\";\nimport { Subject } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeBuilder,\n} from \"../file-system/file-system-node.mjs\";\n\n/**\n * Represents and object that can watch a folder or file on the file system.\n */\nexport interface IZFileWatch {\n /**\n * Starts the watch operation.\n */\n start(): Promise<void>;\n\n /**\n * Stops the watch operation.\n */\n stop(): Promise<void>;\n\n /**\n * The stream for files being added.\n *\n * This can only occur if the target being watched\n * is a folder.\n *\n * @returns\n * The observable that will publish files that\n * get added.\n */\n add(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files being updated.\n *\n * If this watcher points to a folder, then all files\n * recursively will send when they get updated. If this\n * watcher points to a file, then this will only invoke\n * when the file is updated.\n *\n * @returns\n * The observable that will publish files and folders\n * that are updated.\n */\n update(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files and folders being deleted.\n *\n * If this watcher points to a folder, then all files under the\n * folder will be sent through this observable, including the\n * folder being watched. If this points to a file, then\n * this will only receive when the file is unlinked.\n *\n * @returns\n * The observable that will publish file and folders\n * that are unlinked and removed respectively. Note\n * that files and folders streamed this way will not\n * have their stats set.\n */\n remove(): Observable<IZFileSystemNode>;\n}\n\n/**\n * An implementation of the IZFileWatch.\n */\nexport class ZFileWatch implements IZFileWatch {\n private _add: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _update: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _remove: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _watcher: FSWatcher | undefined;\n\n /**\n * Initializes a new instance of this object.\n *\n * @param path -\n * The path to watch.\n */\n public constructor(public readonly path: string) {}\n\n public async start() {\n await this.stop();\n\n this._watcher = watch(this.path, {\n usePolling: true,\n alwaysStat: true,\n ignoreInitial: true,\n\n awaitWriteFinish: {\n stabilityThreshold: 500,\n pollInterval: 50,\n },\n });\n\n function next(\n observable: Subject<IZFileSystemNode>,\n file: string,\n stats: Stats | undefined,\n ) {\n const node = new ZFileSystemNodeBuilder().path(resolve(this.path, file));\n observable.next(stats ? node.stats(stats).build() : node.build());\n }\n\n this._watcher\n .on(\"add\", next.bind(this, this._add))\n .on(\"addDir\", next.bind(this, this._add))\n .on(\"change\", next.bind(this, this._update))\n .on(\"unlink\", next.bind(this, this._remove))\n .on(\"unlinkDir\", next.bind(this, this._remove));\n\n return new Promise<void>((resolve) =>\n this._watcher?.on(\"ready\", () => resolve()),\n );\n }\n\n public async stop() {\n await this._watcher?.close();\n delete this._watcher;\n }\n\n public add() {\n return this._add.asObservable();\n }\n\n public update() {\n return this._update.asObservable();\n }\n\n public remove() {\n return this._remove.asObservable();\n }\n}\n","import { resolve, sep } from \"node:path\";\n\nimport { firstDefined, sleep } from \"@zthun/helpful-fn\";\nimport type { IZDataRequest, IZDataSource } from \"@zthun/helpful-query\";\nimport { ZDataSourceStatic } from \"@zthun/helpful-query\";\nimport { find, findIndex, flatten, trimEnd, uniqBy } from \"lodash-es\";\nimport { minimatch } from \"minimatch\";\nimport type { Subscription } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeType,\n} from \"../file-system/file-system-node.mjs\";\nimport {\n type IZFileSystemService,\n ZFileSystemService,\n} from \"../file-system/file-system-service.mjs\";\nimport { type IZFileWatch, ZFileWatch } from \"../file-watch/file-watch.mjs\";\n\n/**\n * Represents a repository for the file system.\n */\nexport interface IZFileRepository extends IZDataSource<IZFileSystemNode> {\n /**\n * Retrieves a single file from the repository.\n *\n * @param path -\n * The fully qualified path to the file.\n *\n * @returns\n * The node that represents the file. Returns null if no\n * such file exists.\n */\n get(path: string): Promise<IZFileSystemNode | null>;\n}\n\n/**\n * Represents an implementation of a ZFileRepository that watches\n * a given path scope.\n *\n * This repository is only concerned about files. Folders\n * will not be retrieved from this repository.\n */\nexport class ZFileRepository implements IZFileRepository {\n private _service: IZFileSystemService = new ZFileSystemService();\n private _watcher: IZFileWatch | undefined;\n private _nodes: Promise<ZDataSourceStatic<IZFileSystemNode>> =\n Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n private _globs: string[] = [\"**\"];\n private _path: string = \"\";\n private _add: Subscription | undefined;\n private _remove: Subscription | undefined;\n private _update: Subscription | undefined;\n\n /**\n * Gets the path that this repository is watching.\n */\n public get path() {\n return this._path;\n }\n\n /**\n * Gets the globs matchers that this repository is matching against.\n */\n public get globs() {\n return this._globs.slice();\n }\n\n /**\n * Initializes the repository with the given root and glob filter.\n *\n * This will initially scan the file system and setup watches.\n * If you call this method again, then the repository will be\n * {@link reset} and a new set of files will be added to the\n * repository.\n *\n * @param path -\n * The root path of the repository.\n * @param globs -\n * The optional relative globs of the repository. If this is falsy,\n * then ** is used. You can achieve the same kind of operation\n * using filters, but filtering out unwanted files frees up the internal\n * memory being used.\n */\n public async initialize(path: string, globs: string[] = [\"**\"]) {\n await this.reset();\n\n this._path = path;\n this._globs = globs;\n\n // Note that this all happens in the background and should\n // only be awaited later. So the search should not be\n // required to finish when existing this method. The only\n // requirement is that the repository is reset and the path +\n // glob scope is updated. Everything beyond here should not\n // be awaited - it will be awaited later once the caller\n // tries to retrieve the files using retrieve, get, or\n // count.\n const matches = globs.map((g) =>\n this._service.search(g, {\n cwd: path,\n stat: true,\n }),\n );\n\n this._nodes = Promise.all(matches)\n .then((nodes) => {\n const flat = flatten(nodes);\n const uniq = uniqBy(flat, (n) => n.path);\n return uniq.filter((n) => n.type === ZFileSystemNodeType.File);\n })\n .then((files) => {\n return new ZDataSourceStatic(files);\n });\n\n this._watcher = new ZFileWatch(path);\n\n this._add = this._watcher.add().subscribe((node: IZFileSystemNode) => {\n void (async () => {\n if (\n node.type === ZFileSystemNodeType.File &&\n this._globs.some((g) => minimatch(node.path, resolve(this._path, g)))\n ) {\n const nodes = await this._nodes;\n this._nodes = nodes.insert(node);\n }\n })();\n });\n\n this._remove = this._watcher\n .remove()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n let nodes = await this._nodes;\n const path = trimEnd(node.path, sep);\n\n // It's possible that the node given was a folder. If that happens,\n // we need to remove all files that start with the given path.\n // If the node does point to a file, then there is no possibility that\n // more than 1 item would be removed.\n\n const next = async () =>\n findIndex(await nodes.items(), (n) => {\n return (\n n.path === path ||\n (n.path.startsWith(path) &&\n n.path.substring(path.length).charAt(0) === sep)\n );\n });\n\n for (let index = await next(); index >= 0; index = await next()) {\n nodes = await nodes.removeAt(index);\n }\n\n this._nodes = Promise.resolve(nodes);\n })();\n });\n\n this._update = this._watcher\n .update()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n const nodes = await this._nodes;\n const index = findIndex(\n await nodes.items(),\n (n) => n.path === node.path,\n );\n\n // It's possible node was filtered out by the globs, or\n // it is a directory. If so, then we won't have it in our\n // list.\n if (index >= 0) {\n const next = await nodes.removeAt(index);\n this._nodes = next.insert(node, index);\n }\n })();\n });\n\n // Kick off the initial seed operation with an even loop\n // invocation.\n await sleep(100);\n\n await this._watcher?.start();\n }\n\n /**\n * Resets the repository as if it was initially created.\n */\n public async reset(): Promise<void> {\n await this._watcher?.stop();\n\n this._add?.unsubscribe();\n this._remove?.unsubscribe();\n this._update?.unsubscribe();\n\n delete this._add;\n delete this._remove;\n delete this._update;\n delete this._watcher;\n\n this._path = \"\";\n this._globs = [\"**\"];\n this._nodes = Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n }\n\n public async get(path: string): Promise<IZFileSystemNode | null> {\n const nodes = await this._nodes;\n const items = await nodes.items();\n const node = find(items, (f) => f.path === path);\n\n return firstDefined(null, node);\n }\n\n public async count(request: IZDataRequest): Promise<number> {\n const source = await this._nodes;\n return source.count(request);\n }\n\n public async retrieve(request: IZDataRequest): Promise<IZFileSystemNode[]> {\n const source = await this._nodes;\n return source.retrieve(request);\n }\n}\n","import type { PathLike } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function resolvePathLike(path: PathLike): string {\n if (typeof path === \"string\") {\n return resolve(path);\n }\n\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n\n return resolve(path.toString());\n}\n","import { sleep } from \"@zthun/helpful-fn\";\n\n/**\n * The actual delay time that you should wait for a watch\n * operation to pick up your file changes.\n */\nexport const ZWatchDelay = 1500;\n\n/**\n * Performs a sleep long enough to allow a watch operation\n * to pick up a change.\n *\n * You should never really need this. Where it is useful\n * is for unit testing with IO operations and you want to\n * wait for your write operations to get picked up by\n * a file watch operation.\n */\nexport function sleepWatchDelay() {\n return sleep(ZWatchDelay);\n}\n","import type { PathLike } from \"fs\";\nimport { mkdir } from \"fs/promises\";\n\nimport type { IZStreamWrite } from \"./stream-write.mjs\";\n\n/**\n * A stream that writes folders.\n *\n * Writing folders is idempotent. If the folder you\n * are trying to write already exists, then the write\n * operation still succeeds\n */\nexport class ZStreamFolder implements IZStreamWrite {\n public async write(path: PathLike): Promise<number> {\n await mkdir(path, { recursive: true });\n\n return 0;\n }\n}\n","import type { PathLike, Stats } from \"node:fs\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\n\nimport { dirname } from \"path\";\n\nimport { resolvePathLike } from \"../resolve-path-like/resolve-path-like.js\";\nimport { ZStreamFolder } from \"./stream-folder.mjs\";\nimport type { IZStreamRead, IZStreamReadOptions } from \"./stream-read.mjs\";\nimport type { IZStreamWrite, IZStreamWriteOptions } from \"./stream-write.mjs\";\n\n/**\n * Options for the stream file object.\n */\nexport interface IZStreamFileOptions {\n /**\n * Cache options.\n *\n * A warning that file content caching will take up significant memory\n * if the file size is too big or the max files is too big. Make sure\n * you know what you're doing when you change the default values of this.\n */\n cache?: {\n /**\n * Maximum number of bytes a file can be before it will not be cached.\n * The default is 100 Kib (102400 bytes)\n *\n * @default 102400\n */\n fileSize?: bigint;\n /**\n * The maximum number of files that are to be cached. The cache order\n * is first in, first out. Set this to 0 to not cache anything. The\n * default is 1000.\n *\n * @default 1000\n */\n maxFiles?: number;\n };\n}\n\n/**\n * A stream that can read and write to files.\n *\n * This is mostly a wrapper to readFile and writeFile from node, but\n * with some optimizations.\n *\n * First, this class supports file content caching so reading in a file\n * that's under a certain size threshold will store it in memory for\n * later retrieval.\n */\nexport class ZStreamFile implements IZStreamWrite, IZStreamRead {\n private static readonly FileSizeDefault = 102400; // One Hundred KibiBytes\n private static readonly MaxFilesDefault = 1000;\n\n private _cache = new Map<string, { stats: Stats; buffer: Promise<Buffer> }>();\n\n /**\n * Initializes a new instance of this object.\n *\n * @param options -\n * The options for file read and writes.\n */\n public constructor(public readonly options: IZStreamFileOptions = {}) {}\n\n public async read(\n path: PathLike,\n options?: IZStreamReadOptions,\n ): Promise<Buffer> {\n const _path = resolvePathLike(path);\n\n const stats = await stat(_path);\n const cached = this._cache.get(_path);\n\n const buffer =\n cached && cached.stats.mtimeMs >= stats.mtimeMs\n ? cached.buffer\n : readFile(_path, options);\n\n return this._addToCache(_path, { stats, buffer });\n }\n\n public async write(\n path: PathLike,\n { buffer = Buffer.from(\"\") }: IZStreamWriteOptions = {},\n ): Promise<number> {\n const _path = resolvePathLike(path);\n const directory = dirname(_path);\n\n await new ZStreamFolder().write(directory);\n await writeFile(_path, buffer, { flush: true });\n\n // If this file specifically was cached earlier,\n // we can just remove it now so we make room for\n // another file. Consumers can just read the\n // file again to recache it.\n this._cache.delete(_path);\n\n return buffer.length;\n }\n\n private _addToCache(\n path: string,\n item: { stats: Stats; buffer: Promise<Buffer> },\n ) {\n const { cache = {} } = this.options;\n const {\n fileSize = ZStreamFile.FileSizeDefault,\n maxFiles = ZStreamFile.MaxFilesDefault,\n } = cache;\n\n if (item.stats.size > fileSize) {\n // In this case, the file size is too big to cache in memory,\n // so we're bowing out here.\n return item.buffer;\n }\n\n // We will remove this path from the cache first since\n // we want it to be the most recent file (at the end)\n // of the key list. The removal does nothing if the\n // file was not cached.\n this._cache.delete(path);\n this._cache.set(path, item);\n\n if (this._cache.size > maxFiles) {\n // Retrieving the keys from a javascript map is order\n // by the time in which the keys are created. So\n // we are going to remove the first key which is the\n // oldest.\n const itr = this._cache.keys();\n this._cache.delete(itr.next().value);\n }\n\n return item.buffer;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["basename","dirname","extname","isUndefined","omitBy","ZFileSystemNodeType","ZFileSystemNodeBuilder","_node","path","type","extension","name","parent","title","created","at","Date","toJSON","updated","size","bytes","BigInt","decorate","file","bind","folder","stats","s","builder","birthtime","mtime","isFile","build","clone","structuredClone","access","dirname","isAbsolute","resolve","cwd","glob","ZFileSystemNodeBuilder","ZFileSystemService","info","path","file","search","pattern","options","paths","stat","withFileTypes","map","fullpath","created","birthtime","updated","atime","size","isFile","folder","undefined","build","walk","start","stop","mode","_test","dir","exists","length","resolve","watch","Subject","ZFileSystemNodeBuilder","ZFileWatch","_add","_update","_remove","_watcher","path","start","stop","usePolling","alwaysStat","ignoreInitial","awaitWriteFinish","stabilityThreshold","pollInterval","next","observable","file","stats","node","build","on","bind","Promise","close","add","asObservable","update","remove","resolve","sep","firstDefined","sleep","ZDataSourceStatic","find","findIndex","flatten","trimEnd","uniqBy","minimatch","ZFileSystemNodeType","ZFileSystemService","ZFileWatch","ZFileRepository","_service","_watcher","_nodes","Promise","_globs","_path","_add","_remove","_update","path","globs","slice","initialize","reset","matches","map","g","search","cwd","stat","all","then","nodes","flat","uniq","n","filter","type","File","files","add","subscribe","node","some","insert","remove","next","items","startsWith","substring","length","charAt","index","removeAt","update","start","stop","unsubscribe","get","f","count","request","source","retrieve","sleep","ZWatchDelay","sleepWatchDelay","readdir","dirname","firstTruthy","sleep","ZLogEntryBuilder","ZLoggerContext","glob","noop","ZWatchDelay","ZCrumbtrailJobNudge","_controller","_resolve","_promise","_logger","logger","kill","abort","run","options","controller","AbortController","promise","resolve","Promise","withResolvers","directory","process","cwd","recursive","every","ms","log","info","message","build","warning","catch","onlyDirectories","signal","aborted","resolve","cwd","firstDefined","ZLogEntryBuilder","ZLoggerContext","uniq","minimatch","ZFileWatch","ZCrumbtrailJobWatch","_logger","_globs","_watch","_ready","Promise","_promise","_resolve","msg","info","message","build","add","path","remove","warning","update","watching","globs","slice","ready","logger","kill","stop","_handleFsEvent","entry","directory","some","g","log","_handleAdd","node","_handleRemove","_handleUpdate","run","args","promise","withResolvers","length","filter","join","subscribe","bind","start","resolve","fileURLToPath","resolvePathLike","path","URL","toString","mkdir","ZStreamFolder","write","path","recursive","readFile","stat","writeFile","dirname","resolvePathLike","ZStreamFolder","ZStreamFile","FileSizeDefault","MaxFilesDefault","_cache","Map","options","read","path","_path","stats","cached","get","buffer","mtimeMs","_addToCache","write","Buffer","from","directory","flush","delete","length","item","cache","fileSize","maxFiles","size","set","itr","keys","next","value"],"sources":["../src/file-system/file-system-node.mts","../src/file-system/file-system-service.mts","../src/file-watch/file-watch.mts","../src/file-repository/file-repository.mts","../src/sleep-watch-delay/sleep-watch-delay.mts","../src/job-nudge/job-nudge.mts","../src/job-watch/job-watch.mts","../src/resolve-path-like/resolve-path-like.ts","../src/stream/stream-folder.mts","../src/stream/stream-file.mts"],"sourcesContent":["import type { Stats } from \"node:fs\";\nimport { basename, dirname, extname } from \"node:path\";\n\nimport { type ZMutable } from \"@zthun/helpful-fn\";\nimport { isUndefined, omitBy } from \"lodash-es\";\n\n/**\n * Represents a type of a file system node.\n */\nexport enum ZFileSystemNodeType {\n File = \"file\",\n Folder = \"folder\",\n}\n\nexport interface IZFileSystemNode {\n /**\n * The absolute path of the node.\n */\n path: string;\n\n /**\n * The type of the node (file or folder).\n */\n type: ZFileSystemNodeType;\n\n /**\n * The creation date of the node.\n */\n created?: string;\n\n /**\n * The modification date of the node.\n */\n updated?: string;\n\n /**\n * The size of the node in bytes.\n */\n size?: bigint;\n\n /**\n * The file or folder name with the extension.\n *\n * Calculated from the path.\n */\n readonly name: string;\n\n /**\n * The file extension.\n *\n * Calculated from the path.\n */\n readonly extension: string;\n\n /**\n * File title.\n *\n * The name without the extension.\n * Calculated from the path.\n */\n readonly title: string;\n\n /**\n * Parent directory path.\n */\n readonly parent: string;\n}\n\n/**\n * Represents a builder for a file system node.\n */\nexport class ZFileSystemNodeBuilder {\n private _node: ZMutable<IZFileSystemNode> = {\n path: \"/\",\n type: ZFileSystemNodeType.Folder,\n extension: \"\",\n name: \"\",\n parent: \"\",\n title: \"\",\n };\n\n public created(at?: Date | string) {\n this._node.created = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public updated(at?: Date | string) {\n this._node.updated = at instanceof Date ? at.toJSON() : at;\n\n return this;\n }\n\n public size(bytes: bigint | number | undefined) {\n this._node.size = typeof bytes == \"number\" ? BigInt(bytes) : bytes;\n\n return this;\n }\n\n public path(path: string) {\n this._node.path = path;\n\n return this.decorate();\n }\n\n public type(type: ZFileSystemNodeType) {\n this._node.type = type;\n\n return this.decorate();\n }\n\n public file = this.type.bind(this, ZFileSystemNodeType.File);\n public folder = this.type.bind(this, ZFileSystemNodeType.Folder);\n\n public stats(s: Stats) {\n const builder = this.size(s.size).created(s.birthtime).updated(s.mtime);\n\n return s.isFile() ? builder.file() : builder.folder();\n }\n\n public build() {\n const clone = structuredClone(this._node);\n\n return omitBy(clone, isUndefined) as IZFileSystemNode;\n }\n\n private decorate() {\n const { path, type } = this._node;\n\n this._node.name = basename(path);\n this._node.extension = \"\";\n this._node.title = this._node.name;\n this._node.parent = dirname(path);\n\n if (type === ZFileSystemNodeType.File) {\n const extension = extname(path);\n this._node.extension = extension;\n this._node.title = basename(path, extension);\n }\n\n if (!path || path === \"/\" || this._node.parent === \".\") {\n this._node.parent = \"\";\n }\n\n return this;\n }\n}\n","import { access } from \"node:fs/promises\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { cwd } from \"node:process\";\n\nimport { glob } from \"glob\";\n\nimport type { IZFileSystemNode } from \"./file-system-node.mjs\";\nimport { ZFileSystemNodeBuilder } from \"./file-system-node.mjs\";\n\n/**\n * Represents options for searches.\n */\nexport interface IZFileSystemSearchOptions {\n /**\n * The directory to search in.\n *\n * If this is not set, then the cwd of the application is used.\n */\n cwd?: string;\n\n /**\n * A flag that determines whether or not to load the\n * file system information.\n *\n * This is true by default.\n */\n stat?: boolean;\n}\n\n/**\n * Represents options for directory walking.\n */\nexport interface IZFileSystemWalkOptions {\n /**\n * The starting directory.\n *\n * The default is the current working directory\n *\n * @see process.cwd for more information.\n */\n start?: string;\n\n /**\n * The directory to stop at.\n *\n * The default is the root of the file system.\n */\n stop?: string;\n\n /**\n * The type of mode that the path must support in order\n * to be approved.\n *\n * The default is undefined and left up to the node api.\n */\n mode?: number;\n}\n\n/**\n * Represents a service to enumerate the file system.\n */\nexport interface IZFileSystemService {\n /**\n * Gets information about a node.\n *\n * @param path -\n * The path to get information for.\n *\n * @returns\n * Information about the node.\n */\n info(path: string): Promise<IZFileSystemNode>;\n\n /**\n * Reads all nodes that match a pattern.\n *\n * @param pattern -\n * The pattern string to match against or a list\n * of patterns to match.\n * @param options -\n * The options for the search.\n *\n * @returns\n * A list of path strings that match the given patterns.\n */\n search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]>;\n\n /**\n * Walks up a directory tree to search for existence of a given path.\n *\n * @param search -\n * The path to search for. This is the candidate folder path that\n * may or may not exist somewhere from the start directory all the\n * way up the directory tree.\n * @param options -\n * The given options for the search.\n *\n * @returns\n * The fully qualified path to the first path that matches the search\n * starting at the options start or the current working directory if not\n * specified. Returns null if no such directory exists.\n *\n * @example\n *\n * ```ts\n * import { resolve } from 'path'\n *\n * // Find any folder named .vscode from the current working directory all the way\n * // up the directory tree. Returns null if no vscode directory can be found.\n * const service = new ZFileSystemService();\n * const vscode = service.walk('.vscode');\n *\n * // Walk the directory tree from the current script and find the .config folder.\n * const config = service.walk('.config', { start: __dirname });\n *\n * // Walk the directory tree from the current script and stop when we reach\n * // at most 2 directories up.\n * const start = __dirname;\n * const stop = resolve(__dirname, '../..');\n * const file = service.walk('path/to/file.json', { start, stop });\n * ```\n */\n walk(\n search: string,\n options?: IZFileSystemWalkOptions,\n ): Promise<string | null>;\n}\n\n/**\n * Represents a node implementation of a file system service.\n */\nexport class ZFileSystemService implements IZFileSystemService {\n public async info(path: string): Promise<IZFileSystemNode> {\n const [file] = await this.search(path);\n return file;\n }\n\n public async search(\n pattern: string | string[],\n options?: IZFileSystemSearchOptions,\n ): Promise<IZFileSystemNode[]> {\n const paths = await glob(pattern, {\n stat: true,\n ...options,\n withFileTypes: true,\n });\n\n return paths.map((path) => {\n let info = new ZFileSystemNodeBuilder()\n .path(path.fullpath())\n .created(path.birthtime)\n .updated(path.atime)\n .size(path.size);\n\n // Note that for folders, node will return the size of the underlying OS metadata,\n // hence, why we remove the size on the folder here.\n info = path.isFile() ? info.file() : info.folder().size(undefined);\n\n return info.build();\n });\n }\n\n public async walk(search: string, options?: IZFileSystemWalkOptions) {\n const start = options?.start || cwd();\n const stop = options?.stop || \"/\";\n const mode = options?.mode;\n\n const _test = async (path: string) => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n };\n\n if (isAbsolute(search)) {\n return (await _test(search)) ? search : null;\n }\n\n let dir = start;\n do {\n const path = resolve(dir, search);\n const exists = await _test(path);\n\n if (exists) {\n return path;\n }\n\n dir = dir === stop ? \"\" : dirname(dir);\n } while (dir.length);\n\n return null;\n }\n}\n","import { type Stats } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport type { FSWatcher } from \"chokidar\";\nimport { watch } from \"chokidar\";\nimport type { Observable } from \"rxjs\";\nimport { Subject } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeBuilder,\n} from \"../file-system/file-system-node.mjs\";\n\n/**\n * Represents and object that can watch a folder or file on the file system.\n */\nexport interface IZFileWatch {\n /**\n * Starts the watch operation.\n */\n start(): Promise<void>;\n\n /**\n * Stops the watch operation.\n */\n stop(): Promise<void>;\n\n /**\n * The stream for files being added.\n *\n * This can only occur if the target being watched\n * is a folder.\n *\n * @returns\n * The observable that will publish files that\n * get added.\n */\n add(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files being updated.\n *\n * If this watcher points to a folder, then all files\n * recursively will send when they get updated. If this\n * watcher points to a file, then this will only invoke\n * when the file is updated.\n *\n * @returns\n * The observable that will publish files and folders\n * that are updated.\n */\n update(): Observable<IZFileSystemNode>;\n\n /**\n * The stream for files and folders being deleted.\n *\n * If this watcher points to a folder, then all files under the\n * folder will be sent through this observable, including the\n * folder being watched. If this points to a file, then\n * this will only receive when the file is unlinked.\n *\n * @returns\n * The observable that will publish file and folders\n * that are unlinked and removed respectively. Note\n * that files and folders streamed this way will not\n * have their stats set.\n */\n remove(): Observable<IZFileSystemNode>;\n}\n\n/**\n * An implementation of the IZFileWatch.\n */\nexport class ZFileWatch implements IZFileWatch {\n private _add: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _update: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _remove: Subject<IZFileSystemNode> = new Subject<IZFileSystemNode>();\n private _watcher: FSWatcher | undefined;\n\n /**\n * Initializes a new instance of this object.\n *\n * @param path -\n * The path to watch.\n */\n public constructor(public readonly path: string) {}\n\n public async start() {\n await this.stop();\n\n this._watcher = watch(this.path, {\n usePolling: true,\n alwaysStat: true,\n ignoreInitial: true,\n\n awaitWriteFinish: {\n stabilityThreshold: 500,\n pollInterval: 50,\n },\n });\n\n function next(\n observable: Subject<IZFileSystemNode>,\n file: string,\n stats: Stats | undefined,\n ) {\n const node = new ZFileSystemNodeBuilder().path(resolve(this.path, file));\n observable.next(stats ? node.stats(stats).build() : node.build());\n }\n\n this._watcher\n .on(\"add\", next.bind(this, this._add))\n .on(\"addDir\", next.bind(this, this._add))\n .on(\"change\", next.bind(this, this._update))\n .on(\"unlink\", next.bind(this, this._remove))\n .on(\"unlinkDir\", next.bind(this, this._remove));\n\n return new Promise<void>((resolve) =>\n this._watcher?.on(\"ready\", () => resolve()),\n );\n }\n\n public async stop() {\n await this._watcher?.close();\n delete this._watcher;\n }\n\n public add() {\n return this._add.asObservable();\n }\n\n public update() {\n return this._update.asObservable();\n }\n\n public remove() {\n return this._remove.asObservable();\n }\n}\n","import { resolve, sep } from \"node:path\";\n\nimport { firstDefined, sleep } from \"@zthun/helpful-fn\";\nimport type { IZDataRequest, IZDataSource } from \"@zthun/helpful-query\";\nimport { ZDataSourceStatic } from \"@zthun/helpful-query\";\nimport { find, findIndex, flatten, trimEnd, uniqBy } from \"lodash-es\";\nimport { minimatch } from \"minimatch\";\nimport type { Subscription } from \"rxjs\";\n\nimport {\n type IZFileSystemNode,\n ZFileSystemNodeType,\n} from \"../file-system/file-system-node.mjs\";\nimport {\n type IZFileSystemService,\n ZFileSystemService,\n} from \"../file-system/file-system-service.mjs\";\nimport { type IZFileWatch, ZFileWatch } from \"../file-watch/file-watch.mjs\";\n\n/**\n * Represents a repository for the file system.\n */\nexport interface IZFileRepository extends IZDataSource<IZFileSystemNode> {\n /**\n * Retrieves a single file from the repository.\n *\n * @param path -\n * The fully qualified path to the file.\n *\n * @returns\n * The node that represents the file. Returns null if no\n * such file exists.\n */\n get(path: string): Promise<IZFileSystemNode | null>;\n}\n\n/**\n * Represents an implementation of a ZFileRepository that watches\n * a given path scope.\n *\n * This repository is only concerned about files. Folders\n * will not be retrieved from this repository.\n */\nexport class ZFileRepository implements IZFileRepository {\n private _service: IZFileSystemService = new ZFileSystemService();\n private _watcher: IZFileWatch | undefined;\n private _nodes: Promise<ZDataSourceStatic<IZFileSystemNode>> =\n Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n private _globs: string[] = [\"**\"];\n private _path: string = \"\";\n private _add: Subscription | undefined;\n private _remove: Subscription | undefined;\n private _update: Subscription | undefined;\n\n /**\n * Gets the path that this repository is watching.\n */\n public get path() {\n return this._path;\n }\n\n /**\n * Gets the globs matchers that this repository is matching against.\n */\n public get globs() {\n return this._globs.slice();\n }\n\n /**\n * Initializes the repository with the given root and glob filter.\n *\n * This will initially scan the file system and setup watches.\n * If you call this method again, then the repository will be\n * {@link reset} and a new set of files will be added to the\n * repository.\n *\n * @param path -\n * The root path of the repository.\n * @param globs -\n * The optional relative globs of the repository. If this is falsy,\n * then ** is used. You can achieve the same kind of operation\n * using filters, but filtering out unwanted files frees up the internal\n * memory being used.\n */\n public async initialize(path: string, globs: string[] = [\"**\"]) {\n await this.reset();\n\n this._path = path;\n this._globs = globs;\n\n // Note that this all happens in the background and should\n // only be awaited later. So the search should not be\n // required to finish when existing this method. The only\n // requirement is that the repository is reset and the path +\n // glob scope is updated. Everything beyond here should not\n // be awaited - it will be awaited later once the caller\n // tries to retrieve the files using retrieve, get, or\n // count.\n const matches = globs.map((g) =>\n this._service.search(g, {\n cwd: path,\n stat: true,\n }),\n );\n\n this._nodes = Promise.all(matches)\n .then((nodes) => {\n const flat = flatten(nodes);\n const uniq = uniqBy(flat, (n) => n.path);\n return uniq.filter((n) => n.type === ZFileSystemNodeType.File);\n })\n .then((files) => {\n return new ZDataSourceStatic(files);\n });\n\n this._watcher = new ZFileWatch(path);\n\n this._add = this._watcher.add().subscribe((node: IZFileSystemNode) => {\n void (async () => {\n if (\n node.type === ZFileSystemNodeType.File &&\n this._globs.some((g) => minimatch(node.path, resolve(this._path, g)))\n ) {\n const nodes = await this._nodes;\n this._nodes = nodes.insert(node);\n }\n })();\n });\n\n this._remove = this._watcher\n .remove()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n let nodes = await this._nodes;\n const path = trimEnd(node.path, sep);\n\n // It's possible that the node given was a folder. If that happens,\n // we need to remove all files that start with the given path.\n // If the node does point to a file, then there is no possibility that\n // more than 1 item would be removed.\n\n const next = async () =>\n findIndex(await nodes.items(), (n) => {\n return (\n n.path === path ||\n (n.path.startsWith(path) &&\n n.path.substring(path.length).charAt(0) === sep)\n );\n });\n\n for (let index = await next(); index >= 0; index = await next()) {\n nodes = await nodes.removeAt(index);\n }\n\n this._nodes = Promise.resolve(nodes);\n })();\n });\n\n this._update = this._watcher\n .update()\n .subscribe((node: IZFileSystemNode) => {\n void (async () => {\n const nodes = await this._nodes;\n const index = findIndex(\n await nodes.items(),\n (n) => n.path === node.path,\n );\n\n // It's possible node was filtered out by the globs, or\n // it is a directory. If so, then we won't have it in our\n // list.\n if (index >= 0) {\n const next = await nodes.removeAt(index);\n this._nodes = next.insert(node, index);\n }\n })();\n });\n\n // Kick off the initial seed operation with an even loop\n // invocation.\n await sleep(100);\n\n await this._watcher?.start();\n }\n\n /**\n * Resets the repository as if it was initially created.\n */\n public async reset(): Promise<void> {\n await this._watcher?.stop();\n\n this._add?.unsubscribe();\n this._remove?.unsubscribe();\n this._update?.unsubscribe();\n\n delete this._add;\n delete this._remove;\n delete this._update;\n delete this._watcher;\n\n this._path = \"\";\n this._globs = [\"**\"];\n this._nodes = Promise.resolve(new ZDataSourceStatic<IZFileSystemNode>([]));\n }\n\n public async get(path: string): Promise<IZFileSystemNode | null> {\n const nodes = await this._nodes;\n const items = await nodes.items();\n const node = find(items, (f) => f.path === path);\n\n return firstDefined(null, node);\n }\n\n public async count(request: IZDataRequest): Promise<number> {\n const source = await this._nodes;\n return source.count(request);\n }\n\n public async retrieve(request: IZDataRequest): Promise<IZFileSystemNode[]> {\n const source = await this._nodes;\n return source.retrieve(request);\n }\n}\n","import { sleep } from \"@zthun/helpful-fn\";\n\n/**\n * The actual delay time that you should wait for a watch\n * operation to pick up your file changes.\n */\nexport const ZWatchDelay = 1500;\n\n/**\n * Performs a sleep long enough to allow a watch operation\n * to pick up a change.\n *\n * You should never really need this. Where it is useful\n * is for unit testing with IO operations and you want to\n * wait for your write operations to get picked up by\n * a file watch operation.\n */\nexport function sleepWatchDelay() {\n return sleep(ZWatchDelay);\n}\n","import { readdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { firstTruthy, sleep } from \"@zthun/helpful-fn\";\nimport type { IZLogger } from \"@zthun/lumberjacky-log\";\nimport { ZLogEntryBuilder, ZLoggerContext } from \"@zthun/lumberjacky-log\";\nimport glob from \"fast-glob\";\nimport { noop } from \"lodash-es\";\n\nimport { ZWatchDelay } from \"../sleep-watch-delay/sleep-watch-delay.mjs\";\n\n/**\n * Options for the nudge command.\n */\nexport interface IZCrumbtrailJobNudgeOptions {\n /**\n * The directory to nudge.\n *\n * The default if not specified is the current working directory.\n */\n directory?: string;\n\n /**\n * Whether to nudge recursively.\n *\n * Warning: This can have severe CPU\n * usage for deep directories.\n *\n * Default is false.\n */\n recursive?: boolean;\n\n /**\n * The total number of milliseconds to wait\n * between nudges.\n *\n * Default is {@link ZWatchDelay}\n */\n every?: number;\n}\n\n/**\n * An operation to continuously nudge a directory.\n *\n * This is a special operation that lists the contents of a targeted parent directory.\n * The main reason for this is to work around an issue when you are running inside of\n * a container and your host is not linux.\n *\n * A lot of times, you will not receive events in this situation for add and update\n * until the virtual file bridge is refreshed by listing the outer directory contents.\n * This command helps to force the bridge to send file change events. You should\n * only need this if you are running on a non linux host inside a docker container.\n *\n * Run a separate container in the background and just nudge the directory\n * for however long you need.\n */\nexport class ZCrumbtrailJobNudge {\n private _controller?: AbortController;\n private _resolve?: (val: number) => void;\n private _promise?: Promise<number>;\n private readonly _logger: IZLogger;\n\n public constructor(logger: IZLogger) {\n this._logger = new ZLoggerContext(\"ZCrumbtrailNudge\", logger);\n }\n\n public async kill(): Promise<void> {\n this._controller?.abort();\n delete this._controller;\n\n await this._promise;\n delete this._promise;\n }\n\n public async run(options: IZCrumbtrailJobNudgeOptions = {}): Promise<number> {\n await this.kill();\n\n const controller = new AbortController();\n this._controller = controller;\n\n const { promise, resolve } = Promise.withResolvers<number>();\n this._promise = promise;\n this._resolve = resolve;\n\n const {\n directory = process.cwd(),\n recursive,\n every = ZWatchDelay,\n } = options;\n\n const ms = firstTruthy(ZWatchDelay, every);\n\n this._logger.log(\n new ZLogEntryBuilder()\n .info()\n .message(`Starting a nudge loop every ${ms} milliseconds`)\n .build(),\n );\n\n if (recursive) {\n this._logger.log(\n new ZLogEntryBuilder()\n .warning()\n .message(\"Nudging is recursive. Child folders will be nudged too.\")\n .build(),\n );\n }\n\n do {\n this._logger.log(\n new ZLogEntryBuilder()\n .info()\n .message(`Nudging ${directory} to refresh`)\n .build(),\n );\n await readdir(dirname(directory)).catch(noop);\n\n if (recursive) {\n await glob(`${directory}/**`, { onlyDirectories: true }).catch(noop);\n }\n\n await sleep(ms);\n } while (!controller.signal.aborted);\n\n resolve(0);\n delete this._resolve;\n\n return this._promise;\n }\n}\n","import { resolve } from \"node:path\";\nimport { cwd } from \"node:process\";\n\nimport { firstDefined } from \"@zthun/helpful-fn\";\nimport type { IZLogEntry, IZLogger } from \"@zthun/lumberjacky-log\";\nimport { ZLogEntryBuilder, ZLoggerContext } from \"@zthun/lumberjacky-log\";\nimport { uniq } from \"lodash-es\";\nimport { minimatch } from \"minimatch\";\n\nimport type { IZFileSystemNode } from \"../file-system/file-system-node.mjs\";\nimport { ZFileWatch } from \"../file-watch/file-watch.mjs\";\n\n/**\n * Arguments for the crumbtrail app.\n */\nexport interface IZCrumbtrailJobWatchOptions {\n /**\n * The directory to watch.\n *\n * If this is falsy, then the cwd is used.\n */\n directory?: string;\n\n /**\n * The list of file globs to watch.\n *\n * If this is falsy or empty, then '**' is used.\n */\n globs?: string[];\n}\n\n/**\n * The root application for the crumbtrail cli.\n */\nexport class ZCrumbtrailJobWatch {\n private _logger: IZLogger;\n private _globs: string[] | undefined;\n private _watch: ZFileWatch | undefined;\n private _ready: Promise<void> = Promise.resolve();\n private _promise: Promise<number> | undefined;\n private _resolve: ((value: number) => void) | undefined;\n\n /**\n * Gets the entry for a basic information message.\n *\n * @returns\n * The log entry for a basic information message.\n */\n public static msg(msg: string): IZLogEntry {\n return new ZLogEntryBuilder().info().message(msg).build();\n }\n\n /**\n * Gets the message for when a file is added.\n *\n * @returns\n * The message for when a file is added.\n */\n public static add(path: string): IZLogEntry {\n return new ZLogEntryBuilder().info().message(`Node added: ${path}`).build();\n }\n\n /**\n * Gets the message for when a file/folder is removed.\n *\n * @returns\n * The message for when a file/folder is added.\n */\n public static remove(path: string): IZLogEntry {\n return new ZLogEntryBuilder()\n .warning()\n .message(`Node removed: ${path}`)\n .build();\n }\n\n /**\n * Gets the message for when a file is updated.\n *\n * @returns\n * The message for when a file is updated.\n */\n public static update(path: string): IZLogEntry {\n return new ZLogEntryBuilder()\n .info()\n .message(`Node updated: ${path}`)\n .build();\n }\n\n /**\n * Gets the current directory being watched.\n *\n * @returns\n * The directory that is watching for events.\n */\n public watching() {\n return Promise.resolve(this._watch?.path);\n }\n\n /**\n * Gets the list of globs that filter the directory contents.\n *\n * @returns\n * The list of globs that filter the directory contents.\n */\n public globs() {\n return Promise.resolve(this._globs?.slice());\n }\n\n /**\n * Returns a promise that can be awaited on to\n * make sure the watch is initialized.\n */\n public async ready() {\n return this._ready;\n }\n\n /**\n * Initializes a new instance of this object.\n *\n * @param logger -\n * The logger to use to output events.\n */\n public constructor(logger: IZLogger) {\n this._logger = new ZLoggerContext(\"ZCrumbtrailApp\", logger);\n }\n\n /**\n * Kills the application.\n */\n public async kill(): Promise<void> {\n await this._watch?.stop();\n\n delete this._watch;\n delete this._globs;\n this._ready = Promise.resolve();\n\n this._resolve?.(0);\n await this._promise;\n delete this._promise;\n }\n\n private _handleFsEvent(path: string, entry: IZLogEntry) {\n const globs = firstDefined([\"**\"], this._globs);\n const directory = firstDefined(cwd(), this._watch?.path);\n\n if (globs?.some((g) => minimatch(path, resolve(directory, g)))) {\n this._logger.log(entry);\n }\n }\n\n private _handleAdd(node: IZFileSystemNode) {\n this._handleFsEvent(node.path, ZCrumbtrailJobWatch.add(node.path));\n }\n\n private _handleRemove(node: IZFileSystemNode) {\n this._handleFsEvent(node.path, ZCrumbtrailJobWatch.remove(node.path));\n }\n\n private _handleUpdate(node: IZFileSystemNode) {\n this._handleFsEvent(node.path, ZCrumbtrailJobWatch.update(node.path));\n }\n\n /**\n * Runs the application.\n *\n * @param args -\n * The application arguments.\n *\n * @returns\n * The process exit code.\n */\n public async run(args: IZCrumbtrailJobWatchOptions = {}): Promise<number> {\n if (this._promise) {\n return this._promise;\n }\n\n const { promise, resolve } = Promise.withResolvers<number>();\n this._resolve = resolve;\n this._promise = promise;\n\n const { directory = cwd(), globs = [\"**\"] } = args;\n\n this._globs = uniq(globs.slice());\n this._globs = this._globs.length ? this._globs : [\"**\"];\n this._watch = new ZFileWatch(directory);\n\n const filter = globs.join(\",\");\n this._logger.log(ZCrumbtrailJobWatch.msg(\"Welcome to Crumbtrail CLI\"));\n this._logger.log(\n ZCrumbtrailJobWatch.msg(`You are now watching ${directory}`),\n );\n this._logger.log(\n ZCrumbtrailJobWatch.msg(`Logging files matching ${filter}.`),\n );\n this._logger.log(ZCrumbtrailJobWatch.msg(\"Press Ctrl+C to stop watching\"));\n\n this._watch.add().subscribe(this._handleAdd.bind(this));\n this._watch.remove().subscribe(this._handleRemove.bind(this));\n this._watch.update().subscribe(this._handleUpdate.bind(this));\n\n this._ready = this._watch.start();\n await this._ready;\n\n return this._promise;\n }\n}\n","import type { PathLike } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function resolvePathLike(path: PathLike): string {\n if (typeof path === \"string\") {\n return resolve(path);\n }\n\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n\n return resolve(path.toString());\n}\n","import type { PathLike } from \"fs\";\nimport { mkdir } from \"fs/promises\";\n\nimport type { IZStreamWrite } from \"./stream-write.mjs\";\n\n/**\n * A stream that writes folders.\n *\n * Writing folders is idempotent. If the folder you\n * are trying to write already exists, then the write\n * operation still succeeds\n */\nexport class ZStreamFolder implements IZStreamWrite {\n public async write(path: PathLike): Promise<number> {\n await mkdir(path, { recursive: true });\n\n return 0;\n }\n}\n","import type { PathLike, Stats } from \"node:fs\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\n\nimport { dirname } from \"path\";\n\nimport { resolvePathLike } from \"../resolve-path-like/resolve-path-like.js\";\nimport { ZStreamFolder } from \"./stream-folder.mjs\";\nimport type { IZStreamRead, IZStreamReadOptions } from \"./stream-read.mjs\";\nimport type { IZStreamWrite, IZStreamWriteOptions } from \"./stream-write.mjs\";\n\n/**\n * Options for the stream file object.\n */\nexport interface IZStreamFileOptions {\n /**\n * Cache options.\n *\n * A warning that file content caching will take up significant memory\n * if the file size is too big or the max files is too big. Make sure\n * you know what you're doing when you change the default values of this.\n */\n cache?: {\n /**\n * Maximum number of bytes a file can be before it will not be cached.\n * The default is 100 Kib (102400 bytes)\n *\n * @default 102400\n */\n fileSize?: bigint;\n /**\n * The maximum number of files that are to be cached. The cache order\n * is first in, first out. Set this to 0 to not cache anything. The\n * default is 1000.\n *\n * @default 1000\n */\n maxFiles?: number;\n };\n}\n\n/**\n * A stream that can read and write to files.\n *\n * This is mostly a wrapper to readFile and writeFile from node, but\n * with some optimizations.\n *\n * First, this class supports file content caching so reading in a file\n * that's under a certain size threshold will store it in memory for\n * later retrieval.\n */\nexport class ZStreamFile implements IZStreamWrite, IZStreamRead {\n private static readonly FileSizeDefault = 102400; // One Hundred KibiBytes\n private static readonly MaxFilesDefault = 1000;\n\n private _cache = new Map<string, { stats: Stats; buffer: Promise<Buffer> }>();\n\n /**\n * Initializes a new instance of this object.\n *\n * @param options -\n * The options for file read and writes.\n */\n public constructor(public readonly options: IZStreamFileOptions = {}) {}\n\n public async read(\n path: PathLike,\n options?: IZStreamReadOptions,\n ): Promise<Buffer> {\n const _path = resolvePathLike(path);\n\n const stats = await stat(_path);\n const cached = this._cache.get(_path);\n\n const buffer =\n cached && cached.stats.mtimeMs >= stats.mtimeMs\n ? cached.buffer\n : readFile(_path, options);\n\n return this._addToCache(_path, { stats, buffer });\n }\n\n public async write(\n path: PathLike,\n { buffer = Buffer.from(\"\") }: IZStreamWriteOptions = {},\n ): Promise<number> {\n const _path = resolvePathLike(path);\n const directory = dirname(_path);\n\n await new ZStreamFolder().write(directory);\n await writeFile(_path, buffer, { flush: true });\n\n // If this file specifically was cached earlier,\n // we can just remove it now so we make room for\n // another file. Consumers can just read the\n // file again to recache it.\n this._cache.delete(_path);\n\n return buffer.length;\n }\n\n private _addToCache(\n path: string,\n item: { stats: Stats; buffer: Promise<Buffer> },\n ) {\n const { cache = {} } = this.options;\n const {\n fileSize = ZStreamFile.FileSizeDefault,\n maxFiles = ZStreamFile.MaxFilesDefault,\n } = cache;\n\n if (item.stats.size > fileSize) {\n // In this case, the file size is too big to cache in memory,\n // so we're bowing out here.\n return item.buffer;\n }\n\n // We will remove this path from the cache first since\n // we want it to be the most recent file (at the end)\n // of the key list. The removal does nothing if the\n // file was not cached.\n this._cache.delete(path);\n this._cache.set(path, item);\n\n if (this._cache.size > maxFiles) {\n // Retrieving the keys from a javascript map is order\n // by the time in which the keys are created. So\n // we are going to remove the first key which is the\n // oldest.\n const itr = this._cache.keys();\n this._cache.delete(itr.next().value);\n }\n\n return item.buffer;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { IZLogger } from '@zthun/lumberjacky-log';
|
|
2
|
+
/**
|
|
3
|
+
* Options for the nudge command.
|
|
4
|
+
*/
|
|
5
|
+
export interface IZCrumbtrailJobNudgeOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The directory to nudge.
|
|
8
|
+
*
|
|
9
|
+
* The default if not specified is the current working directory.
|
|
10
|
+
*/
|
|
11
|
+
directory?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Whether to nudge recursively.
|
|
14
|
+
*
|
|
15
|
+
* Warning: This can have severe CPU
|
|
16
|
+
* usage for deep directories.
|
|
17
|
+
*
|
|
18
|
+
* Default is false.
|
|
19
|
+
*/
|
|
20
|
+
recursive?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The total number of milliseconds to wait
|
|
23
|
+
* between nudges.
|
|
24
|
+
*
|
|
25
|
+
* Default is {@link ZWatchDelay}
|
|
26
|
+
*/
|
|
27
|
+
every?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* An operation to continuously nudge a directory.
|
|
31
|
+
*
|
|
32
|
+
* This is a special operation that lists the contents of a targeted parent directory.
|
|
33
|
+
* The main reason for this is to work around an issue when you are running inside of
|
|
34
|
+
* a container and your host is not linux.
|
|
35
|
+
*
|
|
36
|
+
* A lot of times, you will not receive events in this situation for add and update
|
|
37
|
+
* until the virtual file bridge is refreshed by listing the outer directory contents.
|
|
38
|
+
* This command helps to force the bridge to send file change events. You should
|
|
39
|
+
* only need this if you are running on a non linux host inside a docker container.
|
|
40
|
+
*
|
|
41
|
+
* Run a separate container in the background and just nudge the directory
|
|
42
|
+
* for however long you need.
|
|
43
|
+
*/
|
|
44
|
+
export declare class ZCrumbtrailJobNudge {
|
|
45
|
+
private _controller?;
|
|
46
|
+
private _resolve?;
|
|
47
|
+
private _promise?;
|
|
48
|
+
private readonly _logger;
|
|
49
|
+
constructor(logger: IZLogger);
|
|
50
|
+
kill(): Promise<void>;
|
|
51
|
+
run(options?: IZCrumbtrailJobNudgeOptions): Promise<number>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { IZLogEntry, IZLogger } from '@zthun/lumberjacky-log';
|
|
2
|
+
/**
|
|
3
|
+
* Arguments for the crumbtrail app.
|
|
4
|
+
*/
|
|
5
|
+
export interface IZCrumbtrailJobWatchOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The directory to watch.
|
|
8
|
+
*
|
|
9
|
+
* If this is falsy, then the cwd is used.
|
|
10
|
+
*/
|
|
11
|
+
directory?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The list of file globs to watch.
|
|
14
|
+
*
|
|
15
|
+
* If this is falsy or empty, then '**' is used.
|
|
16
|
+
*/
|
|
17
|
+
globs?: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The root application for the crumbtrail cli.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ZCrumbtrailJobWatch {
|
|
23
|
+
private _logger;
|
|
24
|
+
private _globs;
|
|
25
|
+
private _watch;
|
|
26
|
+
private _ready;
|
|
27
|
+
private _promise;
|
|
28
|
+
private _resolve;
|
|
29
|
+
/**
|
|
30
|
+
* Gets the entry for a basic information message.
|
|
31
|
+
*
|
|
32
|
+
* @returns
|
|
33
|
+
* The log entry for a basic information message.
|
|
34
|
+
*/
|
|
35
|
+
static msg(msg: string): IZLogEntry;
|
|
36
|
+
/**
|
|
37
|
+
* Gets the message for when a file is added.
|
|
38
|
+
*
|
|
39
|
+
* @returns
|
|
40
|
+
* The message for when a file is added.
|
|
41
|
+
*/
|
|
42
|
+
static add(path: string): IZLogEntry;
|
|
43
|
+
/**
|
|
44
|
+
* Gets the message for when a file/folder is removed.
|
|
45
|
+
*
|
|
46
|
+
* @returns
|
|
47
|
+
* The message for when a file/folder is added.
|
|
48
|
+
*/
|
|
49
|
+
static remove(path: string): IZLogEntry;
|
|
50
|
+
/**
|
|
51
|
+
* Gets the message for when a file is updated.
|
|
52
|
+
*
|
|
53
|
+
* @returns
|
|
54
|
+
* The message for when a file is updated.
|
|
55
|
+
*/
|
|
56
|
+
static update(path: string): IZLogEntry;
|
|
57
|
+
/**
|
|
58
|
+
* Gets the current directory being watched.
|
|
59
|
+
*
|
|
60
|
+
* @returns
|
|
61
|
+
* The directory that is watching for events.
|
|
62
|
+
*/
|
|
63
|
+
watching(): Promise<string | undefined>;
|
|
64
|
+
/**
|
|
65
|
+
* Gets the list of globs that filter the directory contents.
|
|
66
|
+
*
|
|
67
|
+
* @returns
|
|
68
|
+
* The list of globs that filter the directory contents.
|
|
69
|
+
*/
|
|
70
|
+
globs(): Promise<string[] | undefined>;
|
|
71
|
+
/**
|
|
72
|
+
* Returns a promise that can be awaited on to
|
|
73
|
+
* make sure the watch is initialized.
|
|
74
|
+
*/
|
|
75
|
+
ready(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Initializes a new instance of this object.
|
|
78
|
+
*
|
|
79
|
+
* @param logger -
|
|
80
|
+
* The logger to use to output events.
|
|
81
|
+
*/
|
|
82
|
+
constructor(logger: IZLogger);
|
|
83
|
+
/**
|
|
84
|
+
* Kills the application.
|
|
85
|
+
*/
|
|
86
|
+
kill(): Promise<void>;
|
|
87
|
+
private _handleFsEvent;
|
|
88
|
+
private _handleAdd;
|
|
89
|
+
private _handleRemove;
|
|
90
|
+
private _handleUpdate;
|
|
91
|
+
/**
|
|
92
|
+
* Runs the application.
|
|
93
|
+
*
|
|
94
|
+
* @param args -
|
|
95
|
+
* The application arguments.
|
|
96
|
+
*
|
|
97
|
+
* @returns
|
|
98
|
+
* The process exit code.
|
|
99
|
+
*/
|
|
100
|
+
run(args?: IZCrumbtrailJobWatchOptions): Promise<number>;
|
|
101
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zthun/crumbtrail-fs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "A better file system module for node",
|
|
5
5
|
"author": "Anthony Bonta",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,25 +28,28 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@zthun/helpful-fn": "^10.0.
|
|
32
|
-
"@zthun/helpful-query": "^10.0.
|
|
31
|
+
"@zthun/helpful-fn": "^10.0.1",
|
|
32
|
+
"@zthun/helpful-query": "^10.0.1",
|
|
33
|
+
"@zthun/lumberjacky-log": "^4.0.9",
|
|
33
34
|
"chokidar": "^5.0.0",
|
|
35
|
+
"fast-glob": "^3.3.3",
|
|
34
36
|
"glob": "^13.0.6",
|
|
35
37
|
"lodash-es": "^4.18.1",
|
|
36
38
|
"minimatch": "^10.2.6",
|
|
37
39
|
"rxjs": "^7.8.2"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
|
-
"@zthun/janitor-build-config": "^21.
|
|
41
|
-
"@zthun/janitor-ts-config": "^21.
|
|
42
|
+
"@zthun/janitor-build-config": "^21.1.3",
|
|
43
|
+
"@zthun/janitor-ts-config": "^21.1.3",
|
|
44
|
+
"@zthun/janitor-vite": "^21.1.4",
|
|
42
45
|
"typescript": "^6.0.3",
|
|
43
|
-
"vite": "^8.2.
|
|
44
|
-
"vitest": "^4.1.
|
|
46
|
+
"vite": "^8.2.2",
|
|
47
|
+
"vitest": "^4.1.11",
|
|
45
48
|
"vitest-mock-extended": "^5.1.1"
|
|
46
49
|
},
|
|
47
50
|
"files": [
|
|
48
51
|
"dist"
|
|
49
52
|
],
|
|
50
53
|
"sideEffects": false,
|
|
51
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "3aac05ac1a20f55ac9617dd55f69063e2cde261f"
|
|
52
55
|
}
|
package/dist/vite.config.d.mts
DELETED