@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.
Files changed (66) hide show
  1. package/package.json +8 -8
  2. package/src/lib/Collection.js +132 -17
  3. package/src/lib/Contract.js +1 -1
  4. package/src/lib/Data.js +27 -18
  5. package/src/lib/DirectoryObject.js +1 -1
  6. package/src/lib/FS.js +10 -0
  7. package/src/lib/Glog.js +27 -10
  8. package/src/lib/Logger.js +3 -0
  9. package/src/lib/Sass.js +6 -1
  10. package/src/lib/Tantrum.js +43 -0
  11. package/src/lib/TypeSpec.js +11 -7
  12. package/src/lib/Util.js +82 -0
  13. package/src/lib/Valid.js +24 -6
  14. package/src/types/Collection.d.ts +6 -1
  15. package/src/types/Contract.d.ts +27 -27
  16. package/src/types/Data.d.ts +23 -23
  17. package/src/types/FS.d.ts +3 -3
  18. package/src/types/Glog.d.ts +302 -49
  19. package/src/types/Sass.d.ts +1 -1
  20. package/src/types/Schemer.d.ts +29 -29
  21. package/src/types/Tantrum.d.ts +10 -10
  22. package/src/types/Term.d.ts +1 -1
  23. package/src/types/Terms.d.ts +21 -21
  24. package/src/types/Type.d.ts +1 -1
  25. package/src/types/Util.d.ts +20 -2
  26. package/src/types/index.d.ts +17 -23
  27. package/src/types/index.d.ts.map +1 -0
  28. package/src/types/lib/Cache.d.ts +28 -0
  29. package/src/types/lib/Cache.d.ts.map +1 -0
  30. package/src/types/lib/Collection.d.ts +246 -0
  31. package/src/types/lib/Collection.d.ts.map +1 -0
  32. package/src/types/lib/Contract.d.ts +72 -0
  33. package/src/types/lib/Contract.d.ts.map +1 -0
  34. package/src/types/lib/Data.d.ts +189 -0
  35. package/src/types/lib/Data.d.ts.map +1 -0
  36. package/src/types/lib/DirectoryObject.d.ts +148 -0
  37. package/src/types/lib/DirectoryObject.d.ts.map +1 -0
  38. package/src/types/lib/FS.d.ts +70 -0
  39. package/src/types/lib/FS.d.ts.map +1 -0
  40. package/src/types/lib/FileObject.d.ts +189 -0
  41. package/src/types/lib/FileObject.d.ts.map +1 -0
  42. package/src/types/lib/Glog.d.ts +113 -0
  43. package/src/types/lib/Glog.d.ts.map +1 -0
  44. package/src/types/lib/Logger.d.ts +46 -0
  45. package/src/types/lib/Logger.d.ts.map +1 -0
  46. package/src/types/lib/Sass.d.ts +62 -0
  47. package/src/types/lib/Sass.d.ts.map +1 -0
  48. package/src/types/lib/Schemer.d.ts +23 -0
  49. package/src/types/lib/Schemer.d.ts.map +1 -0
  50. package/src/types/lib/Tantrum.d.ts +50 -0
  51. package/src/types/lib/Tantrum.d.ts.map +1 -0
  52. package/src/types/lib/Term.d.ts +103 -0
  53. package/src/types/lib/Term.d.ts.map +1 -0
  54. package/src/types/lib/Terms.d.ts +24 -0
  55. package/src/types/lib/Terms.d.ts.map +1 -0
  56. package/src/types/lib/TypeSpec.d.ts +92 -0
  57. package/src/types/lib/TypeSpec.d.ts.map +1 -0
  58. package/src/types/lib/Util.d.ts +197 -0
  59. package/src/types/lib/Util.d.ts.map +1 -0
  60. package/src/types/lib/Valid.d.ts +33 -0
  61. package/src/types/lib/Valid.d.ts.map +1 -0
  62. package/src/lib/Action.js +0 -283
  63. package/src/lib/ActionBuilder.js +0 -144
  64. package/src/lib/ActionRunner.js +0 -79
  65. package/src/lib/Hooks.js +0 -194
  66. package/src/lib/Piper.js +0 -155
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gesslar/toolkit",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Get in, bitches, we're going toolkitting.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -20,12 +20,12 @@
20
20
  "node": ">=20"
21
21
  },
22
22
  "scripts": {
23
+ "types:build": "tsc -p tsconfig.types.json",
23
24
  "lint": "eslint src/",
24
25
  "lint:fix": "eslint src/ --fix",
25
26
  "submit": "npm publish --access public",
26
27
  "update": "npx npm-check-updates -u && npm install",
27
28
  "test": "node --test tests/unit/*.test.js",
28
- "test:unit": "node --test tests/unit/*.test.js",
29
29
  "pr": "gt submit --publish --restack --ai"
30
30
  },
31
31
  "repository": {
@@ -57,11 +57,11 @@
57
57
  "yaml": "^2.8.1"
58
58
  },
59
59
  "devDependencies": {
60
- "@stylistic/eslint-plugin": "^5.4.0",
61
- "@types/node": "^24.6.2",
62
- "@typescript-eslint/eslint-plugin": "^8.45.0",
63
- "@typescript-eslint/parser": "^8.45.0",
64
- "eslint": "^9.36.0",
65
- "eslint-plugin-jsdoc": "^60.7.1"
60
+ "@stylistic/eslint-plugin": "^5.5.0",
61
+ "@types/node": "^24.9.1",
62
+ "@typescript-eslint/eslint-plugin": "^8.46.2",
63
+ "@typescript-eslint/parser": "^8.46.2",
64
+ "eslint": "^9.38.0",
65
+ "eslint-plugin-jsdoc": "^61.1.8"
66
66
  }
67
67
  }
@@ -1,9 +1,31 @@
1
+ /**
2
+ * @file Collection.js
3
+ *
4
+ * Provides utility functions for working with collections (arrays, objects, sets, maps).
5
+ * Includes methods for iteration, transformation, validation, and manipulation of
6
+ * various collection types.
7
+ */
8
+
1
9
  import Data from "./Data.js"
2
10
  import Valid from "./Valid.js"
3
11
  import Sass from "./Sass.js"
4
12
  import Util from "./Util.js"
5
13
 
14
+ /**
15
+ * Utility class for collection operations.
16
+ * Provides static methods for working with arrays, objects, sets, and maps.
17
+ */
6
18
  export default class Collection {
19
+ /**
20
+ * Evaluates an array with a predicate function, optionally in reverse order.
21
+ * Returns the first truthy result from the predicate.
22
+ *
23
+ * @param {Array<unknown>} collection - The array to evaluate
24
+ * @param {(value: unknown, index: number, array: Array<unknown>) => unknown} predicate - Function to evaluate each element
25
+ * @param {boolean} [forward] - Whether to iterate forward (true) or backward (false). Defaults to true
26
+ * @returns {unknown|undefined} The first truthy result from the predicate, or undefined
27
+ * @throws {Sass} If collection is not an array or predicate is not a function
28
+ */
7
29
  static evalArray(collection, predicate, forward=true) {
8
30
  const req = "Array"
9
31
  const type = Data.typeOf(collection)
@@ -24,6 +46,15 @@ export default class Collection {
24
46
  }
25
47
  }
26
48
 
49
+ /**
50
+ * Evaluates an object with a predicate function.
51
+ * Returns the first truthy result from the predicate.
52
+ *
53
+ * @param {object} collection - The object to evaluate
54
+ * @param {(value: unknown, key: string, object: object) => unknown} predicate - Function to evaluate each property
55
+ * @returns {unknown|undefined} The first truthy result from the predicate, or undefined
56
+ * @throws {Sass} If collection is not an object or predicate is not a function
57
+ */
27
58
  static evalObject(collection, predicate) {
28
59
  const req = "Object"
29
60
  const type = Data.typeOf(collection)
@@ -42,6 +73,15 @@ export default class Collection {
42
73
  }
43
74
  }
44
75
 
76
+ /**
77
+ * Evaluates a Set with a predicate function.
78
+ * Returns the first truthy result from the predicate.
79
+ *
80
+ * @param {Set<unknown>} collection - The Set to evaluate
81
+ * @param {(value: unknown, set: Set<unknown>) => unknown} predicate - Function to evaluate each element
82
+ * @returns {unknown|undefined} The first truthy result from the predicate, or undefined
83
+ * @throws {Sass} If collection is not a Set or predicate is not a function
84
+ */
45
85
  static evalSet(collection, predicate) {
46
86
  const req = "Set"
47
87
  const type = Data.typeOf(collection)
@@ -60,6 +100,16 @@ export default class Collection {
60
100
  }
61
101
  }
62
102
 
103
+ /**
104
+ * Evaluates a Map with a predicate function, optionally in reverse order.
105
+ * Returns the first truthy result from the predicate.
106
+ *
107
+ * @param {Map<unknown, unknown>} collection - The Map to evaluate
108
+ * @param {(value: unknown, key: unknown, map: Map<unknown, unknown>) => unknown} predicate - Function to evaluate each entry
109
+ * @param {boolean} [forward] - Whether to iterate forward (true) or backward (false). Defaults to true
110
+ * @returns {unknown|undefined} The first truthy result from the predicate, or undefined
111
+ * @throws {Sass} If collection is not a Map or predicate is not a function
112
+ */
63
113
  static evalMap(collection, predicate, forward=true) {
64
114
  const req = "Map"
65
115
  const type = Data.typeOf(collection)
@@ -80,12 +130,27 @@ export default class Collection {
80
130
  }
81
131
  }
82
132
 
133
+ /**
134
+ * Zips two arrays together into an array of pairs.
135
+ * The resulting array length equals the shorter input array.
136
+ *
137
+ * @param {Array<unknown>} array1 - The first array
138
+ * @param {Array<unknown>} array2 - The second array
139
+ * @returns {Array<[unknown, unknown]>} Array of paired elements
140
+ */
83
141
  static zip(array1, array2) {
84
142
  const minLength = Math.min(array1.length, array2.length)
85
143
 
86
144
  return Array.from({length: minLength}, (_, i) => [array1[i], array2[i]])
87
145
  }
88
146
 
147
+ /**
148
+ * Unzips an array of pairs into separate arrays.
149
+ * Transposes a 2D array structure.
150
+ *
151
+ * @param {Array<Array<unknown>>} array - Array of arrays to unzip
152
+ * @returns {Array<Array<unknown>>} Array of unzipped arrays, or empty array for invalid input
153
+ */
89
154
  static unzip(array) {
90
155
  if(!Array.isArray(array) || array.length === 0) {
91
156
  return [] // Handle empty or invalid input
@@ -108,6 +173,15 @@ export default class Collection {
108
173
  return unzipped
109
174
  }
110
175
 
176
+ /**
177
+ * Maps an array using an async function, processing items sequentially.
178
+ * Unlike Promise.all(array.map()), this processes one item at a time.
179
+ *
180
+ * @param {Array<unknown>} array - The array to map
181
+ * @param {(item: unknown) => Promise<unknown>} asyncFn - Async function to apply to each element
182
+ * @returns {Promise<Array<unknown>>} Promise resolving to the mapped array
183
+ * @throws {Sass} If array is not an Array or asyncFn is not a function
184
+ */
111
185
  static async asyncMap(array, asyncFn) {
112
186
  const req = "Array"
113
187
  const type = Data.typeOf(array)
@@ -128,9 +202,8 @@ export default class Collection {
128
202
  /**
129
203
  * Checks if all elements in an array are of a specified type
130
204
  *
131
- * @param {Array} arr - The array to check
132
- * @param {string} type - The type to check for (optional, defaults to the
133
- * type of the first element)
205
+ * @param {Array<unknown>} arr - The array to check
206
+ * @param {string} [type] - The type to check for (optional, defaults to the type of the first element)
134
207
  * @returns {boolean} Whether all elements are of the specified type
135
208
  */
136
209
  static isArrayUniform(arr, type) {
@@ -155,8 +228,8 @@ export default class Collection {
155
228
  /**
156
229
  * Checks if an array is unique
157
230
  *
158
- * @param {Array} arr - The array of which to remove duplicates
159
- * @returns {Array} The unique elements of the array
231
+ * @param {Array<unknown>} arr - The array of which to remove duplicates
232
+ * @returns {Array<unknown>} The unique elements of the array
160
233
  */
161
234
  static isArrayUnique(arr) {
162
235
  const req = "Array"
@@ -170,9 +243,9 @@ export default class Collection {
170
243
  /**
171
244
  * Returns the intersection of two arrays.
172
245
  *
173
- * @param {Array} arr1 - The first array.
174
- * @param {Array} arr2 - The second array.
175
- * @returns {Array} The intersection of the two arrays.
246
+ * @param {Array<unknown>} arr1 - The first array.
247
+ * @param {Array<unknown>} arr2 - The second array.
248
+ * @returns {Array<unknown>} The intersection of the two arrays.
176
249
  */
177
250
  static intersection(arr1, arr2) {
178
251
  const req = "Array"
@@ -198,8 +271,8 @@ export default class Collection {
198
271
  * Collection.intersects([1, 2, 3], [3, 4, 5]) // returns true
199
272
  * Collection.intersects(["a", "b"], ["c", "d"]) // returns false
200
273
  *
201
- * @param {Array} arr1 - The first array to check for intersection.
202
- * @param {Array} arr2 - The second array to check for intersection.
274
+ * @param {Array<unknown>} arr1 - The first array to check for intersection.
275
+ * @param {Array<unknown>} arr2 - The second array to check for intersection.
203
276
  * @returns {boolean} True if any element is shared between the arrays, false otherwise.
204
277
  */
205
278
  static intersects(arr1, arr2) {
@@ -219,11 +292,11 @@ export default class Collection {
219
292
  * Pads an array to a specified length with a value. This operation
220
293
  * occurs in-place.
221
294
  *
222
- * @param {Array} arr - The array to pad.
295
+ * @param {Array<unknown>} arr - The array to pad.
223
296
  * @param {number} length - The length to pad the array to.
224
297
  * @param {unknown} value - The value to pad the array with.
225
- * @param {number} position - The position to pad the array at.
226
- * @returns {Array} The padded array.
298
+ * @param {number} [position] - The position to pad the array at. Defaults to 0
299
+ * @returns {Array<unknown>} The padded array.
227
300
  */
228
301
  static arrayPad(arr, length, value, position = 0) {
229
302
  const req = "Array"
@@ -254,9 +327,9 @@ export default class Collection {
254
327
  * Filters an array asynchronously using a predicate function.
255
328
  * Applies the predicate to all items in parallel and returns filtered results.
256
329
  *
257
- * @param {Array} arr - The array to filter
258
- * @param {function(unknown): Promise<boolean>} predicate - Async predicate function that returns a promise resolving to boolean
259
- * @returns {Promise<Array>} Promise resolving to the filtered array
330
+ * @param {Array<unknown>} arr - The array to filter
331
+ * @param {(value: unknown, index: number, array: Array<unknown>) => Promise<boolean>} predicate - Async predicate function that returns a promise resolving to boolean
332
+ * @returns {Promise<Array<unknown>>} Promise resolving to the filtered array
260
333
  */
261
334
  static async asyncFilter(arr, predicate) {
262
335
  const req = "Array"
@@ -468,7 +541,7 @@ export default class Collection {
468
541
 
469
542
  if(
470
543
  !Data.isType(spec, "Array", {allowEmpty: false}) &&
471
- !Data.isType(spec, "function")
544
+ !Data.isType(spec, "Function")
472
545
  )
473
546
  throw Sass.new("Spec must be an array or a function.")
474
547
 
@@ -498,6 +571,15 @@ export default class Collection {
498
571
  return result
499
572
  }
500
573
 
574
+ /**
575
+ * Trims falsy values from both ends of an array (in-place).
576
+ * Optionally preserves specific falsy values.
577
+ *
578
+ * @param {Array<unknown>} arr - The array to trim
579
+ * @param {Array<unknown>} [except] - Values to preserve even if falsy. Defaults to empty array
580
+ * @returns {Array<unknown>} The trimmed array (same reference, modified in-place)
581
+ * @throws {Sass} If arr is not an Array or except is not an Array
582
+ */
501
583
  static trimArray(arr, except=[]) {
502
584
  Valid.type(arr, "Array")
503
585
  Valid.type(except, "Array")
@@ -508,6 +590,15 @@ export default class Collection {
508
590
  return arr
509
591
  }
510
592
 
593
+ /**
594
+ * Trims falsy values from the right end of an array (in-place).
595
+ * Optionally preserves specific falsy values.
596
+ *
597
+ * @param {Array<unknown>} arr - The array to trim
598
+ * @param {Array<unknown>} [except] - Values to preserve even if falsy. Defaults to empty array
599
+ * @returns {Array<unknown>} The trimmed array (same reference, modified in-place)
600
+ * @throws {Sass} If arr is not an Array or except is not an Array
601
+ */
511
602
  static trimArrayRight(arr, except=[]) {
512
603
  Valid.type(arr, "Array")
513
604
  Valid.type(except, "Array")
@@ -519,6 +610,15 @@ export default class Collection {
519
610
  return arr
520
611
  }
521
612
 
613
+ /**
614
+ * Trims falsy values from the left end of an array (in-place).
615
+ * Optionally preserves specific falsy values.
616
+ *
617
+ * @param {Array<unknown>} arr - The array to trim
618
+ * @param {Array<unknown>} [except] - Values to preserve even if falsy. Defaults to empty array
619
+ * @returns {Array<unknown>} The trimmed array (same reference, modified in-place)
620
+ * @throws {Sass} If arr is not an Array or except is not an Array
621
+ */
522
622
  static trimArrayLeft(arr, except=[]) {
523
623
  Valid.type(arr, "Array")
524
624
  Valid.type(except, "Array")
@@ -535,6 +635,14 @@ export default class Collection {
535
635
  return arr
536
636
  }
537
637
 
638
+ /**
639
+ * Transposes an array of objects into an object of arrays.
640
+ * Collects values for each key across all objects into arrays.
641
+ *
642
+ * @param {Array<object>} objects - Array of plain objects to transpose
643
+ * @returns {object} Object with keys from input objects, values as arrays
644
+ * @throws {Sass} If objects is not an Array or contains non-plain objects
645
+ */
538
646
  static transposeObjects(objects) {
539
647
  const req = "Array"
540
648
  const type = Data.typeOf(objects)
@@ -560,6 +668,13 @@ export default class Collection {
560
668
  }, {})
561
669
  }
562
670
 
671
+ /**
672
+ * Flattens an array (or nested array) of objects and transposes them.
673
+ * Combines flat() and transposeObjects() operations.
674
+ *
675
+ * @param {Array<object>|Array<Array<object>>} input - Array or nested array of objects
676
+ * @returns {object} Transposed object with arrays of values
677
+ */
563
678
  static flattenObjectArray(input) {
564
679
  const flattened = Array.isArray(input) ? input.flat() : input
565
680
 
@@ -156,7 +156,7 @@ export default class Contract {
156
156
  *
157
157
  * @param {object} providerTerms - Terms offered by provider
158
158
  * @param {object} consumerTerms - Terms expected by consumer
159
- * @param {Array} stack - Stack trace for nested validation
159
+ * @param {Array<string>} stack - Stack trace for nested validation
160
160
  * @returns {object} Result with status and errors
161
161
  * @private
162
162
  */
package/src/lib/Data.js CHANGED
@@ -17,17 +17,18 @@ export default class Data {
17
17
  */
18
18
  static primitives = Object.freeze([
19
19
  // Primitives
20
- "Undefined",
21
- "Null",
20
+ "Bigint",
22
21
  "Boolean",
22
+ "Class",
23
+ "Null",
23
24
  "Number",
24
- "Bigint",
25
25
  "String",
26
26
  "Symbol",
27
+ "Undefined",
27
28
 
28
29
  // Object Categories from typeof
29
- "Object",
30
30
  "Function",
31
+ "Object",
31
32
  ])
32
33
 
33
34
  /**
@@ -38,21 +39,21 @@ export default class Data {
38
39
  */
39
40
  static constructors = Object.freeze([
40
41
  // Object Constructors
41
- "Object",
42
42
  "Array",
43
- "Function",
44
43
  "Date",
45
- "RegExp",
46
44
  "Error",
45
+ "Float32Array",
46
+ "Float64Array",
47
+ "Function",
48
+ "Int8Array",
47
49
  "Map",
50
+ "Object",
51
+ "Promise",
52
+ "RegExp",
48
53
  "Set",
54
+ "Uint8Array",
49
55
  "WeakMap",
50
56
  "WeakSet",
51
- "Promise",
52
- "Int8Array",
53
- "Uint8Array",
54
- "Float32Array",
55
- "Float64Array",
56
57
  ])
57
58
 
58
59
  /**
@@ -123,7 +124,7 @@ export default class Data {
123
124
  ? type
124
125
  : Data.newTypeSpec(type, options)
125
126
 
126
- return typeSpec.match(value, options)
127
+ return typeSpec.matches(value, options)
127
128
  }
128
129
 
129
130
  /**
@@ -134,9 +135,8 @@ export default class Data {
134
135
  */
135
136
  static isValidType(type) {
136
137
  // Allow built-in types
137
- if(Data.dataTypes.includes(type)) {
138
+ if(Data.dataTypes.includes(type))
138
139
  return true
139
- }
140
140
 
141
141
  // Allow custom classes (PascalCase starting with capital letter)
142
142
  return /^[A-Z][a-zA-Z0-9]*$/.test(type)
@@ -155,6 +155,15 @@ export default class Data {
155
155
  if(!Data.isValidType(type))
156
156
  return false
157
157
 
158
+ // We gotta do classes up front. Ugh.
159
+ if(/^[Cc]lass$/.test(type)) {
160
+ if(typeof value === "function" &&
161
+ value.prototype &&
162
+ value.prototype.constructor === value)
163
+
164
+ return true
165
+ }
166
+
158
167
  const valueType = Data.typeOf(value)
159
168
 
160
169
  // Special cases that need extra validation
@@ -327,9 +336,9 @@ export default class Data {
327
336
  * Filters an array asynchronously using a predicate function.
328
337
  * Applies the predicate to all items in parallel and returns filtered results.
329
338
  *
330
- * @param {Array} arr - The array to filter
331
- * @param {function(unknown): Promise<boolean>} predicate - Async predicate function that returns a promise resolving to boolean
332
- * @returns {Promise<Array>} Promise resolving to the filtered array
339
+ * @param {Array<unknown>} arr - The array to filter
340
+ * @param {(value: unknown) => Promise<boolean>} predicate - Async predicate function that returns a promise resolving to boolean
341
+ * @returns {Promise<Array<unknown>>} Promise resolving to the filtered array
333
342
  */
334
343
  static async asyncFilter(arr, predicate) {
335
344
  const results = await Promise.all(arr.map(predicate))
@@ -191,7 +191,7 @@ export default class DirectoryObject extends FS {
191
191
  /**
192
192
  * Returns the directory path split into segments.
193
193
  *
194
- * @returns {string[]} Array of path segments
194
+ * @returns {Array<string>} Array of path segments
195
195
  * @example
196
196
  * const dir = new DirectoryObject('/path/to/directory')
197
197
  * console.log(dir.trail) // ['', 'path', 'to', 'directory']
package/src/lib/FS.js CHANGED
@@ -1,3 +1,10 @@
1
+ /**
2
+ * @file FS.js
3
+ *
4
+ * File system utilities for path manipulation, file discovery, and path resolution.
5
+ * Provides glob-based file search, URI conversion, and intelligent path merging.
6
+ */
7
+
1
8
  import {globby} from "globby"
2
9
  import path from "node:path"
3
10
  import url from "node:url"
@@ -14,6 +21,9 @@ const fdType = Object.freeze(
14
21
  await Collection.allocateObject(upperFdTypes, fdTypes)
15
22
  )
16
23
 
24
+ /**
25
+ * File system utility class for path operations and file discovery.
26
+ */
17
27
  export default class FS {
18
28
  static fdTypes = fdTypes
19
29
  static upperFdTypes = upperFdTypes
package/src/lib/Glog.js CHANGED
@@ -1,11 +1,6 @@
1
- import c from "@gesslar/colours"
2
-
3
- import Data from "./Data.js"
4
- import Term from "./Term.js"
5
- import Util from "./Util.js"
6
- // ErrorStackParser will be dynamically imported when needed
7
-
8
1
  /**
2
+ * @file Glog.js
3
+ *
9
4
  * Enhanced Global logging utility that combines simple logging with advanced Logger features.
10
5
  *
11
6
  * Can be used in multiple ways:
@@ -16,6 +11,13 @@ import Util from "./Util.js"
16
11
  * 5. Traditional logger: logger.debug("message", level)
17
12
  */
18
13
 
14
+ import c from "@gesslar/colours"
15
+
16
+ import Data from "./Data.js"
17
+ import Term from "./Term.js"
18
+ import Util from "./Util.js"
19
+ // ErrorStackParser will be dynamically imported when needed
20
+
19
21
  // Enhanced color system using @gesslar/colours
20
22
  export const loggerColours = {
21
23
  debug: [
@@ -238,10 +240,24 @@ class Glog {
238
240
  }
239
241
 
240
242
  // Traditional logger methods
241
- debug(message, level = 0, ...arg) {
243
+ /**
244
+ * Log a debug message with specified verbosity level.
245
+ * Level 0 means debug OFF - use levels 1-4 for actual debug output.
246
+ * Debug messages only show when logLevel > 0.
247
+ *
248
+ * @param {string} message - Debug message to log
249
+ * @param {number} level - Debug verbosity level (1-4, default: 1)
250
+ * @param {...unknown} arg - Additional arguments to log
251
+ * @throws {Error} If level < 1 (level 0 = debug OFF)
252
+ */
253
+ debug(message, level = 1, ...arg) {
254
+ if(level < 1) {
255
+ throw new Error("Debug level must be >= 1 (level 0 = debug OFF)")
256
+ }
257
+
242
258
  const currentLevel = this.#logLevel || Glog.logLevel
243
259
 
244
- if(level <= currentLevel) {
260
+ if(currentLevel > 0 && level <= currentLevel) {
245
261
  Term.debug(this.#compose("debug", message, level), ...arg)
246
262
  }
247
263
  }
@@ -370,10 +386,11 @@ export default new Proxy(Glog, {
370
386
  return new target(...argumentsList)
371
387
  },
372
388
  get(target, prop) {
389
+ // Hide execute method from public API
373
390
  if(prop === "execute") {
374
391
  return undefined
375
392
  }
376
393
 
377
- return target[prop]
394
+ return Reflect.get(target, prop)
378
395
  }
379
396
  })
package/src/lib/Logger.js CHANGED
@@ -180,3 +180,6 @@ export default class Logger {
180
180
  this.vscodeError?.(JSON.stringify(message))
181
181
  }
182
182
  }
183
+
184
+ // NOTE: This is an artifact file kept for reference during Glog development.
185
+ // Not exported from toolkit. Has broken imports to ./Core.js (actions package).
package/src/lib/Sass.js CHANGED
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import Term from "./Term.js"
15
+ import Tantrum from "./Tantrum.js"
15
16
 
16
17
  /**
17
18
  * Custom error class for toolkit errors.
@@ -149,15 +150,19 @@ export default class Sass extends Error {
149
150
  * other errors. Otherwise creates a new Sass instance.
150
151
  *
151
152
  * @param {string} message - The error message
152
- * @param {Error|Sass} [error] - Optional existing error to wrap or enhance
153
+ * @param {Error|Sass|Tantrum} [error] - Optional existing error to wrap or enhance
153
154
  * @returns {Sass} New or enhanced Sass instance
154
155
  */
155
156
  static new(message, error) {
156
157
  if(error) {
158
+ if(error instanceof Tantrum)
159
+ return Tantrum.new(message, error)
160
+
157
161
  return error instanceof Sass
158
162
  ? error.addTrace(message)
159
163
  : Sass.from(error, message)
160
164
  } else {
165
+
161
166
  return new Sass(message)
162
167
  }
163
168
  }
@@ -17,6 +17,8 @@ import Term from "./Term.js"
17
17
  * Automatically wraps plain errors in Sass instances for consistent reporting.
18
18
  */
19
19
  export default class Tantrum extends AggregateError {
20
+ #trace = []
21
+
20
22
  /**
21
23
  * Creates a new Tantrum instance.
22
24
  *
@@ -38,6 +40,41 @@ export default class Tantrum extends AggregateError {
38
40
  super(wrappedErrors, message)
39
41
  this.name = "Tantrum"
40
42
  }
43
+
44
+ /**
45
+ * Adds a trace message and returns this instance for chaining.
46
+ *
47
+ * @param {string} message - The trace message to add
48
+ * @param {Error|Sass} [_error] - Optional error (currently unused, reserved for future use)
49
+ * @returns {this} This Tantrum instance for method chaining
50
+ */
51
+ addTrace(message, _error) {
52
+ if(typeof message !== "string")
53
+ throw Sass.new(`Tantrum.addTrace expected string, got ${JSON.stringify(message)}`)
54
+
55
+ this.trace = message
56
+
57
+ return this
58
+ }
59
+
60
+ /**
61
+ * Gets the error trace array.
62
+ *
63
+ * @returns {Array<string>} Array of trace messages
64
+ */
65
+ get trace() {
66
+ return this.#trace
67
+ }
68
+
69
+ /**
70
+ * Adds a message to the beginning of the trace array.
71
+ *
72
+ * @param {string} message - The trace message to add
73
+ */
74
+ set trace(message) {
75
+ this.#trace.unshift(message)
76
+ }
77
+
41
78
  /**
42
79
  * Reports all aggregated errors to the terminal with formatted output.
43
80
  *
@@ -49,6 +86,9 @@ export default class Tantrum extends AggregateError {
49
86
  this.message
50
87
  )
51
88
 
89
+ if(this.trace)
90
+ Term.error(this.trace.join("\n"))
91
+
52
92
  Term.error()
53
93
 
54
94
  this.errors.forEach(error => {
@@ -64,6 +104,9 @@ export default class Tantrum extends AggregateError {
64
104
  * @returns {Tantrum} New Tantrum instance
65
105
  */
66
106
  static new(message, errors = []) {
107
+ if(errors instanceof Tantrum)
108
+ return errors.addTrace(message)
109
+
67
110
  return new Tantrum(message, errors)
68
111
  }
69
112
  }
@@ -138,23 +138,27 @@ export default class TypeSpec {
138
138
  * @param {boolean} options.allowEmpty - Whether empty values are allowed
139
139
  * @returns {boolean} True if the value matches any type specification
140
140
  */
141
+ matches(value, options) {
142
+ return this.match(value,options).length > 0
143
+ }
144
+
141
145
  match(value, options) {
142
146
  const allowEmpty = options?.allowEmpty ?? true
143
147
  const empty = Data.isEmpty(value)
144
148
 
145
- // If we have a list of types, because the string was validly parsed,
146
- // we need to ensure that all of the types that were parsed are valid types
147
- // in JavaScript.
149
+ // If we have a list of types, because the string was validly parsed, we
150
+ // need to ensure that all of the types that were parsed are valid types in
151
+ // JavaScript.
148
152
  if(this.length && !this.every(t => Data.isValidType(t.typeName)))
149
- return false
153
+ return []
150
154
 
151
155
  // Now, let's do some checking with the types, respecting the array flag
152
156
  // with the value
153
157
  const valueType = Data.typeOf(value)
154
158
  const isArray = valueType === "Array"
155
159
 
156
- // We need to ensure that we match the type and the consistency of the types
157
- // in an array, if it is an array and an array is allowed.
160
+ // We need to ensure that we match the type and the consistency of the
161
+ // types in an array, if it is an array and an array is allowed.
158
162
  const matchingTypeSpec = this.filter(spec => {
159
163
  const {typeName: allowedType, array: allowedArray} = spec
160
164
 
@@ -187,7 +191,7 @@ export default class TypeSpec {
187
191
  return false
188
192
  })
189
193
 
190
- return matchingTypeSpec.length > 0
194
+ return matchingTypeSpec
191
195
  }
192
196
 
193
197
  /**