@gesslar/toolkit 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/browser/lib/Data.js +4 -4
- package/src/browser/lib/TypeSpec.js +115 -39
- package/src/node/index.js +2 -1
- package/src/node/lib/Cache.js +105 -35
- package/src/node/lib/Data.js +49 -0
- package/src/node/lib/DirectoryObject.js +4 -7
- package/src/node/lib/FileObject.js +89 -53
- package/src/node/lib/FileSystem.js +47 -2
- package/src/node/lib/Font.js +1 -1
- package/src/node/lib/Notify.js +6 -6
- package/src/node/lib/Term.js +1 -1
- package/src/node/lib/Util.js +3 -3
- package/src/node/lib/Watcher.js +118 -0
- package/types/browser/lib/Data.d.ts +2 -8
- package/types/browser/lib/Data.d.ts.map +1 -1
- package/types/browser/lib/TypeSpec.d.ts +21 -36
- package/types/browser/lib/TypeSpec.d.ts.map +1 -1
- package/types/node/index.d.ts +2 -1
- package/types/node/lib/Cache.d.ts +36 -5
- package/types/node/lib/Cache.d.ts.map +1 -1
- package/types/node/lib/Data.d.ts +19 -0
- package/types/node/lib/Data.d.ts.map +1 -0
- package/types/node/lib/DirectoryObject.d.ts +6 -5
- package/types/node/lib/DirectoryObject.d.ts.map +1 -1
- package/types/node/lib/FileObject.d.ts +54 -26
- package/types/node/lib/FileObject.d.ts.map +1 -1
- package/types/node/lib/FileSystem.d.ts +19 -0
- package/types/node/lib/FileSystem.d.ts.map +1 -1
- package/types/node/lib/Notify.d.ts +10 -10
- package/types/node/lib/Notify.d.ts.map +1 -1
- package/types/node/lib/Term.d.ts +2 -2
- package/types/node/lib/Term.d.ts.map +1 -1
- package/types/node/lib/Util.d.ts +6 -6
- package/types/node/lib/Util.d.ts.map +1 -1
- package/types/node/lib/Watcher.d.ts +38 -0
- package/types/node/lib/Watcher.d.ts.map +1 -0
|
@@ -4,14 +4,13 @@
|
|
|
4
4
|
* resolution and existence checks.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import {Buffer} from "node:buffer"
|
|
8
8
|
import fs from "node:fs/promises"
|
|
9
|
-
import YAML from "yaml"
|
|
10
9
|
import {URL} from "node:url"
|
|
11
|
-
import {Buffer} from "node:buffer"
|
|
12
10
|
import {inspect} from "node:util"
|
|
13
11
|
|
|
14
|
-
import
|
|
12
|
+
import Cache from "./Cache.js"
|
|
13
|
+
import Data from "./Data.js"
|
|
15
14
|
import DirectoryObject from "./DirectoryObject.js"
|
|
16
15
|
import FS from "./FileSystem.js"
|
|
17
16
|
import Sass from "./Sass.js"
|
|
@@ -33,19 +32,6 @@ import Valid from "./Valid.js"
|
|
|
33
32
|
*/
|
|
34
33
|
|
|
35
34
|
export default class FileObject extends FS {
|
|
36
|
-
/**
|
|
37
|
-
* Configuration mapping data types to their respective parser modules for loadData method.
|
|
38
|
-
* Each parser module must have a .parse() method that accepts a string and returns parsed data.
|
|
39
|
-
*
|
|
40
|
-
* @type {{[key: string]: Array<typeof JSON5 | typeof YAML>}}
|
|
41
|
-
*/
|
|
42
|
-
static dataLoaderConfig = Object.freeze({
|
|
43
|
-
json5: [JSON5],
|
|
44
|
-
json: [JSON5],
|
|
45
|
-
yaml: [YAML],
|
|
46
|
-
any: [JSON5, YAML]
|
|
47
|
-
})
|
|
48
|
-
|
|
49
35
|
/**
|
|
50
36
|
* @type {object}
|
|
51
37
|
* @property {string|null} supplied - User-supplied path
|
|
@@ -70,6 +56,8 @@ export default class FileObject extends FS {
|
|
|
70
56
|
real: null,
|
|
71
57
|
})
|
|
72
58
|
|
|
59
|
+
#cache = null
|
|
60
|
+
|
|
73
61
|
/**
|
|
74
62
|
* Constructs a FileObject instance.
|
|
75
63
|
*
|
|
@@ -162,6 +150,7 @@ export default class FileObject extends FS {
|
|
|
162
150
|
extension: this.extension,
|
|
163
151
|
isFile: this.isFile,
|
|
164
152
|
parentPath: this.parentPath,
|
|
153
|
+
cached: this.cached
|
|
165
154
|
}
|
|
166
155
|
}
|
|
167
156
|
|
|
@@ -377,17 +366,74 @@ export default class FileObject extends FS {
|
|
|
377
366
|
}
|
|
378
367
|
}
|
|
379
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Whether this FileObject has an active cache attached.
|
|
371
|
+
*
|
|
372
|
+
* @returns {boolean} True if a Cache instance is attached
|
|
373
|
+
*/
|
|
374
|
+
get cached() {
|
|
375
|
+
return Data.isType(this.#cache, "Cache")
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Attaches a Cache instance to this FileObject for caching read and
|
|
380
|
+
* loadData results. If no cache is provided, a new Cache is created.
|
|
381
|
+
*
|
|
382
|
+
* @param {Cache} [cache] - The Cache instance to attach
|
|
383
|
+
* @returns {FileObject} This FileObject for chaining
|
|
384
|
+
* @throws {Sass} If a cache is already attached
|
|
385
|
+
*/
|
|
386
|
+
withCache(cache) {
|
|
387
|
+
Valid.type(cache, "Undefined|Cache")
|
|
388
|
+
Valid.assert(!this.#cache, "Cache already set. Remove the cache before re-assigning.")
|
|
389
|
+
|
|
390
|
+
cache ??= new Cache()
|
|
391
|
+
|
|
392
|
+
this.#cache = cache
|
|
393
|
+
|
|
394
|
+
return this
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Removes the attached cache, clearing any cached data for this file first.
|
|
399
|
+
*
|
|
400
|
+
* @returns {FileObject} This FileObject for chaining
|
|
401
|
+
*/
|
|
402
|
+
removeCache() {
|
|
403
|
+
this.resetCache()
|
|
404
|
+
this.#cache = null
|
|
405
|
+
|
|
406
|
+
return this
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Clears cached data for this file without removing the cache itself.
|
|
411
|
+
*
|
|
412
|
+
* @returns {FileObject} This FileObject for chaining
|
|
413
|
+
*/
|
|
414
|
+
resetCache() {
|
|
415
|
+
this.#cache?.resetCache(this)
|
|
416
|
+
|
|
417
|
+
return this
|
|
418
|
+
}
|
|
419
|
+
|
|
380
420
|
/**
|
|
381
421
|
* Reads the content of a file asynchronously.
|
|
382
422
|
*
|
|
383
|
-
* @param {
|
|
423
|
+
* @param {object} [options] - Read options
|
|
424
|
+
* @param {string} [options.encoding="utf8"] - The encoding to read the file as
|
|
425
|
+
* @param {boolean} [options.skipCache=false] - If true, bypass the cache
|
|
384
426
|
* @returns {Promise<string>} The file contents
|
|
385
427
|
*/
|
|
386
|
-
async read(encoding="utf8") {
|
|
428
|
+
async read({encoding="utf8", skipCache=false} = {}) {
|
|
387
429
|
const filePath = this.path
|
|
388
430
|
|
|
431
|
+
if(this.#cache && skipCache === false)
|
|
432
|
+
return await this.#cache.loadFromCache(
|
|
433
|
+
this, {encoding})
|
|
434
|
+
|
|
389
435
|
if(!(await this.exists))
|
|
390
|
-
throw Sass.new(`No such file '${
|
|
436
|
+
throw Sass.new(`No such file '${this}'`)
|
|
391
437
|
|
|
392
438
|
return await fs.readFile(filePath, encoding)
|
|
393
439
|
}
|
|
@@ -419,7 +465,7 @@ export default class FileObject extends FS {
|
|
|
419
465
|
*
|
|
420
466
|
* @param {string} content - The content to write
|
|
421
467
|
* @param {string} [encoding] - The encoding in which to write (default: "utf8")
|
|
422
|
-
* @returns {Promise<
|
|
468
|
+
* @returns {Promise<undefined>}
|
|
423
469
|
* @throws {Sass} If the file URL is invalid or the parent directory doesn't exist
|
|
424
470
|
* @example
|
|
425
471
|
* const file = new FileObject('./output/data.json')
|
|
@@ -444,7 +490,7 @@ export default class FileObject extends FS {
|
|
|
444
490
|
* Supports ArrayBuffer, TypedArrays (Uint8Array, etc.), Blob, and Node Buffer types.
|
|
445
491
|
*
|
|
446
492
|
* @param {ArrayBuffer|Blob|Buffer} data - The binary data to write
|
|
447
|
-
* @returns {Promise<
|
|
493
|
+
* @returns {Promise<undefined>}
|
|
448
494
|
* @throws {Sass} If the file URL is invalid
|
|
449
495
|
* @throws {Sass} If the parent directory doesn't exist
|
|
450
496
|
* @throws {Sass} If the data is not a valid binary type
|
|
@@ -471,44 +517,34 @@ export default class FileObject extends FS {
|
|
|
471
517
|
}
|
|
472
518
|
|
|
473
519
|
/**
|
|
474
|
-
* Loads an object from JSON or YAML file.
|
|
475
|
-
*
|
|
520
|
+
* Loads an object from JSON or YAML file. Attempts to parse content as JSON5
|
|
521
|
+
* first, then falls back to YAML if specified.
|
|
476
522
|
*
|
|
477
|
-
* @param {
|
|
478
|
-
* @param {string} [
|
|
523
|
+
* @param {object} [options] - Load options
|
|
524
|
+
* @param {string} [options.type="any"] - The expected type of data to parse ("json", "json5", "yaml", or "any")
|
|
525
|
+
* @param {string} [options.encoding="utf8"] - The encoding to read the file as
|
|
526
|
+
* @param {boolean} [options.skipCache=false] - If true, bypass the cache
|
|
479
527
|
* @returns {Promise<unknown>} The parsed data object
|
|
480
528
|
* @throws {Sass} If the content cannot be parsed or type is unsupported
|
|
481
529
|
* @example
|
|
482
530
|
* const configFile = new FileObject('./config.json5')
|
|
483
|
-
* const config = await configFile.loadData('json5')
|
|
531
|
+
* const config = await configFile.loadData({type: 'json5'})
|
|
484
532
|
*
|
|
485
533
|
* // Auto-detect format
|
|
486
|
-
* const data = await configFile.loadData(
|
|
487
|
-
*/
|
|
488
|
-
async loadData(type="any", encoding="utf8") {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
if(!toTry)
|
|
499
|
-
throw Sass.new(`Unsupported data type '${type}'. Supported types: json, json5, yaml.`)
|
|
500
|
-
|
|
501
|
-
for(const format of toTry) {
|
|
502
|
-
try {
|
|
503
|
-
const result = format.parse(content)
|
|
504
|
-
|
|
505
|
-
return result
|
|
506
|
-
} catch {
|
|
507
|
-
// nothing to see here
|
|
508
|
-
}
|
|
509
|
-
}
|
|
534
|
+
* const data = await configFile.loadData()
|
|
535
|
+
*/
|
|
536
|
+
async loadData({type="any", encoding="utf8", skipCache=false} = {}) {
|
|
537
|
+
if(this.#cache && skipCache === false)
|
|
538
|
+
return await this.#cache.loadDataFromCache(
|
|
539
|
+
this, {encoding, type})
|
|
540
|
+
|
|
541
|
+
if(!(await this.exists))
|
|
542
|
+
throw Sass.new(`No such file '${this}'`)
|
|
543
|
+
|
|
544
|
+
const content = await this.read({encoding, skipCache})
|
|
545
|
+
const result = Data.textAsData(content, type)
|
|
510
546
|
|
|
511
|
-
|
|
547
|
+
return result
|
|
512
548
|
}
|
|
513
549
|
|
|
514
550
|
/**
|
|
@@ -610,7 +646,7 @@ export default class FileObject extends FS {
|
|
|
610
646
|
/**
|
|
611
647
|
* Deletes the file from the filesystem.
|
|
612
648
|
*
|
|
613
|
-
* @returns {Promise<
|
|
649
|
+
* @returns {Promise<undefined>} Resolves when file is deleted
|
|
614
650
|
* @throws {Sass} If the file URL is invalid
|
|
615
651
|
* @throws {Sass} If the file does not exist
|
|
616
652
|
* @example
|
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
import path from "node:path"
|
|
12
12
|
import url from "node:url"
|
|
13
13
|
|
|
14
|
+
import Collection from "../../browser/lib/Collection.js"
|
|
14
15
|
import Data from "../../browser/lib/Data.js"
|
|
16
|
+
import Glog from "./Glog.js"
|
|
15
17
|
import Valid from "./Valid.js"
|
|
16
|
-
import
|
|
18
|
+
import Watcher from "./Watcher.js"
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
|
-
* @import
|
|
21
|
+
* @import Sass from "./Sass.js"
|
|
20
22
|
*/
|
|
21
23
|
|
|
22
24
|
const fdTypes = Object.freeze(["file", "directory"])
|
|
@@ -33,6 +35,8 @@ export default class FileSystem {
|
|
|
33
35
|
static upperFdTypes = upperFdTypes
|
|
34
36
|
static fdType = fdType
|
|
35
37
|
|
|
38
|
+
#watcher = null
|
|
39
|
+
|
|
36
40
|
/**
|
|
37
41
|
* Compute the relative path from another file or directory to this instance.
|
|
38
42
|
*
|
|
@@ -53,6 +57,47 @@ export default class FileSystem {
|
|
|
53
57
|
return FileSystem.relativeOrAbsolute(fileOrDirectoryObject, this)
|
|
54
58
|
}
|
|
55
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Watch this file or directory for changes.
|
|
62
|
+
*
|
|
63
|
+
* @param {object} [options] - Watch options
|
|
64
|
+
* @param {Function} [options.onChange] - Callback invoked on change
|
|
65
|
+
* @param {number} [options.debounceMs] - Debounce interval in milliseconds
|
|
66
|
+
* @param {boolean} [options.persistent] - Keep the process alive while watching
|
|
67
|
+
* @returns {Promise<undefined>}
|
|
68
|
+
*/
|
|
69
|
+
async watch(options={}) {
|
|
70
|
+
Valid.type(options, "Object")
|
|
71
|
+
|
|
72
|
+
const localOptions = Collection.cloneObject(options)
|
|
73
|
+
|
|
74
|
+
const {onChange} = localOptions ?? {}
|
|
75
|
+
Valid.type(onChange, "Undefined|Function")
|
|
76
|
+
|
|
77
|
+
delete localOptions.onChange
|
|
78
|
+
|
|
79
|
+
this.stopWatching()
|
|
80
|
+
|
|
81
|
+
this.#watcher = new Watcher()
|
|
82
|
+
|
|
83
|
+
await this.#watcher.watch(this, Object.assign({},
|
|
84
|
+
localOptions,
|
|
85
|
+
{
|
|
86
|
+
onChange: onChange ?? (() => {
|
|
87
|
+
Glog(`${this} changed somehow.`)
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Stop watching this file or directory for changes.
|
|
95
|
+
*/
|
|
96
|
+
stopWatching() {
|
|
97
|
+
this.#watcher?.stopWatching()
|
|
98
|
+
this.#watcher = null
|
|
99
|
+
}
|
|
100
|
+
|
|
56
101
|
/**
|
|
57
102
|
* Fix slashes in a path
|
|
58
103
|
*
|
package/src/node/lib/Font.js
CHANGED
package/src/node/lib/Notify.js
CHANGED
|
@@ -31,7 +31,7 @@ export class Notify {
|
|
|
31
31
|
*
|
|
32
32
|
* @param {string} type - Event name to dispatch.
|
|
33
33
|
* @param {unknown} [payload] - Data to send with the event.
|
|
34
|
-
* @returns {
|
|
34
|
+
* @returns {undefined}
|
|
35
35
|
*/
|
|
36
36
|
emit(type, payload=undefined) {
|
|
37
37
|
Valid.type(type, "String", {allowEmpty: false})
|
|
@@ -46,7 +46,7 @@ export class Notify {
|
|
|
46
46
|
*
|
|
47
47
|
* @param {string} type - Event name to dispatch.
|
|
48
48
|
* @param {unknown} [payload] - Data to send with the event.
|
|
49
|
-
* @returns {Promise<
|
|
49
|
+
* @returns {Promise<undefined>} Resolves when all listeners have completed.
|
|
50
50
|
*/
|
|
51
51
|
async asyncEmit(type, payload) {
|
|
52
52
|
Valid.type(type, "String", {allowEmpty: false})
|
|
@@ -74,10 +74,10 @@ export class Notify {
|
|
|
74
74
|
* Registers a listener for the given event type.
|
|
75
75
|
*
|
|
76
76
|
* @param {string} type - Event name to listen for.
|
|
77
|
-
* @param {(payload: unknown) =>
|
|
77
|
+
* @param {(payload: unknown) => undefined} handler - Listener callback.
|
|
78
78
|
* @param {EventEmitter} [emitter] - The EventEmitter to attach to. Default is internal emitter.
|
|
79
79
|
* @param {NotifyEventOptions} [options] - Options for the listener.
|
|
80
|
-
* @returns {() =>
|
|
80
|
+
* @returns {() => undefined} Dispose function to unregister the handler.
|
|
81
81
|
*/
|
|
82
82
|
on(type, handler, emitter=this.#emitter, options=undefined) {
|
|
83
83
|
Valid.type(type, "String", {allowEmpty: false})
|
|
@@ -96,9 +96,9 @@ export class Notify {
|
|
|
96
96
|
* Removes a previously registered listener for the given event type.
|
|
97
97
|
*
|
|
98
98
|
* @param {string} type - Event name to remove.
|
|
99
|
-
* @param {(payload: unknown) =>
|
|
99
|
+
* @param {(payload: unknown) => undefined} handler - Listener callback to detach.
|
|
100
100
|
* @param {EventEmitter} [emitter] - The EventEmitter from which to remove. Default is internal emitter.
|
|
101
|
-
* @returns {
|
|
101
|
+
* @returns {undefined}
|
|
102
102
|
*/
|
|
103
103
|
off(type, handler, emitter=this.#emitter) {
|
|
104
104
|
Valid.type(type, "String", {allowEmpty: false})
|
package/src/node/lib/Term.js
CHANGED
|
@@ -230,7 +230,7 @@ export default class Term {
|
|
|
230
230
|
* @param {string | Array<string | [string, string]>} args - Message or segments.
|
|
231
231
|
* @param {object} [options] - Behaviour flags.
|
|
232
232
|
* @param {boolean} options.silent - When true, suppress output.
|
|
233
|
-
* @returns {
|
|
233
|
+
* @returns {undefined}
|
|
234
234
|
*/
|
|
235
235
|
static status(args, {silent=false} = {}) {
|
|
236
236
|
if(silent)
|
package/src/node/lib/Util.js
CHANGED
|
@@ -65,7 +65,7 @@ export default class Util extends BrowserUtil {
|
|
|
65
65
|
* @param {object} emitter - The emitter object (already validated)
|
|
66
66
|
* @param {string} event - The event name to emit
|
|
67
67
|
* @param {...unknown} args - Arguments to pass to event listeners
|
|
68
|
-
* @returns {Promise<
|
|
68
|
+
* @returns {Promise<undefined>} Resolves when all listeners have completed
|
|
69
69
|
*/
|
|
70
70
|
static async #performAsyncEmit(emitter, event, ...args) {
|
|
71
71
|
const listeners = emitter.listeners(event)
|
|
@@ -97,7 +97,7 @@ export default class Util extends BrowserUtil {
|
|
|
97
97
|
* @param {EventEmitter} emitter - The EventEmitter instance to emit on
|
|
98
98
|
* @param {string} event - The event name to emit
|
|
99
99
|
* @param {...unknown} args - Arguments to pass to event listeners
|
|
100
|
-
* @returns {Promise<
|
|
100
|
+
* @returns {Promise<undefined>} Resolves when all listeners have completed
|
|
101
101
|
*/
|
|
102
102
|
static async asyncEmit(emitter, event, ...args) {
|
|
103
103
|
try {
|
|
@@ -124,7 +124,7 @@ export default class Util extends BrowserUtil {
|
|
|
124
124
|
* @param {object} emitter - Any object with EventEmitter-like interface
|
|
125
125
|
* @param {string} event - The event name to emit
|
|
126
126
|
* @param {...unknown} args - Arguments to pass to event listeners
|
|
127
|
-
* @returns {Promise<
|
|
127
|
+
* @returns {Promise<undefined>} Resolves when all listeners have completed, but no grapes.
|
|
128
128
|
*/
|
|
129
129
|
static async asyncEmitQuack(emitter, event, ...args) {
|
|
130
130
|
try {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import {watch} from "node:fs/promises"
|
|
2
|
+
import Valid from "./Valid.js"
|
|
3
|
+
import Data from "./Data.js"
|
|
4
|
+
import Time from "../../browser/lib/Time.js"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @import FileObject from "./FileObject.js"
|
|
8
|
+
* @import DirectoryObject from "./DirectoryObject.js"
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const OverFlowBehaviour = Object.freeze({
|
|
12
|
+
IGNORE: "ignore",
|
|
13
|
+
THROW: "throw",
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export default class Watcher {
|
|
17
|
+
#abortController
|
|
18
|
+
#state = new Map()
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Watch one or more file/directory targets for changes, invoking a callback
|
|
22
|
+
* with debounce protection.
|
|
23
|
+
*
|
|
24
|
+
* @param {FileObject|DirectoryObject|Array.<(FileObject|DirectoryObject)>} targets - The target(s) to watch
|
|
25
|
+
* @param {object} options - Watch options
|
|
26
|
+
* @param {(target: FileObject|DirectoryObject) => void} options.onChange - Callback invoked on change
|
|
27
|
+
* @param {number} [options.debounceMs=50] - Debounce interval in milliseconds
|
|
28
|
+
* @param {boolean} [options.persistent=true] - Keep the process alive while watching
|
|
29
|
+
* @param {boolean} [options.recursive=false] - Watch subdirectories (directories only)
|
|
30
|
+
* @param {string} [options.overflow="ignore"] - Overflow behaviour ("ignore" or "throw")
|
|
31
|
+
* @returns {Promise<undefined>}
|
|
32
|
+
*/
|
|
33
|
+
async watch(targets, {
|
|
34
|
+
onChange,
|
|
35
|
+
debounceMs=50,
|
|
36
|
+
persistent=true,
|
|
37
|
+
recursive=false,
|
|
38
|
+
overflow=OverFlowBehaviour.IGNORE
|
|
39
|
+
} = {}) {
|
|
40
|
+
Valid.type(targets, "FileObject|DirectoryObject|(FileObject|DirectoryObject)[]")
|
|
41
|
+
Valid.type(onChange, "Function")
|
|
42
|
+
Valid.type(debounceMs, "Number")
|
|
43
|
+
Valid.type(persistent, "Boolean")
|
|
44
|
+
Valid.type(recursive, "Undefined|Boolean")
|
|
45
|
+
Valid.type(overflow, "String")
|
|
46
|
+
Valid.assert(Object.values(OverFlowBehaviour).includes(overflow), `Overflow must be one of "ignore" or "throw".`)
|
|
47
|
+
|
|
48
|
+
if(!Data.isType(targets, "Array")) {
|
|
49
|
+
targets = [targets]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.#abortController = new AbortController()
|
|
53
|
+
|
|
54
|
+
for(const target of targets) {
|
|
55
|
+
const watcher = watch(target.url, {
|
|
56
|
+
recursive: target.isDirectory ? recursive : false,
|
|
57
|
+
persistent,
|
|
58
|
+
signal: this.#abortController.signal,
|
|
59
|
+
overflow
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
this.#state.set(target, {busy: false, pending: false})
|
|
63
|
+
|
|
64
|
+
;(async() => {
|
|
65
|
+
try {
|
|
66
|
+
for await(const _ of watcher) {
|
|
67
|
+
const state = this.#state.get(target)
|
|
68
|
+
|
|
69
|
+
if(!state) {
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if(state.busy) {
|
|
74
|
+
state.pending = true
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
state.pending = false
|
|
79
|
+
state.busy = true
|
|
80
|
+
|
|
81
|
+
while(true) {
|
|
82
|
+
await Time.after(debounceMs)
|
|
83
|
+
|
|
84
|
+
if(state.pending) {
|
|
85
|
+
state.pending = false
|
|
86
|
+
continue
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
break
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
await onChange(target)
|
|
94
|
+
} catch(callbackErr) {
|
|
95
|
+
console.error("Watcher onChange callback error:", callbackErr)
|
|
96
|
+
}
|
|
97
|
+
state.busy = false
|
|
98
|
+
}
|
|
99
|
+
} catch(err) {
|
|
100
|
+
if(err.name === "AbortError") {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.error("Watcher error:", err)
|
|
105
|
+
}
|
|
106
|
+
})()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Stop watching all targets.
|
|
112
|
+
*/
|
|
113
|
+
stopWatching() {
|
|
114
|
+
this.#state.clear()
|
|
115
|
+
this.#abortController?.abort()
|
|
116
|
+
this.#abortController = null
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -106,15 +106,9 @@ export default class Data {
|
|
|
106
106
|
* defining the type of a value and whether an array is expected.
|
|
107
107
|
*
|
|
108
108
|
* @param {string} string - The string to parse into a type spec.
|
|
109
|
-
* @
|
|
110
|
-
* @returns {Array<object>} An array of type specs.
|
|
109
|
+
* @returns {TypeSpec} A new TypeSpec instance.
|
|
111
110
|
*/
|
|
112
|
-
static newTypeSpec(string: string
|
|
113
|
-
/**
|
|
114
|
-
* - The delimiter for union types
|
|
115
|
-
*/
|
|
116
|
-
delimiter?: string;
|
|
117
|
-
}): Array<object>;
|
|
111
|
+
static newTypeSpec(string: string): TypeSpec;
|
|
118
112
|
/**
|
|
119
113
|
* Checks if a value is of a specified type
|
|
120
114
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Data.d.ts","sourceRoot":"","sources":["../../../src/browser/lib/Data.js"],"names":[],"mappings":"AAUA;IACA;;;;;OAKG;IACD,mBAFQ,KAAK,CAAC,MAAM,CAAC,CAgBnB;IAEF;;;;;OAKG;IACH,qBAFU,KAAK,CAAC,MAAM,CAAC,CAmBrB;IAEF;;;;;;;OAOG;IACH,kBAFU,KAAK,CAAC,MAAM,CAAC,CAKrB;IAEF;;;;;OAKG;IACH,uBAFU,KAAK,CAAC,MAAM,CAAC,CAE2D;IAElF;;;;;;OAMG;IACH,sBAJW,MAAM,UACN,MAAM,GACJ,MAAM,CAMlB;IAED;;;;;;OAMG;IACH,uBAJW,MAAM,WACN,MAAM,GACJ,MAAM,CAMlB;IAED;;;;;;;;;;;OAWG;IACH,yBATW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAWlB;IAED;;;;;;;;;;;OAWG;IACH,wBATW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAWlB;IAED;;;;;;;OAOG;IACH,yBALW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAWlB;IAED;;;;;;;OAOG;IACH,0BALW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAYlB;IAED;;;;;OAKG;IAEH;;;;;OAKG;IAEH
|
|
1
|
+
{"version":3,"file":"Data.d.ts","sourceRoot":"","sources":["../../../src/browser/lib/Data.js"],"names":[],"mappings":"AAUA;IACA;;;;;OAKG;IACD,mBAFQ,KAAK,CAAC,MAAM,CAAC,CAgBnB;IAEF;;;;;OAKG;IACH,qBAFU,KAAK,CAAC,MAAM,CAAC,CAmBrB;IAEF;;;;;;;OAOG;IACH,kBAFU,KAAK,CAAC,MAAM,CAAC,CAKrB;IAEF;;;;;OAKG;IACH,uBAFU,KAAK,CAAC,MAAM,CAAC,CAE2D;IAElF;;;;;;OAMG;IACH,sBAJW,MAAM,UACN,MAAM,GACJ,MAAM,CAMlB;IAED;;;;;;OAMG;IACH,uBAJW,MAAM,WACN,MAAM,GACJ,MAAM,CAMlB;IAED;;;;;;;;;;;OAWG;IACH,yBATW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAWlB;IAED;;;;;;;;;;;OAWG;IACH,wBATW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAWlB;IAED;;;;;;;OAOG;IACH,yBALW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAWlB;IAED;;;;;;;OAOG;IACH,0BALW,MAAM,UACN,MAAM,oBACN,OAAO,GACL,MAAM,CAYlB;IAED;;;;;OAKG;IAEH;;;;;OAKG;IAEH;;;;;;OAMG;IACH,2BAHW,MAAM,GACJ,QAAQ,CAIpB;IAED;;;;;;;OAOG;IACH,qBALW,OAAO,QACP,MAAM,GAAC,QAAQ;;;;qBAlBZ,OAAO;QAoBR,OAAO,CAQnB;IAED;;;;;OAKG;IACH,yBAHW,MAAM,GACJ,OAAO,CASnB;IAED;;;;;;;;OAQG;IACH,yBAJW,OAAO,QACP,MAAM,GACJ,OAAO,CAenB;IAED;;;;;;OAMG;IACH,qBAHW,OAAO,GACL,MAAM,CAoBlB;IAED;;;;;OAKG;IACH,wBAHW,OAAO,GACL,OAAO,CAInB;IAED;;;;;;;;OAQG;IACH,sBALW,OAAO,oBACP,OAAO,GAEL,OAAO,CA8BnB;IAED;;;;;OAKG;IACH,6BAHW,MAAM,GACJ,MAAM,CAmBlB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,QACN,KAAK,CAAC,MAAM,CAAC,GACX,MAAM,CAiBlB;IAED;;;;;;;OAOG;IACH,2BAJW,MAAM,QACN,KAAK,CAAC,MAAM,CAAC,SACb,OAAO,QAMjB;IAED;;;;;OAKG;IACH,+BAHc,MAAM,EAAA,GACP,MAAM,CAqBlB;IAED;;;;;;;OAOG;IACH,wBAJW,KAAK,CAAC,OAAO,CAAC,aACd,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAClC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAMnC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,OACN,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;OAOG;IACH,oBALW,MAAM,OACN,MAAM,OACN,MAAM,GACJ,OAAO,CAInB;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,4BAbW,OAAO,GACL,OAAO,CA+BnB;IAED;;;;;;;;;;;;;;;OAeG;IACH,uBAXW,OAAO,GACL,OAAO,CAgBnB;CAEF;qBA5gBoB,eAAe"}
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Options for creating a new TypeSpec.
|
|
3
|
-
*
|
|
4
|
-
* @typedef {object} TypeSpecOptions
|
|
5
|
-
* @property {string} [delimiter="|"] - The delimiter for union types
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Options for type validation methods.
|
|
9
|
-
*
|
|
10
|
-
* @typedef {object} TypeValidationOptions
|
|
11
|
-
* @property {boolean} [allowEmpty=true] - Whether empty values are allowed
|
|
12
|
-
*/
|
|
13
1
|
/**
|
|
14
2
|
* Type specification class for parsing and validating complex type definitions.
|
|
15
3
|
* Supports union types, array types, and validation options.
|
|
@@ -19,9 +7,8 @@ export default class TypeSpec {
|
|
|
19
7
|
* Creates a new TypeSpec instance.
|
|
20
8
|
*
|
|
21
9
|
* @param {string} string - The type specification string (e.g., "string|number", "object[]")
|
|
22
|
-
* @param {TypeSpecOptions} [options] - Additional parsing options
|
|
23
10
|
*/
|
|
24
|
-
constructor(string: string
|
|
11
|
+
constructor(string: string);
|
|
25
12
|
specs: any[];
|
|
26
13
|
length: number;
|
|
27
14
|
stringRepresentation: string;
|
|
@@ -91,36 +78,34 @@ export default class TypeSpec {
|
|
|
91
78
|
* Handles array types, union types, and empty value validation.
|
|
92
79
|
*
|
|
93
80
|
* @param {unknown} value - The value to test against the type specifications
|
|
94
|
-
* @param {
|
|
81
|
+
* @param {TypeMatchOptions} [options] - Validation options
|
|
95
82
|
* @returns {boolean} True if the value matches any type specification
|
|
96
83
|
*/
|
|
97
|
-
matches(value: unknown, options?:
|
|
84
|
+
matches(value: unknown, options?: {
|
|
85
|
+
/**
|
|
86
|
+
* - Permit a spec of {@link Data.emptyableTypes} to be empty
|
|
87
|
+
*/
|
|
88
|
+
allowEmpty?: boolean;
|
|
89
|
+
}): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Options that can be passed to {@link TypeSpec.match}
|
|
92
|
+
*
|
|
93
|
+
* @typedef {object} TypeMatchOptions
|
|
94
|
+
* @property {boolean} [allowEmpty=true] - Permit a spec of {@link Data.emptyableTypes} to be empty
|
|
95
|
+
*/
|
|
98
96
|
/**
|
|
99
97
|
* Returns matching type specifications for a value.
|
|
100
98
|
*
|
|
101
99
|
* @param {unknown} value - The value to test against the type specifications
|
|
102
|
-
* @param {
|
|
100
|
+
* @param {TypeMatchOptions} [options] - Validation options
|
|
103
101
|
* @returns {Array<object>} Array of matching type specifications
|
|
104
102
|
*/
|
|
105
|
-
match(value: unknown,
|
|
103
|
+
match(value: unknown, { allowEmpty, }?: {
|
|
104
|
+
/**
|
|
105
|
+
* - Permit a spec of {@link Data.emptyableTypes} to be empty
|
|
106
|
+
*/
|
|
107
|
+
allowEmpty?: boolean;
|
|
108
|
+
}): Array<object>;
|
|
106
109
|
#private;
|
|
107
110
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Options for creating a new TypeSpec.
|
|
110
|
-
*/
|
|
111
|
-
export type TypeSpecOptions = {
|
|
112
|
-
/**
|
|
113
|
-
* - The delimiter for union types
|
|
114
|
-
*/
|
|
115
|
-
delimiter?: string;
|
|
116
|
-
};
|
|
117
|
-
/**
|
|
118
|
-
* Options for type validation methods.
|
|
119
|
-
*/
|
|
120
|
-
export type TypeValidationOptions = {
|
|
121
|
-
/**
|
|
122
|
-
* - Whether empty values are allowed
|
|
123
|
-
*/
|
|
124
|
-
allowEmpty?: boolean;
|
|
125
|
-
};
|
|
126
111
|
//# sourceMappingURL=TypeSpec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypeSpec.d.ts","sourceRoot":"","sources":["../../../src/browser/lib/TypeSpec.js"],"names":[],"mappings":"AAWA
|
|
1
|
+
{"version":3,"file":"TypeSpec.d.ts","sourceRoot":"","sources":["../../../src/browser/lib/TypeSpec.js"],"names":[],"mappings":"AAWA;;;GAGG;AACH;IAGE;;;;OAIG;IACH,oBAFW,MAAM,EAUhB;IAJC,aAAwB;IACxB,eAAgC;IAChC,6BAA2C;IAI7C;;;;OAIG;IACH,YAFa,MAAM,CAkBlB;IAED;;;;OAIG;IACH,UAFa,OAAO,CASnB;IAED;;;;OAIG;IACH,kBAFW,CAAS,IAAO,EAAP,OAAO,KAAG,IAAI,QAIjC;IAED;;;;;OAKG;IACH,gBAHW,CAAS,IAAO,EAAP,OAAO,KAAG,OAAO,GACxB,OAAO,CAInB;IAED;;;;;OAKG;IACH,eAHW,CAAS,IAAO,EAAP,OAAO,KAAG,OAAO,GACxB,OAAO,CAInB;IAED;;;;;OAKG;IACH,iBAHW,CAAS,IAAO,EAAP,OAAO,KAAG,OAAO,GACxB,KAAK,CAAC,OAAO,CAAC,CAI1B;IAED;;;;;OAKG;IACH,cAHW,CAAS,IAAO,EAAP,OAAO,KAAG,OAAO,GACxB,KAAK,CAAC,OAAO,CAAC,CAI1B;IAED;;;;;;OAMG;IACH,iBAJW,CAAS,IAAO,EAAP,OAAO,EAAE,IAAO,EAAP,OAAO,KAAG,OAAO,gBACnC,OAAO,GACL,OAAO,CAInB;IAED;;;;;OAKG;IACH,eAHW,CAAS,IAAO,EAAP,OAAO,KAAG,OAAO,GACxB,MAAM,GAAC,SAAS,CAI5B;IAED;;;;;;;OAOG;IACH,eAJW,OAAO;;;;qBAYJ,OAAO;QAVR,OAAO,CAInB;IAED;;;;;OAKG;IAEH;;;;;;OAMG;IACH,aAJW,OAAO;;;;qBANJ,OAAO;QAQR,KAAK,CAAC,MAAM,CAAC,CAsGzB;;CAqFF"}
|
package/types/node/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default as Collection } from "../browser/lib/Collection.js";
|
|
2
|
-
export { default as Data } from "
|
|
2
|
+
export { default as Data } from "./lib/Data.js";
|
|
3
3
|
export { default as Promised } from "../browser/lib/Promised.js";
|
|
4
4
|
export { default as Time } from "../browser/lib/Time.js";
|
|
5
5
|
export { default as Type } from "../browser/lib/TypeSpec.js";
|
|
@@ -16,4 +16,5 @@ export { default as Glog } from "./lib/Glog.js";
|
|
|
16
16
|
export { default as Term } from "./lib/Term.js";
|
|
17
17
|
export { default as Disposer, Disposer as DisposerClass } from "../browser/lib/Disposer.js";
|
|
18
18
|
export { default as Notify, Notify as NotifyClass } from "./lib/Notify.js";
|
|
19
|
+
export { default as Watcher, OverFlowBehaviour } from "./lib/Watcher.js";
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|