@gesslar/toolkit 0.5.0 → 0.7.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/package.json +8 -8
- package/src/lib/Collection.js +132 -17
- package/src/lib/Contract.js +1 -1
- package/src/lib/Data.js +27 -18
- package/src/lib/DirectoryObject.js +1 -1
- package/src/lib/FS.js +10 -0
- package/src/lib/Glog.js +27 -10
- package/src/lib/Logger.js +3 -0
- package/src/lib/Sass.js +6 -1
- package/src/lib/Tantrum.js +43 -0
- package/src/lib/TypeSpec.js +11 -7
- package/src/lib/Util.js +82 -0
- package/src/lib/Valid.js +24 -6
- package/src/types/Collection.d.ts +6 -1
- package/src/types/Contract.d.ts +27 -27
- package/src/types/Data.d.ts +23 -23
- package/src/types/FS.d.ts +3 -3
- package/src/types/Glog.d.ts +302 -49
- package/src/types/Sass.d.ts +1 -1
- package/src/types/Schemer.d.ts +29 -29
- package/src/types/Tantrum.d.ts +10 -10
- package/src/types/Term.d.ts +1 -1
- package/src/types/Terms.d.ts +21 -21
- package/src/types/Type.d.ts +1 -1
- package/src/types/Util.d.ts +20 -2
- package/src/types/index.d.ts +17 -23
- package/src/types/index.d.ts.map +1 -0
- package/src/types/lib/Cache.d.ts +28 -0
- package/src/types/lib/Cache.d.ts.map +1 -0
- package/src/types/lib/Collection.d.ts +246 -0
- package/src/types/lib/Collection.d.ts.map +1 -0
- package/src/types/lib/Contract.d.ts +72 -0
- package/src/types/lib/Contract.d.ts.map +1 -0
- package/src/types/lib/Data.d.ts +189 -0
- package/src/types/lib/Data.d.ts.map +1 -0
- package/src/types/lib/DirectoryObject.d.ts +148 -0
- package/src/types/lib/DirectoryObject.d.ts.map +1 -0
- package/src/types/lib/FS.d.ts +70 -0
- package/src/types/lib/FS.d.ts.map +1 -0
- package/src/types/lib/FileObject.d.ts +189 -0
- package/src/types/lib/FileObject.d.ts.map +1 -0
- package/src/types/lib/Glog.d.ts +113 -0
- package/src/types/lib/Glog.d.ts.map +1 -0
- package/src/types/lib/Logger.d.ts +46 -0
- package/src/types/lib/Logger.d.ts.map +1 -0
- package/src/types/lib/Sass.d.ts +62 -0
- package/src/types/lib/Sass.d.ts.map +1 -0
- package/src/types/lib/Schemer.d.ts +23 -0
- package/src/types/lib/Schemer.d.ts.map +1 -0
- package/src/types/lib/Tantrum.d.ts +50 -0
- package/src/types/lib/Tantrum.d.ts.map +1 -0
- package/src/types/lib/Term.d.ts +103 -0
- package/src/types/lib/Term.d.ts.map +1 -0
- package/src/types/lib/Terms.d.ts +24 -0
- package/src/types/lib/Terms.d.ts.map +1 -0
- package/src/types/lib/TypeSpec.d.ts +92 -0
- package/src/types/lib/TypeSpec.d.ts.map +1 -0
- package/src/types/lib/Util.d.ts +197 -0
- package/src/types/lib/Util.d.ts.map +1 -0
- package/src/types/lib/Valid.d.ts +33 -0
- package/src/types/lib/Valid.d.ts.map +1 -0
- package/src/lib/Action.js +0 -283
- package/src/lib/ActionBuilder.js +0 -144
- package/src/lib/ActionRunner.js +0 -79
- package/src/lib/Hooks.js +0 -194
- package/src/lib/Piper.js +0 -155
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility class providing common helper functions for string manipulation,
|
|
3
|
+
* timing, hashing, and option parsing.
|
|
4
|
+
*/
|
|
5
|
+
export default class Util {
|
|
6
|
+
/**
|
|
7
|
+
* Capitalizes the first letter of a string.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} text - The text to capitalize
|
|
10
|
+
* @returns {string} Text with first letter capitalized
|
|
11
|
+
*/
|
|
12
|
+
static capitalize(text: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Measure wall-clock time for an async function.
|
|
15
|
+
*
|
|
16
|
+
* @template T
|
|
17
|
+
* @param {() => Promise<T>} fn - Thunk returning a promise.
|
|
18
|
+
* @returns {Promise<{result: T, cost: number}>} Object containing result and elapsed ms (number, 1 decimal).
|
|
19
|
+
*/
|
|
20
|
+
static time<T>(fn: () => Promise<T>): Promise<{
|
|
21
|
+
result: T;
|
|
22
|
+
cost: number;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Right-align a string inside a fixed width (left pad with spaces).
|
|
26
|
+
* If the string exceeds width it is returned unchanged.
|
|
27
|
+
*
|
|
28
|
+
* @param {string|number} text - Text to align.
|
|
29
|
+
* @param {number} width - Target field width (default 80).
|
|
30
|
+
* @returns {string} Padded string.
|
|
31
|
+
*/
|
|
32
|
+
static rightAlignText(text: string | number, width?: number): string;
|
|
33
|
+
/**
|
|
34
|
+
* Centre-align a string inside a fixed width (pad with spaces on left).
|
|
35
|
+
* If the string exceeds width it is returned unchanged.
|
|
36
|
+
*
|
|
37
|
+
* @param {string|number} text - Text to align.
|
|
38
|
+
* @param {number} width - Target field width (default 80).
|
|
39
|
+
* @returns {string} Padded string with text centred.
|
|
40
|
+
*/
|
|
41
|
+
static centreAlignText(text: string | number, width?: number): string;
|
|
42
|
+
/**
|
|
43
|
+
* Compute sha256 hash (hex) of the provided string.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} s - Input string.
|
|
46
|
+
* @returns {string} 64-char hexadecimal digest.
|
|
47
|
+
*/
|
|
48
|
+
static hashOf(s: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Extracts canonical option names from a Commander-style options object.
|
|
51
|
+
*
|
|
52
|
+
* Each key in the input object is a string containing one or more option
|
|
53
|
+
* forms, separated by commas (e.g. "-w, --watch"). This function splits each
|
|
54
|
+
* key, trims whitespace, and parses out the long option name (e.g. "watch")
|
|
55
|
+
* for each entry. If no long option ("--") is present, the short option (e.g.
|
|
56
|
+
* "v" from "-v") will be included in the result array. If both are present,
|
|
57
|
+
* the long option is preferred.
|
|
58
|
+
*
|
|
59
|
+
* Example:
|
|
60
|
+
* generateOptionNames({"-w, --watch": "desc", "-v": "desc"})
|
|
61
|
+
* → ["watch", "v"]
|
|
62
|
+
*
|
|
63
|
+
* Edge cases:
|
|
64
|
+
* - If a key contains only a short option ("-v"), that short name will be
|
|
65
|
+
* included in the result.
|
|
66
|
+
* - If multiple long options are present, only the first is used.
|
|
67
|
+
* - If the option string is malformed, may return undefined for that entry
|
|
68
|
+
* (filtered out).
|
|
69
|
+
*
|
|
70
|
+
* @param {object} object - Mapping of option strings to descriptions.
|
|
71
|
+
* @returns {Array<string>} Array of canonical option names (long preferred, short if no long present).
|
|
72
|
+
*/
|
|
73
|
+
static generateOptionNames(object: object): Array<string>;
|
|
74
|
+
/**
|
|
75
|
+
* Asynchronously awaits all promises in parallel.
|
|
76
|
+
* Wrapper around Promise.all for consistency with other utility methods.
|
|
77
|
+
*
|
|
78
|
+
* @param {Array<Promise<unknown>>} promises - Array of promises to await
|
|
79
|
+
* @returns {Promise<Array<unknown>>} Results of all promises
|
|
80
|
+
*/
|
|
81
|
+
static awaitAll(promises: Array<Promise<unknown>>): Promise<Array<unknown>>;
|
|
82
|
+
/**
|
|
83
|
+
* Settles all promises (both fulfilled and rejected) in parallel.
|
|
84
|
+
* Wrapper around Promise.allSettled for consistency with other utility methods.
|
|
85
|
+
*
|
|
86
|
+
* @param {Array<Promise<unknown>>} promises - Array of promises to settle
|
|
87
|
+
* @returns {Promise<Array<object>>} Results of all settled promises with status and value/reason
|
|
88
|
+
*/
|
|
89
|
+
static settleAll(promises: Array<Promise<unknown>>): Promise<Array<object>>;
|
|
90
|
+
/**
|
|
91
|
+
* Checks if any result in the settled promise array is rejected.
|
|
92
|
+
*
|
|
93
|
+
* @param {Array<object>} result - Array of settled promise results.
|
|
94
|
+
* @returns {boolean} True if any result is rejected, false otherwise.
|
|
95
|
+
*/
|
|
96
|
+
static anyRejected(result: Array<object>): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Filters and returns all rejected results from a settled promise array.
|
|
99
|
+
*
|
|
100
|
+
* @param {Array<object>} result - Array of settled promise results.
|
|
101
|
+
* @returns {Array<object>} Array of rejected results.
|
|
102
|
+
*/
|
|
103
|
+
static settledAndRejected(result: Array<object>): Array<object>;
|
|
104
|
+
/**
|
|
105
|
+
* Extracts the rejection reasons from an array of rejected promise results.
|
|
106
|
+
*
|
|
107
|
+
* @param {Array<object>} rejected - Array of rejected results.
|
|
108
|
+
* @returns {Array<unknown>} Array of rejection reasons.
|
|
109
|
+
*/
|
|
110
|
+
static rejectedReasons(rejected: Array<object>): Array<unknown>;
|
|
111
|
+
/**
|
|
112
|
+
* Throws a Sass error containing all rejection reasons from settled promises.
|
|
113
|
+
*
|
|
114
|
+
* @param {string} [_message] - Optional error message. Defaults to "GIGO"
|
|
115
|
+
* @param {Array<object>} rejected - Array of rejected results.
|
|
116
|
+
* @throws {Error} Throws a Sass error with rejection reasons.
|
|
117
|
+
*/
|
|
118
|
+
static throwRejected(_message?: string, rejected: Array<object>): void;
|
|
119
|
+
/**
|
|
120
|
+
* Filters and returns all fulfilled results from a settled promise array.
|
|
121
|
+
*
|
|
122
|
+
* @param {Array<object>} result - Array of settled promise results.
|
|
123
|
+
* @returns {Array<object>} Array of fulfilled results.
|
|
124
|
+
*/
|
|
125
|
+
static settledAndFulfilled(result: Array<object>): Array<object>;
|
|
126
|
+
/**
|
|
127
|
+
* Extracts the values from all fulfilled results in a settled promise array.
|
|
128
|
+
*
|
|
129
|
+
* @param {Array<object>} result - Array of settled promise results.
|
|
130
|
+
* @returns {Array<unknown>} Array of fulfilled values.
|
|
131
|
+
*/
|
|
132
|
+
static fulfilledValues(result: Array<object>): Array<unknown>;
|
|
133
|
+
/**
|
|
134
|
+
* Returns the first promise to resolve or reject from an array of promises.
|
|
135
|
+
* Wrapper around Promise.race for consistency with other utility methods.
|
|
136
|
+
*
|
|
137
|
+
* @param {Array<Promise<unknown>>} promises - Array of promises to race
|
|
138
|
+
* @returns {Promise<unknown>} Result of the first settled promise
|
|
139
|
+
*/
|
|
140
|
+
static race(promises: Array<Promise<unknown>>): Promise<unknown>;
|
|
141
|
+
/**
|
|
142
|
+
* Private method that performs the actual async emission logic.
|
|
143
|
+
* Handles listener execution, error aggregation, and result processing.
|
|
144
|
+
*
|
|
145
|
+
* @param {object} emitter - The emitter object (already validated)
|
|
146
|
+
* @param {string} event - The event name to emit
|
|
147
|
+
* @param {...unknown} args - Arguments to pass to event listeners
|
|
148
|
+
* @returns {Promise<void>} Resolves when all listeners have completed
|
|
149
|
+
*/
|
|
150
|
+
static "__#private@#performAsyncEmit"(emitter: object, event: string, ...args: unknown[]): Promise<void>;
|
|
151
|
+
/**
|
|
152
|
+
* Emits an event asynchronously and waits for all listeners to complete.
|
|
153
|
+
* Unlike the standard EventEmitter.emit() which is synchronous, this method
|
|
154
|
+
* properly handles async event listeners by waiting for all of them to
|
|
155
|
+
* resolve or reject using Promise.allSettled().
|
|
156
|
+
*
|
|
157
|
+
* Uses strict instanceof checking to ensure the emitter is a genuine EventEmitter.
|
|
158
|
+
*
|
|
159
|
+
* @param {EventEmitter} emitter - The EventEmitter instance to emit on
|
|
160
|
+
* @param {string} event - The event name to emit
|
|
161
|
+
* @param {...unknown} args - Arguments to pass to event listeners
|
|
162
|
+
* @returns {Promise<void>} Resolves when all listeners have completed
|
|
163
|
+
*/
|
|
164
|
+
static asyncEmit(emitter: EventEmitter, event: string, ...args: unknown[]): Promise<void>;
|
|
165
|
+
/**
|
|
166
|
+
* Emits an event asynchronously and waits for all listeners to complete.
|
|
167
|
+
* Like asyncEmit, but uses duck typing for more flexible emitter validation.
|
|
168
|
+
* Accepts any object that has the required EventEmitter-like methods.
|
|
169
|
+
*
|
|
170
|
+
* @param {object} emitter - Any object with EventEmitter-like interface
|
|
171
|
+
* @param {string} event - The event name to emit
|
|
172
|
+
* @param {...unknown} args - Arguments to pass to event listeners
|
|
173
|
+
* @returns {Promise<void>} Resolves when all listeners have completed
|
|
174
|
+
*/
|
|
175
|
+
static asyncEmitAnon(emitter: object, event: string, ...args: unknown[]): Promise<void>;
|
|
176
|
+
/**
|
|
177
|
+
* Determine the Levenshtein distance between two string values
|
|
178
|
+
*
|
|
179
|
+
* @param {string} a The first value for comparison.
|
|
180
|
+
* @param {string} b The second value for comparison.
|
|
181
|
+
* @returns {number} The Levenshtein distance
|
|
182
|
+
*/
|
|
183
|
+
static levenshteinDistance(a: string, b: string): number;
|
|
184
|
+
/**
|
|
185
|
+
* Determine the closest match between a string and allowed values
|
|
186
|
+
* from the Levenshtein distance.
|
|
187
|
+
*
|
|
188
|
+
* @param {string} input The input string to resolve
|
|
189
|
+
* @param {Array<string>} allowedValues The values which are permitted
|
|
190
|
+
* @param {number} [threshold] Max edit distance for a "close match"
|
|
191
|
+
* @returns {string} Suggested, probable match.
|
|
192
|
+
*/
|
|
193
|
+
static findClosestMatch(input: string, allowedValues: Array<string>, threshold?: number): string;
|
|
194
|
+
static regexify(input: any, trim?: boolean, flags?: any[]): RegExp;
|
|
195
|
+
}
|
|
196
|
+
import { EventEmitter } from "node:events";
|
|
197
|
+
//# sourceMappingURL=Util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Util.d.ts","sourceRoot":"","sources":["../../lib/Util.js"],"names":[],"mappings":"AAOA;;;GAGG;AACH;IACE;;;;;OAKG;IACH,wBAHW,MAAM,GACJ,MAAM,CAYlB;IAED;;;;;;OAMG;IACH,YAJa,CAAC,MACH,MAAM,OAAO,CAAC,CAAC,CAAC,GACd,OAAO,CAAC;QAAC,MAAM,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,CAAC,CAQ9C;IAED;;;;;;;OAOG;IACH,4BAJW,MAAM,GAAC,MAAM,UACb,MAAM,GACJ,MAAM,CAWlB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,MAAM,UACb,MAAM,GACJ,MAAM,CAalB;IAED;;;;;OAKG;IACH,iBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,mCAHW,MAAM,GACJ,KAAK,CAAC,MAAM,CAAC,CAazB;IAED;;;;;;OAMG;IACH,0BAHW,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GACrB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAInC;IAED;;;;;;OAMG;IACH,2BAHW,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GACrB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAIlC;IAED;;;;;OAKG;IACH,2BAHW,KAAK,CAAC,MAAM,CAAC,GACX,OAAO,CAInB;IAED;;;;;OAKG;IACH,kCAHW,KAAK,CAAC,MAAM,CAAC,GACX,KAAK,CAAC,MAAM,CAAC,CAIzB;IAED;;;;;OAKG;IACH,iCAHW,KAAK,CAAC,MAAM,CAAC,GACX,KAAK,CAAC,OAAO,CAAC,CAI1B;IAED;;;;;;OAMG;IACH,gCAJW,MAAM,YACN,KAAK,CAAC,MAAM,CAAC,QAKvB;IAED;;;;;OAKG;IACH,mCAHW,KAAK,CAAC,MAAM,CAAC,GACX,KAAK,CAAC,MAAM,CAAC,CAIzB;IAED;;;;;OAKG;IACH,+BAHW,KAAK,CAAC,MAAM,CAAC,GACX,KAAK,CAAC,OAAO,CAAC,CAI1B;IAED;;;;;;OAMG;IACH,sBAHW,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GACrB,OAAO,CAAC,OAAO,CAAC,CAI5B;IAED;;;;;;;;OAQG;IACH,+CALW,MAAM,SACN,MAAM,WACH,OAAO,EAAA,GACR,OAAO,CAAC,IAAI,CAAC,CAmBzB;IAED;;;;;;;;;;;;OAYG;IACH,0BALW,YAAY,SACZ,MAAM,WACH,OAAO,EAAA,GACR,OAAO,CAAC,IAAI,CAAC,CAqBzB;IAED;;;;;;;;;OASG;IACH,8BALW,MAAM,SACN,MAAM,WACH,OAAO,EAAA,GACR,OAAO,CAAC,IAAI,CAAC,CAyBzB;IAED;;;;;;OAMG;IACH,8BAJW,MAAM,KACN,MAAM,GACJ,MAAM,CAsBlB;IAED;;;;;;;;OAQG;IACH,+BALW,MAAM,iBACN,KAAK,CAAC,MAAM,CAAC,cACb,MAAM,GACJ,MAAM,CAwBlB;IAED,mEAiBC;CACF;6BAjZ0B,aAAa"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utility class providing type checking and assertion methods.
|
|
3
|
+
*/
|
|
4
|
+
export default class Valid {
|
|
5
|
+
/**
|
|
6
|
+
* Validates a value against a type. Uses Data.isType.
|
|
7
|
+
*
|
|
8
|
+
* @param {unknown} value - The value to validate
|
|
9
|
+
* @param {string} type - The expected type in the form of "object", "object[]", "object|object[]"
|
|
10
|
+
* @param {object} [options] - Additional options for validation.
|
|
11
|
+
*/
|
|
12
|
+
static type(value: unknown, type: string, options?: object): void;
|
|
13
|
+
/**
|
|
14
|
+
* Asserts a condition
|
|
15
|
+
*
|
|
16
|
+
* @param {boolean} condition - The condition to assert
|
|
17
|
+
* @param {string} message - The message to display if the condition is not
|
|
18
|
+
* met
|
|
19
|
+
* @param {number} [arg] - The argument to display if the condition is not
|
|
20
|
+
* met (optional)
|
|
21
|
+
*/
|
|
22
|
+
static assert(condition: boolean, message: string, arg?: number): void;
|
|
23
|
+
static "__#private@#restrictedProto": string[];
|
|
24
|
+
/**
|
|
25
|
+
* Protects against prototype pollution by checking keys for dangerous property names.
|
|
26
|
+
* Throws if any restricted prototype properties are found in the keys array.
|
|
27
|
+
*
|
|
28
|
+
* @param {Array<string>} keys - Array of property keys to validate
|
|
29
|
+
* @throws {Sass} If any key matches restricted prototype properties (__proto__, constructor, prototype)
|
|
30
|
+
*/
|
|
31
|
+
static prototypePollutionProtection(keys: Array<string>): void;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=Valid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Valid.d.ts","sourceRoot":"","sources":["../../lib/Valid.js"],"names":[],"mappings":"AAaA;;GAEG;AACH;IACE;;;;;;OAMG;IACH,mBAJW,OAAO,QACP,MAAM,YACN,MAAM,QAQhB;IAED;;;;;;;;OAQG;IACH,yBANW,OAAO,WACP,MAAM,QAEN,MAAM,QAmBhB;IAED,+CAAmE;IAEnE;;;;;;OAMG;IACH,0CAHW,KAAK,CAAC,MAAM,CAAC,QAYvB;CACF"}
|
package/src/lib/Action.js
DELETED
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import ActionBuilder from "./ActionBuilder.js"
|
|
2
|
-
import ActionRunner from "./ActionRunner.js"
|
|
3
|
-
import Data from "./Data.js"
|
|
4
|
-
import FileObject from "./FileObject.js"
|
|
5
|
-
import Hooks from "./Hooks.js"
|
|
6
|
-
import Sass from "./Sass.js"
|
|
7
|
-
import Terms from "./Terms.js"
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generic base class for managing actions with lifecycle hooks.
|
|
11
|
-
* Provides common functionality for action setup, execution, and cleanup.
|
|
12
|
-
* Designed to be extended by specific implementations.
|
|
13
|
-
*/
|
|
14
|
-
export default class Action {
|
|
15
|
-
#action = null
|
|
16
|
-
#hooks = null
|
|
17
|
-
#file = null
|
|
18
|
-
#variables = null
|
|
19
|
-
#runner = null
|
|
20
|
-
#id = null
|
|
21
|
-
#debug
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Creates a new BaseActionManager instance.
|
|
25
|
-
*
|
|
26
|
-
* @param {object} config - Configuration object
|
|
27
|
-
* @param {object} config.actionDefinition - Action definition containing action class and file info
|
|
28
|
-
* @param {object} [config.variables] - Variables to pass to action during setup
|
|
29
|
-
* @param {import('../types.js').DebugFunction} config.debug - The logger's debug function
|
|
30
|
-
*/
|
|
31
|
-
constructor({actionDefinition, variables, debug}) {
|
|
32
|
-
this.#id = Symbol(performance.now())
|
|
33
|
-
this.#variables = variables || {}
|
|
34
|
-
this.#debug = debug
|
|
35
|
-
|
|
36
|
-
const {action,file} = actionDefinition
|
|
37
|
-
this.#action = action
|
|
38
|
-
this.#file = file
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Gets the unique identifier for this action manager instance.
|
|
42
|
-
*
|
|
43
|
-
* @returns {symbol} Unique symbol identifier
|
|
44
|
-
*/
|
|
45
|
-
get id() {
|
|
46
|
-
return this.#id
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Gets the action class constructor.
|
|
51
|
-
*
|
|
52
|
-
* @returns {new () => object} Action class constructor
|
|
53
|
-
*/
|
|
54
|
-
get action() {
|
|
55
|
-
return this.#action
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Gets the current hook manager instance.
|
|
60
|
-
*
|
|
61
|
-
* @returns {Hooks|null} Hook manager instance or null if not set
|
|
62
|
-
*/
|
|
63
|
-
get hooks() {
|
|
64
|
-
return this.#hooks
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Sets the hook manager and attaches hooks to the action.
|
|
69
|
-
*
|
|
70
|
-
* @param {Hooks} hooks - Hook manager instance with hooks and on method.
|
|
71
|
-
* @returns {Promise<this>} Promise of this instance.
|
|
72
|
-
* @throws {Sass} If hook manager is already set.
|
|
73
|
-
*/
|
|
74
|
-
setHooks(hooks) {
|
|
75
|
-
if(this.#hooks)
|
|
76
|
-
throw Sass.new("Hook manager already set")
|
|
77
|
-
|
|
78
|
-
this.#hooks = hooks
|
|
79
|
-
|
|
80
|
-
return this
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// async callHook(kind, activity, action, context) {
|
|
84
|
-
// const hooks = this.#hooks
|
|
85
|
-
|
|
86
|
-
// }
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Gets the action metadata.
|
|
90
|
-
*
|
|
91
|
-
* @returns {object|undefined} Action metadata object
|
|
92
|
-
*/
|
|
93
|
-
get meta() {
|
|
94
|
-
return this.#action?.meta
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Gets the variables passed to the action.
|
|
99
|
-
*
|
|
100
|
-
* @returns {object} Variables object
|
|
101
|
-
*/
|
|
102
|
-
get variables() {
|
|
103
|
-
return this.#variables
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Gets the action runner instance.
|
|
108
|
-
*
|
|
109
|
-
* @returns {ActionRunner?} ActionRunner instance or null if not set up
|
|
110
|
-
*/
|
|
111
|
-
get runner() {
|
|
112
|
-
return this.#runner
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Gets the file information object.
|
|
117
|
-
*
|
|
118
|
-
* @returns {FileObject?} File information object
|
|
119
|
-
*/
|
|
120
|
-
get file() {
|
|
121
|
-
return this.#file
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Setup the action by creating and configuring the runner.
|
|
126
|
-
* This is the main public method to initialize the action for use.
|
|
127
|
-
*
|
|
128
|
-
* @returns {Promise<this>} Promise of this instance.
|
|
129
|
-
* @throws {Sass} If action setup fails
|
|
130
|
-
*/
|
|
131
|
-
async setupAction() {
|
|
132
|
-
this.#debug("Setting up action for %o on %o", 2, this.#action.meta?.kind, this.id)
|
|
133
|
-
|
|
134
|
-
await this.#setupHooks()
|
|
135
|
-
await this.#setupAction()
|
|
136
|
-
|
|
137
|
-
return this
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Setup the action instance and create the runner.
|
|
142
|
-
* Creates a new action instance, calls its setup method with an
|
|
143
|
-
* ActionBuilder, and creates an ActionRunner from the result.
|
|
144
|
-
*
|
|
145
|
-
* Can be overridden in subclasses to customize action setup.
|
|
146
|
-
*
|
|
147
|
-
* @returns {Promise<void>}
|
|
148
|
-
* @throws {Sass} If action setup method is not a function
|
|
149
|
-
* @protected
|
|
150
|
-
*/
|
|
151
|
-
async #setupAction() {
|
|
152
|
-
const actionInstance = new this.#action()
|
|
153
|
-
const setup = actionInstance?.setup
|
|
154
|
-
|
|
155
|
-
// Setup is required for actions.
|
|
156
|
-
if(Data.typeOf(setup) === "Function") {
|
|
157
|
-
const builder = new ActionBuilder(actionInstance)
|
|
158
|
-
const configuredBuilder = setup(builder)
|
|
159
|
-
const buildResult = configuredBuilder.build()
|
|
160
|
-
const runner = new ActionRunner({
|
|
161
|
-
action: buildResult.action,
|
|
162
|
-
build: buildResult.build
|
|
163
|
-
}, this.#hooks)
|
|
164
|
-
|
|
165
|
-
this.#runner = runner
|
|
166
|
-
} else {
|
|
167
|
-
throw Sass.new("Action setup must be a function.")
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Run the action with the provided input.
|
|
173
|
-
* The action must be set up via setupAction() before calling this method.
|
|
174
|
-
*
|
|
175
|
-
* @param {unknown} context - Input data to pass to the action runner
|
|
176
|
-
* @returns {Promise<unknown>} Result from the action execution
|
|
177
|
-
* @throws {Sass} If action is not set up
|
|
178
|
-
*/
|
|
179
|
-
async runAction(context) {
|
|
180
|
-
if(!this.#runner)
|
|
181
|
-
throw Sass.new("Action not set up. Call setupAction() first.")
|
|
182
|
-
|
|
183
|
-
return await this.#runner.run(context)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Cleanup the action and hooks.
|
|
188
|
-
* This should be called when the action is no longer needed to free
|
|
189
|
-
* resources.
|
|
190
|
-
*
|
|
191
|
-
* Calls cleanupHooks() and cleanupActionInstance() which can be overridden.
|
|
192
|
-
*
|
|
193
|
-
* @returns {Promise<this>} Promise of this instance.
|
|
194
|
-
*/
|
|
195
|
-
async cleanupAction() {
|
|
196
|
-
this.#debug("Cleaning up action for %o on %o", 2, this.#action.meta?.kind, this.id)
|
|
197
|
-
|
|
198
|
-
await this.#cleanupHooks()
|
|
199
|
-
await this.#cleanupAction()
|
|
200
|
-
|
|
201
|
-
return this
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Setup hooks if hook manager is present.
|
|
206
|
-
* Calls the hook manager's setup function with action context.
|
|
207
|
-
* Override in subclasses to customize hook setup.
|
|
208
|
-
*
|
|
209
|
-
* @returns {Promise<void>}
|
|
210
|
-
* @throws {Sass} If hook setup is not a function
|
|
211
|
-
* @private
|
|
212
|
-
*/
|
|
213
|
-
async #setupHooks() {
|
|
214
|
-
const setup = this.#hooks?.setup
|
|
215
|
-
const type = Data.typeOf(setup)
|
|
216
|
-
|
|
217
|
-
// No hooks attached.
|
|
218
|
-
if(type === "Null" || type === "Undefined")
|
|
219
|
-
return
|
|
220
|
-
|
|
221
|
-
if(type !== "Function")
|
|
222
|
-
throw Sass.new("Hook setup must be a function.")
|
|
223
|
-
|
|
224
|
-
await setup.call(
|
|
225
|
-
this.hooks.hooks, {
|
|
226
|
-
action: this.#action,
|
|
227
|
-
variables: this.#variables,
|
|
228
|
-
}
|
|
229
|
-
)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Cleanup hooks if hook manager is present.
|
|
234
|
-
* Calls the hook manager's cleanup function.
|
|
235
|
-
* Override in subclasses to customize hook cleanup.
|
|
236
|
-
*
|
|
237
|
-
* @returns {Promise<void>}
|
|
238
|
-
* @protected
|
|
239
|
-
*/
|
|
240
|
-
async #cleanupHooks() {
|
|
241
|
-
const cleanup = this.hooks?.cleanup
|
|
242
|
-
|
|
243
|
-
if(!cleanup)
|
|
244
|
-
return
|
|
245
|
-
|
|
246
|
-
await cleanup.call(this.hooks.hooks)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Cleanup the action instance.
|
|
251
|
-
* Calls the action's cleanup method if it exists.
|
|
252
|
-
* Override in subclasses to add custom cleanup logic.
|
|
253
|
-
*
|
|
254
|
-
* @returns {Promise<void>}
|
|
255
|
-
* @protected
|
|
256
|
-
*/
|
|
257
|
-
async #cleanupAction() {
|
|
258
|
-
const cleanup = this.#action?.cleanup
|
|
259
|
-
|
|
260
|
-
if(!cleanup)
|
|
261
|
-
return
|
|
262
|
-
|
|
263
|
-
await cleanup.call(this.#action)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Returns a string representation of this action manager.
|
|
268
|
-
*
|
|
269
|
-
* @returns {string} String representation with module and action info
|
|
270
|
-
*/
|
|
271
|
-
toString() {
|
|
272
|
-
return `${this.#file?.module || "UNDEFINED"} (${this.meta?.action || "UNDEFINED"})`
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Get contract/terms for this action (override in subclasses)
|
|
277
|
-
*
|
|
278
|
-
* @returns {Terms?} Contract terms or null if not implemented
|
|
279
|
-
*/
|
|
280
|
-
get terms() {
|
|
281
|
-
return null
|
|
282
|
-
}
|
|
283
|
-
}
|
package/src/lib/ActionBuilder.js
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import Valid from "./Valid.js"
|
|
2
|
-
|
|
3
|
-
/** @typedef {import("./ActionRunner.js").default} ActionRunner */
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Activity bit flags recognised by {@link ActionBuilder#act}. The flag decides
|
|
7
|
-
* how results are accumulated for each activity.
|
|
8
|
-
*
|
|
9
|
-
* @readonly
|
|
10
|
-
* @enum {number}
|
|
11
|
-
*/
|
|
12
|
-
export const ACTIVITY = Object.freeze({
|
|
13
|
-
ONCE: 1<<1,
|
|
14
|
-
MANY: 1<<2,
|
|
15
|
-
PARALLEL: 1<<3,
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Fluent builder for describing how an action should process the context that
|
|
20
|
-
* flows through the {@link ActionRunner}. Consumers register named activities,
|
|
21
|
-
* optional hook pairs, and nested parallel pipelines before handing the
|
|
22
|
-
* builder back to the runner for execution.
|
|
23
|
-
*
|
|
24
|
-
* Typical usage:
|
|
25
|
-
*
|
|
26
|
-
* ```js
|
|
27
|
-
* const pipeline = new ActionBuilder(myAction)
|
|
28
|
-
* .act("prepare", ACTIVITY.ONCE, ctx => ctx.initialise())
|
|
29
|
-
* .parallel(parallel => parallel
|
|
30
|
-
* .act("step", ACTIVITY.MANY, ctx => ctx.consume())
|
|
31
|
-
* )
|
|
32
|
-
* .act("finalise", ACTIVITY.ONCE, ctx => ctx.complete())
|
|
33
|
-
* .build()
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* @class ActionBuilder
|
|
37
|
-
*/
|
|
38
|
-
export default class ActionBuilder {
|
|
39
|
-
#action = null
|
|
40
|
-
#activities = new Map([])
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Creates a new ActionBuilder instance with the provided action callback.
|
|
44
|
-
*
|
|
45
|
-
* @param {(ctx: object) => void} action Base action invoked by the runner when a block
|
|
46
|
-
* satisfies the configured structure.
|
|
47
|
-
*/
|
|
48
|
-
constructor(action) {
|
|
49
|
-
this.#action = action
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Returns the underlying action that will receive the extracted context.
|
|
54
|
-
*
|
|
55
|
-
* @returns {(ctx: object) => void} The action callback function that processes the extracted context.
|
|
56
|
-
*/
|
|
57
|
-
get action() {
|
|
58
|
-
return this.#action
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Returns the registered activities keyed by their name.
|
|
63
|
-
*
|
|
64
|
-
* @returns {Map<string | symbol, {op: (context: object) => unknown, kind: number, hooks: {before: ((context: object) => void)|null, after: ((context: object) => void)|null}}>} Map of registered activities and their metadata.
|
|
65
|
-
*/
|
|
66
|
-
get activities() {
|
|
67
|
-
return this.#activities
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Registers a named activity that will run for each matching block.
|
|
72
|
-
*
|
|
73
|
-
* @param {string} name Unique activity identifier.
|
|
74
|
-
* @param {number} kind Activity accumulation strategy (see {@link ACTIVITY}).
|
|
75
|
-
* @param {(context: object) => unknown} op Work function executed with the runner context.
|
|
76
|
-
* @param {{before?: (context: object) => void, after?: (context: object) => void}} [hooks] Optional hooks to run before or after the activity operation.
|
|
77
|
-
* @returns {ActionBuilder} Builder instance for chaining.
|
|
78
|
-
*/
|
|
79
|
-
act(name, kind, op, hooks={}) {
|
|
80
|
-
this.#validActivityKind(kind)
|
|
81
|
-
this.#dupeActivityCheck(name)
|
|
82
|
-
|
|
83
|
-
hooks = this.#normalizeHooks(hooks)
|
|
84
|
-
|
|
85
|
-
this.#activities.set(name, {op, kind, hooks})
|
|
86
|
-
|
|
87
|
-
return this
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
#normalizeHooks({before=null, after=null}) {
|
|
91
|
-
return {before, after}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Defines a nested pipeline that will run with the {@link ACTIVITY} flag PARALLEL.
|
|
96
|
-
*
|
|
97
|
-
* The callback receives a fresh {@link ActionBuilder} scoped to the current
|
|
98
|
-
* action. The callback must return the configured builder so the runner can
|
|
99
|
-
* execute the nested pipeline.
|
|
100
|
-
*
|
|
101
|
-
* @param {(builder: ActionBuilder) => ActionBuilder} func Callback configuring a nested builder.
|
|
102
|
-
* @returns {ActionBuilder} Builder instance for chaining.
|
|
103
|
-
*/
|
|
104
|
-
parallel(func) {
|
|
105
|
-
const activityName = Symbol(performance.now())
|
|
106
|
-
|
|
107
|
-
this.#activities.set(activityName, {
|
|
108
|
-
op: func.call(this.action, new ActionBuilder(this.action)),
|
|
109
|
-
kind: ACTIVITY.PARALLEL
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
return this
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
#validActivityKind(kind) {
|
|
116
|
-
Valid.assert(
|
|
117
|
-
Object.values(ACTIVITY).includes(kind),
|
|
118
|
-
"Invalid activity kind."
|
|
119
|
-
)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Validates that an activity name has not been reused.
|
|
124
|
-
*
|
|
125
|
-
* @private
|
|
126
|
-
* @param {string|symbol} name Activity identifier.
|
|
127
|
-
*/
|
|
128
|
-
#dupeActivityCheck(name) {
|
|
129
|
-
Valid.assert(
|
|
130
|
-
!this.#activities.has(name),
|
|
131
|
-
`Activity '${String(name)}' has already been registered.`
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Finalises the builder and returns a payload that can be consumed by the
|
|
137
|
-
* runner.
|
|
138
|
-
*
|
|
139
|
-
* @returns {{action: (context: object) => unknown, build: ActionBuilder}} Payload consumed by the {@link ActionRunner} constructor.
|
|
140
|
-
*/
|
|
141
|
-
build() {
|
|
142
|
-
return {action: this.#action, build: this}
|
|
143
|
-
}
|
|
144
|
-
}
|