tyneq 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +319 -0
- package/dist/Lazy.cjs +762 -0
- package/dist/Lazy.cjs.map +1 -0
- package/dist/Lazy.js +691 -0
- package/dist/Lazy.js.map +1 -0
- package/dist/TyneqCachedTerminalOperator.cjs +4950 -0
- package/dist/TyneqCachedTerminalOperator.cjs.map +1 -0
- package/dist/TyneqCachedTerminalOperator.d.cts +724 -0
- package/dist/TyneqCachedTerminalOperator.d.cts.map +1 -0
- package/dist/TyneqCachedTerminalOperator.d.ts +724 -0
- package/dist/TyneqCachedTerminalOperator.d.ts.map +1 -0
- package/dist/TyneqCachedTerminalOperator.js +4741 -0
- package/dist/TyneqCachedTerminalOperator.js.map +1 -0
- package/dist/ValidationBuilder.cjs +80 -0
- package/dist/ValidationBuilder.cjs.map +1 -0
- package/dist/ValidationBuilder.d.cts +319 -0
- package/dist/ValidationBuilder.d.cts.map +1 -0
- package/dist/ValidationBuilder.d.ts +319 -0
- package/dist/ValidationBuilder.d.ts.map +1 -0
- package/dist/ValidationBuilder.js +69 -0
- package/dist/ValidationBuilder.js.map +1 -0
- package/dist/core.d.cts +1393 -0
- package/dist/core.d.cts.map +1 -0
- package/dist/core.d.ts +1393 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/index.cjs +863 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1038 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +1038 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +809 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/index.cjs +24 -0
- package/dist/plugin/index.d.cts +89 -0
- package/dist/plugin/index.d.cts.map +1 -0
- package/dist/plugin/index.d.ts +89 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +2 -0
- package/dist/utility/index.cjs +9 -0
- package/dist/utility/index.d.cts +2 -0
- package/dist/utility/index.d.ts +2 -0
- package/dist/utility/index.js +3 -0
- package/package.json +96 -0
package/dist/Lazy.js
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
//#region src/utility/nameof.ts
|
|
2
|
+
/**
|
|
3
|
+
* Extracts the first property name and value from a single-property object.
|
|
4
|
+
* Used to infer parameter names for error messages without string literals.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const count = 5;
|
|
9
|
+
* const [name, value] = nameof({ count }); // -> ["count", 5]
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
function nameof(param) {
|
|
15
|
+
if (param === null || typeof param !== "object") throw new TypeError("nameof expects a non-null object with exactly one own enumerable property.");
|
|
16
|
+
const keys = Object.keys(param);
|
|
17
|
+
if (keys.length !== 1) throw new TypeError("nameof expects an object with exactly one own enumerable property.");
|
|
18
|
+
const key = keys[0];
|
|
19
|
+
return [key, param[key]];
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/utility/guards/extractParameter.ts
|
|
23
|
+
function extractParameter(param, paramName) {
|
|
24
|
+
const [extractedParamName, value] = paramName ? [paramName, param] : nameof(param);
|
|
25
|
+
return {
|
|
26
|
+
key: extractedParamName,
|
|
27
|
+
value
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/core/errors/TyneqError.ts
|
|
32
|
+
/**
|
|
33
|
+
* Base class for all errors thrown by Tyneq.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* try { Tyneq.from([]).first(); }
|
|
38
|
+
* catch (e) { if (e instanceof TyneqError) { console.log(e.message); } }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @group Errors
|
|
42
|
+
*/
|
|
43
|
+
var TyneqError = class extends Error {
|
|
44
|
+
/** The underlying error that caused this error, if any. */
|
|
45
|
+
inner;
|
|
46
|
+
constructor(message, options) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = new.target.name;
|
|
49
|
+
this.inner = options?.inner;
|
|
50
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/core/errors/argument/ArgumentError.ts
|
|
55
|
+
/**
|
|
56
|
+
* Thrown when a method argument fails validation.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* try { Tyneq.from([]).take(-1); }
|
|
61
|
+
* catch (e) { if (e instanceof ArgumentError) { console.log(e.paramName); } }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @see {@link TyneqError}
|
|
65
|
+
* @group Errors
|
|
66
|
+
*/
|
|
67
|
+
var ArgumentError = class extends TyneqError {
|
|
68
|
+
/** The name of the parameter that caused the error. */
|
|
69
|
+
paramName;
|
|
70
|
+
constructor(message, paramName, inner) {
|
|
71
|
+
super(message, { inner });
|
|
72
|
+
this.paramName = paramName;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/core/errors/argument/ArgumentNullError.ts
|
|
77
|
+
/**
|
|
78
|
+
* Thrown when a required argument is `null`.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* try { Tyneq.from([1, 2]).select(null as any); }
|
|
83
|
+
* catch (e) { if (e instanceof ArgumentNullError) { console.log(e.paramName); } }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @see {@link ArgumentError}
|
|
87
|
+
* @group Errors
|
|
88
|
+
*/
|
|
89
|
+
var ArgumentNullError = class extends ArgumentError {
|
|
90
|
+
constructor(paramName, inner) {
|
|
91
|
+
super(`${paramName} cannot be null.`, paramName, inner);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/utility/guards/NullGuards.ts
|
|
96
|
+
/**
|
|
97
|
+
* Null and undefined guard implementations. Called by `ArgumentUtility`.
|
|
98
|
+
*
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
var NullGuards = class NullGuards {
|
|
102
|
+
constructor() {}
|
|
103
|
+
static checkNotNull(value, paramName) {
|
|
104
|
+
if (value === null) throw new ArgumentNullError(paramName);
|
|
105
|
+
}
|
|
106
|
+
static checkNotUndefined(value, paramName) {
|
|
107
|
+
if (value === void 0) throw new ArgumentError(`'${paramName}' cannot be undefined.`, paramName);
|
|
108
|
+
}
|
|
109
|
+
static checkNotOptional(value, paramName) {
|
|
110
|
+
NullGuards.checkNotNull(value, paramName);
|
|
111
|
+
NullGuards.checkNotUndefined(value, paramName);
|
|
112
|
+
}
|
|
113
|
+
static checkNotNullOrEmpty(value, paramName) {
|
|
114
|
+
NullGuards.checkNotNull(value, paramName);
|
|
115
|
+
if (value.length === 0) throw new ArgumentError(`'${paramName}' cannot be empty.`, paramName);
|
|
116
|
+
}
|
|
117
|
+
static checkNotOptionalOrEmpty(value, paramName) {
|
|
118
|
+
NullGuards.checkNotOptional(value, paramName);
|
|
119
|
+
if (value.length === 0) throw new ArgumentError(`'${paramName}' cannot be empty.`, paramName);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/utility/guards/StringGuards.ts
|
|
124
|
+
/**
|
|
125
|
+
* String-specific guard implementations. Called by `ArgumentUtility`.
|
|
126
|
+
*
|
|
127
|
+
* @internal
|
|
128
|
+
*/
|
|
129
|
+
var StringGuards = class {
|
|
130
|
+
constructor() {}
|
|
131
|
+
static checkNotNullOrWhiteSpace(value, paramName) {
|
|
132
|
+
NullGuards.checkNotOptional(value, paramName);
|
|
133
|
+
if (value.trim().length === 0) throw new ArgumentError(`'${paramName}' cannot be empty or whitespace.`, paramName);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/core/errors/argument/ArgumentOutOfRangeError.ts
|
|
138
|
+
/**
|
|
139
|
+
* Thrown when an argument is outside the valid range.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* try { Tyneq.from([1, 2]).take(-1); }
|
|
144
|
+
* catch (e) { if (e instanceof ArgumentOutOfRangeError) { console.log(e.actualValue); } }
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @see {@link ArgumentError}
|
|
148
|
+
* @group Errors
|
|
149
|
+
*/
|
|
150
|
+
var ArgumentOutOfRangeError = class extends ArgumentError {
|
|
151
|
+
/** The actual value that was out of range. */
|
|
152
|
+
actualValue;
|
|
153
|
+
constructor(paramName, message, actualValue, inner) {
|
|
154
|
+
super(message ?? `${paramName} was out of range.`, paramName, inner);
|
|
155
|
+
this.actualValue = actualValue;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/utility/guards/NumericGuards.ts
|
|
160
|
+
/**
|
|
161
|
+
* Numeric range and type guard implementations. Called by `ArgumentUtility`.
|
|
162
|
+
*
|
|
163
|
+
* @internal
|
|
164
|
+
*/
|
|
165
|
+
var NumericGuards = class NumericGuards {
|
|
166
|
+
constructor() {}
|
|
167
|
+
static checkNonNegative(value, paramName) {
|
|
168
|
+
if (!Number.isFinite(value) || value < 0) throw new ArgumentOutOfRangeError(paramName, `'${paramName}' must be a non-negative number.`);
|
|
169
|
+
}
|
|
170
|
+
static checkPositive(value, paramName) {
|
|
171
|
+
if (!Number.isFinite(value) || value <= 0) throw new ArgumentOutOfRangeError(paramName, `'${paramName}' must be a positive number.`);
|
|
172
|
+
}
|
|
173
|
+
static checkNegative(value, paramName) {
|
|
174
|
+
if (!Number.isFinite(value) || value >= 0) throw new ArgumentOutOfRangeError(paramName, `'${paramName}' must be a negative number.`, value);
|
|
175
|
+
}
|
|
176
|
+
static checkNonPositive(value, paramName) {
|
|
177
|
+
if (!Number.isFinite(value) || value > 0) throw new ArgumentOutOfRangeError(paramName, `'${paramName}' must be a non-positive number.`, value);
|
|
178
|
+
}
|
|
179
|
+
static checkInRange(value, min, max, paramName) {
|
|
180
|
+
if (min > max) throw new ArgumentError(`'min' (${min}) must be <= 'max' (${max}).`, "min");
|
|
181
|
+
if (!Number.isFinite(value) || value < min || value > max) throw new ArgumentOutOfRangeError(paramName, `'${paramName}' must be in range [${min}, ${max}].`);
|
|
182
|
+
}
|
|
183
|
+
static checkInteger(value, paramName) {
|
|
184
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) throw new ArgumentError(`'${paramName}' must be an integer.`, paramName);
|
|
185
|
+
}
|
|
186
|
+
static checkFinite(value, paramName) {
|
|
187
|
+
if (!Number.isFinite(value)) throw new ArgumentError(`'${paramName}' must be a finite number.`, paramName);
|
|
188
|
+
}
|
|
189
|
+
static checkNotNaN(value, paramName) {
|
|
190
|
+
if (Number.isNaN(value)) throw new ArgumentError(`'${paramName}' cannot be NaN.`, paramName);
|
|
191
|
+
}
|
|
192
|
+
static checkSafeInteger(value, paramName) {
|
|
193
|
+
if (!Number.isSafeInteger(value)) throw new ArgumentError(`'${paramName}' must be a safe integer.`, paramName);
|
|
194
|
+
}
|
|
195
|
+
static checkArrayIndex(value, paramName, arrayLength) {
|
|
196
|
+
NumericGuards.checkSafeInteger(value, paramName);
|
|
197
|
+
const maxLength = arrayLength ?? Number.MAX_SAFE_INTEGER;
|
|
198
|
+
if (value < 0 || value >= maxLength) throw new ArgumentOutOfRangeError(paramName, `'${paramName}' must be in range [0, ${maxLength}).`, value);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region src/core/errors/argument/ArgumentTypeError.ts
|
|
203
|
+
/**
|
|
204
|
+
* Thrown when an argument has the wrong type.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts
|
|
208
|
+
* try { Tyneq.from([1, 2]).where("not a function" as any); }
|
|
209
|
+
* catch (e) { if (e instanceof ArgumentTypeError) { console.log(e.expectedType, e.actualType); } }
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @see {@link ArgumentError}
|
|
213
|
+
* @group Errors
|
|
214
|
+
*/
|
|
215
|
+
var ArgumentTypeError = class extends ArgumentError {
|
|
216
|
+
/** The expected type name. */
|
|
217
|
+
expectedType;
|
|
218
|
+
/** The actual type name received. */
|
|
219
|
+
actualType;
|
|
220
|
+
constructor(paramName, expectedType, actualType, message, inner) {
|
|
221
|
+
let errorMessage;
|
|
222
|
+
if (message) errorMessage = message;
|
|
223
|
+
else if (expectedType && actualType) errorMessage = `'${paramName}' expected type ${expectedType} but got ${actualType}.`;
|
|
224
|
+
else if (expectedType) errorMessage = `'${paramName}' must be of type ${expectedType}.`;
|
|
225
|
+
else errorMessage = `'${paramName}' has incorrect type.`;
|
|
226
|
+
super(errorMessage, paramName, inner);
|
|
227
|
+
this.expectedType = expectedType;
|
|
228
|
+
this.actualType = actualType;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/utility/TypeGuardUtility.ts
|
|
233
|
+
/**
|
|
234
|
+
* Type guard predicates for Tyneq's core protocol types.
|
|
235
|
+
*
|
|
236
|
+
* @group Utilities
|
|
237
|
+
*/
|
|
238
|
+
var TypeGuardUtility = class {
|
|
239
|
+
constructor() {}
|
|
240
|
+
static isIterable(value) {
|
|
241
|
+
return value !== null && value !== void 0 && typeof value[Symbol.iterator] === "function";
|
|
242
|
+
}
|
|
243
|
+
static isIterator(value) {
|
|
244
|
+
const valueType = typeof value;
|
|
245
|
+
return value !== null && (valueType === "object" || valueType === "function") && typeof value.next === "function";
|
|
246
|
+
}
|
|
247
|
+
static isIterableIterator(value) {
|
|
248
|
+
return this.isIterable(value) && this.isIterator(value);
|
|
249
|
+
}
|
|
250
|
+
static isEnumerator(value) {
|
|
251
|
+
if (!this.isIterator(value)) return false;
|
|
252
|
+
const candidate = value;
|
|
253
|
+
return (candidate.return === void 0 || typeof candidate.return === "function") && (candidate.throw === void 0 || typeof candidate.throw === "function");
|
|
254
|
+
}
|
|
255
|
+
static isEnumerable(value) {
|
|
256
|
+
if (value === null || value === void 0) return false;
|
|
257
|
+
const candidate = value;
|
|
258
|
+
return this.isIterable(value) && typeof candidate.getEnumerator === "function";
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/utility/guards/TypeGuards.ts
|
|
263
|
+
/**
|
|
264
|
+
* Type-checking guard implementations. Called by `ArgumentUtility`.
|
|
265
|
+
*
|
|
266
|
+
* @internal
|
|
267
|
+
*/
|
|
268
|
+
var TypeGuards = class {
|
|
269
|
+
constructor() {}
|
|
270
|
+
static checkFunction(value, paramName) {
|
|
271
|
+
if (typeof value !== "function") throw new ArgumentTypeError(paramName, "function", typeof value);
|
|
272
|
+
}
|
|
273
|
+
static checkIterable(value, paramName) {
|
|
274
|
+
if (!TypeGuardUtility.isIterable(value)) throw new ArgumentTypeError(paramName, "iterable", value === null ? "null" : value === void 0 ? "undefined" : typeof value);
|
|
275
|
+
}
|
|
276
|
+
static checkIterator(value, paramName) {
|
|
277
|
+
if (!TypeGuardUtility.isIterator(value)) throw new ArgumentTypeError(paramName, "iterator", value === null ? "null" : value === void 0 ? "undefined" : typeof value);
|
|
278
|
+
}
|
|
279
|
+
static checkEnumerable(value, paramName) {
|
|
280
|
+
if (!TypeGuardUtility.isEnumerable(value)) throw new ArgumentTypeError(paramName, "Enumerable", value === null ? "null" : value === void 0 ? "undefined" : typeof value);
|
|
281
|
+
}
|
|
282
|
+
static checkEnumerator(value, paramName) {
|
|
283
|
+
if (!TypeGuardUtility.isEnumerator(value)) throw new ArgumentTypeError(paramName, "Enumerator", value === null ? "null" : value === void 0 ? "undefined" : typeof value);
|
|
284
|
+
}
|
|
285
|
+
static checkInstanceOf(value, constructor, paramName) {
|
|
286
|
+
if (!(value instanceof constructor)) throw new ArgumentTypeError(paramName, constructor.name || "unknown", value === null ? "null" : value === void 0 ? "undefined" : typeof value);
|
|
287
|
+
}
|
|
288
|
+
static checkHasLength(value, paramName) {
|
|
289
|
+
if (typeof value !== "object" || value === null || typeof value.length !== "number") throw new ArgumentTypeError(paramName, "object with numeric length property", typeof value);
|
|
290
|
+
}
|
|
291
|
+
static check(value, paramName, predicate, message) {
|
|
292
|
+
if (!predicate(value)) throw new ArgumentError(message, paramName);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
//#endregion
|
|
296
|
+
//#region src/utility/ArgumentUtility.ts
|
|
297
|
+
/**
|
|
298
|
+
* Facade for all argument validation guards.
|
|
299
|
+
*
|
|
300
|
+
* Every method accepts either a single-property object (`{ count }`) - where the
|
|
301
|
+
* property name becomes the error message's parameter name - or a raw value with
|
|
302
|
+
* an explicit `paramName` string. Prefer the object form; the name is inferred
|
|
303
|
+
* automatically via `nameof`.
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```ts
|
|
307
|
+
* import { ArgumentUtility } from "tyneq/utility";
|
|
308
|
+
*
|
|
309
|
+
* function take(count: number) {
|
|
310
|
+
* ArgumentUtility.checkNonNegative({ count }); // throws ArgumentOutOfRangeError if count < 0
|
|
311
|
+
* ArgumentUtility.checkInteger({ count }); // throws ArgumentError if count is not an integer
|
|
312
|
+
* }
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* @group Utilities
|
|
316
|
+
*/
|
|
317
|
+
var ArgumentUtility = class {
|
|
318
|
+
constructor() {}
|
|
319
|
+
static checkNotNull(param, paramName) {
|
|
320
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
321
|
+
NullGuards.checkNotNull(value, key);
|
|
322
|
+
}
|
|
323
|
+
static checkNotUndefined(param, paramName) {
|
|
324
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
325
|
+
NullGuards.checkNotUndefined(value, key);
|
|
326
|
+
}
|
|
327
|
+
static checkNotOptional(param, paramName) {
|
|
328
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
329
|
+
NullGuards.checkNotOptional(value, key);
|
|
330
|
+
}
|
|
331
|
+
static checkNotNullOrEmpty(param, paramName) {
|
|
332
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
333
|
+
NullGuards.checkNotNullOrEmpty(value, key);
|
|
334
|
+
}
|
|
335
|
+
static checkNotOptionalOrEmpty(param, paramName) {
|
|
336
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
337
|
+
NullGuards.checkNotOptionalOrEmpty(value, key);
|
|
338
|
+
}
|
|
339
|
+
static checkNotNullOrWhiteSpace(param, paramName) {
|
|
340
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
341
|
+
StringGuards.checkNotNullOrWhiteSpace(value, key);
|
|
342
|
+
}
|
|
343
|
+
static checkNonNegative(param, paramName) {
|
|
344
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
345
|
+
NumericGuards.checkNonNegative(value, key);
|
|
346
|
+
}
|
|
347
|
+
static checkPositive(param, paramName) {
|
|
348
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
349
|
+
NumericGuards.checkPositive(value, key);
|
|
350
|
+
}
|
|
351
|
+
static checkNegative(param, paramName) {
|
|
352
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
353
|
+
NumericGuards.checkNegative(value, key);
|
|
354
|
+
}
|
|
355
|
+
static checkNonPositive(param, paramName) {
|
|
356
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
357
|
+
NumericGuards.checkNonPositive(value, key);
|
|
358
|
+
}
|
|
359
|
+
static checkInRange(param, min, max, paramName) {
|
|
360
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
361
|
+
NumericGuards.checkInRange(value, min, max, key);
|
|
362
|
+
}
|
|
363
|
+
static checkInteger(param, paramName) {
|
|
364
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
365
|
+
NumericGuards.checkInteger(value, key);
|
|
366
|
+
}
|
|
367
|
+
static checkFinite(param, paramName) {
|
|
368
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
369
|
+
NumericGuards.checkFinite(value, key);
|
|
370
|
+
}
|
|
371
|
+
static checkNotNaN(param, paramName) {
|
|
372
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
373
|
+
NumericGuards.checkNotNaN(value, key);
|
|
374
|
+
}
|
|
375
|
+
static checkSafeInteger(param, paramName) {
|
|
376
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
377
|
+
NumericGuards.checkSafeInteger(value, key);
|
|
378
|
+
}
|
|
379
|
+
static checkArrayIndex(param, paramNameOrArrayLength, arrayLength) {
|
|
380
|
+
const hasExplicitParamName = typeof paramNameOrArrayLength === "string";
|
|
381
|
+
const { key, value } = hasExplicitParamName ? this.extractParameter(param, paramNameOrArrayLength) : this.extractParameter(param);
|
|
382
|
+
const resolvedArrayLength = hasExplicitParamName ? arrayLength : paramNameOrArrayLength;
|
|
383
|
+
NumericGuards.checkArrayIndex(value, key, resolvedArrayLength);
|
|
384
|
+
}
|
|
385
|
+
static checkFunction(param, paramName) {
|
|
386
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
387
|
+
TypeGuards.checkFunction(value, key);
|
|
388
|
+
}
|
|
389
|
+
static checkIterable(param, paramName) {
|
|
390
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
391
|
+
TypeGuards.checkIterable(value, key);
|
|
392
|
+
}
|
|
393
|
+
static checkIterator(param, paramName) {
|
|
394
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
395
|
+
TypeGuards.checkIterator(value, key);
|
|
396
|
+
}
|
|
397
|
+
static checkEnumerable(param, paramName) {
|
|
398
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
399
|
+
TypeGuards.checkEnumerable(value, key);
|
|
400
|
+
}
|
|
401
|
+
static checkEnumerator(param, paramName) {
|
|
402
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
403
|
+
TypeGuards.checkEnumerator(value, key);
|
|
404
|
+
}
|
|
405
|
+
static checkInstanceOf(param, constructor, paramName) {
|
|
406
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
407
|
+
TypeGuards.checkInstanceOf(value, constructor, key);
|
|
408
|
+
}
|
|
409
|
+
static checkHasLength(param, paramName) {
|
|
410
|
+
const { key, value } = this.extractParameter(param, paramName);
|
|
411
|
+
TypeGuards.checkHasLength(value, key);
|
|
412
|
+
}
|
|
413
|
+
static check(param, paramNameOrPredicate, predicateOrMessage, message) {
|
|
414
|
+
const hasExplicitParamName = typeof paramNameOrPredicate === "string";
|
|
415
|
+
const predicate = hasExplicitParamName ? predicateOrMessage : paramNameOrPredicate;
|
|
416
|
+
const validationMessage = hasExplicitParamName ? message : predicateOrMessage;
|
|
417
|
+
const { key, value } = hasExplicitParamName ? this.extractParameter(param, paramNameOrPredicate) : this.extractParameter(param);
|
|
418
|
+
TypeGuards.check(value, key, predicate, validationMessage);
|
|
419
|
+
}
|
|
420
|
+
static extractParameter(param, paramName) {
|
|
421
|
+
return extractParameter(param, paramName);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/core/errors/ReflectionError.ts
|
|
426
|
+
/**
|
|
427
|
+
* Thrown when a prototype reflection operation fails - for example, when a
|
|
428
|
+
* method that is expected to exist on a prototype cannot be found.
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```ts
|
|
432
|
+
* try { reflect(proto).getMethod("missing"); }
|
|
433
|
+
* catch (e) {
|
|
434
|
+
* if (e instanceof ReflectionError) {
|
|
435
|
+
* console.log(e.methodName, e.prototypeName, e.message);
|
|
436
|
+
* }
|
|
437
|
+
* }
|
|
438
|
+
* ```
|
|
439
|
+
*
|
|
440
|
+
* @see {@link TyneqError}
|
|
441
|
+
* @group Errors
|
|
442
|
+
*/
|
|
443
|
+
var ReflectionError = class extends TyneqError {
|
|
444
|
+
/** The name of the method that could not be found. */
|
|
445
|
+
methodName;
|
|
446
|
+
/** The name of the prototype/class that was searched. */
|
|
447
|
+
prototypeName;
|
|
448
|
+
constructor(message, methodName, prototypeName, inner) {
|
|
449
|
+
super(message, { inner });
|
|
450
|
+
this.methodName = methodName;
|
|
451
|
+
this.prototypeName = prototypeName;
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
//#endregion
|
|
455
|
+
//#region src/utility/reflect.ts
|
|
456
|
+
/**
|
|
457
|
+
* The result of a {@link reflect} call. Provides typed access to the members of
|
|
458
|
+
* the reflected target.
|
|
459
|
+
*
|
|
460
|
+
* @group Reflection
|
|
461
|
+
*/
|
|
462
|
+
var ReflectionContext = class {
|
|
463
|
+
proto;
|
|
464
|
+
options;
|
|
465
|
+
/** @internal */
|
|
466
|
+
constructor(proto, options) {
|
|
467
|
+
this.proto = proto;
|
|
468
|
+
this.options = options;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Returns descriptors for all own (and optionally inherited) members,
|
|
472
|
+
* excluding `constructor`.
|
|
473
|
+
*/
|
|
474
|
+
members() {
|
|
475
|
+
return this.collectDescriptors(this.proto);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Returns descriptors for all method members (function-valued own properties),
|
|
479
|
+
* excluding `constructor`.
|
|
480
|
+
*/
|
|
481
|
+
methods() {
|
|
482
|
+
return this.members().filter((d) => d.kind === "method");
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Returns descriptors for all data members (non-function value properties).
|
|
486
|
+
*/
|
|
487
|
+
fields() {
|
|
488
|
+
return this.members().filter((d) => d.kind === "data");
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Returns descriptors for all accessor members (get/set properties).
|
|
492
|
+
*/
|
|
493
|
+
accessors() {
|
|
494
|
+
return this.members().filter((d) => d.kind === "accessor");
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Returns the descriptor for the named member, or `undefined` if not found.
|
|
498
|
+
*/
|
|
499
|
+
get(name) {
|
|
500
|
+
return this.findDescriptor(name);
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Returns `true` if a member with the given name exists on the target.
|
|
504
|
+
*/
|
|
505
|
+
has(name) {
|
|
506
|
+
return this.findDescriptor(name) !== void 0;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Returns the method descriptor for `name`, or throws {@link ReflectionError}
|
|
510
|
+
* if the member does not exist or is not a method.
|
|
511
|
+
*
|
|
512
|
+
* @throws {ReflectionError} when the member is absent or is not a method.
|
|
513
|
+
*/
|
|
514
|
+
getMethod(name) {
|
|
515
|
+
const descriptor = this.findDescriptor(name);
|
|
516
|
+
if (descriptor === void 0) {
|
|
517
|
+
const prototypeName = this.proto?.constructor?.name ?? "unknown";
|
|
518
|
+
throw new ReflectionError(`Method "${String(name)}" not found on ${prototypeName}. Ensure the method is defined directly on the class, not inherited or deleted.`, String(name), prototypeName);
|
|
519
|
+
}
|
|
520
|
+
if (descriptor.kind !== "method") {
|
|
521
|
+
const prototypeName = this.proto?.constructor?.name ?? "unknown";
|
|
522
|
+
throw new ReflectionError(`Member "${String(name)}" on ${prototypeName} is a ${descriptor.kind}, not a method.`, String(name), prototypeName);
|
|
523
|
+
}
|
|
524
|
+
return descriptor;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Returns the accessor descriptor for `name`, or throws {@link ReflectionError}
|
|
528
|
+
* if the member does not exist or is not an accessor.
|
|
529
|
+
*
|
|
530
|
+
* @throws {ReflectionError} when the member is absent or is not an accessor.
|
|
531
|
+
*/
|
|
532
|
+
getAccessor(name) {
|
|
533
|
+
const descriptor = this.findDescriptor(name);
|
|
534
|
+
if (descriptor === void 0) {
|
|
535
|
+
const prototypeName = this.proto?.constructor?.name ?? "unknown";
|
|
536
|
+
throw new ReflectionError(`Accessor "${String(name)}" not found on ${prototypeName}.`, String(name), prototypeName);
|
|
537
|
+
}
|
|
538
|
+
if (descriptor.kind !== "accessor") {
|
|
539
|
+
const prototypeName = this.proto?.constructor?.name ?? "unknown";
|
|
540
|
+
throw new ReflectionError(`Member "${String(name)}" on ${prototypeName} is a ${descriptor.kind}, not an accessor.`, String(name), prototypeName);
|
|
541
|
+
}
|
|
542
|
+
return descriptor;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Returns `true` if a method with the given name exists on the target.
|
|
546
|
+
*
|
|
547
|
+
* Unlike {@link has}, this returns `false` if the member exists but is an accessor or data property.
|
|
548
|
+
*/
|
|
549
|
+
hasMethod(name) {
|
|
550
|
+
return this.findDescriptor(name)?.kind === "method";
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Returns the method descriptor for `name`, or `undefined` if the member does not
|
|
554
|
+
* exist or is not a method. Never throws.
|
|
555
|
+
*/
|
|
556
|
+
tryGetMethod(name) {
|
|
557
|
+
const descriptor = this.findDescriptor(name);
|
|
558
|
+
return descriptor?.kind === "method" ? descriptor : void 0;
|
|
559
|
+
}
|
|
560
|
+
findDescriptor(name) {
|
|
561
|
+
let current = this.proto;
|
|
562
|
+
const stop = Object.prototype;
|
|
563
|
+
while (current !== null && current !== stop) {
|
|
564
|
+
const raw = Object.getOwnPropertyDescriptor(current, name);
|
|
565
|
+
if (raw !== void 0) return buildDescriptor(name, raw);
|
|
566
|
+
if (!this.options.inherited) break;
|
|
567
|
+
current = Object.getPrototypeOf(current);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
collectDescriptors(startProto) {
|
|
571
|
+
const seen = /* @__PURE__ */ new Set();
|
|
572
|
+
const results = [];
|
|
573
|
+
const stop = Object.prototype;
|
|
574
|
+
let current = startProto;
|
|
575
|
+
while (current !== null && current !== stop) {
|
|
576
|
+
const keys = this.options.symbols ? Reflect.ownKeys(current) : Object.getOwnPropertyNames(current);
|
|
577
|
+
for (const key of keys) {
|
|
578
|
+
if (key === "constructor") continue;
|
|
579
|
+
if (seen.has(key)) continue;
|
|
580
|
+
seen.add(key);
|
|
581
|
+
const raw = Object.getOwnPropertyDescriptor(current, key);
|
|
582
|
+
if (raw === void 0) continue;
|
|
583
|
+
const descriptor = buildDescriptor(key, raw);
|
|
584
|
+
if (descriptor !== void 0) results.push(descriptor);
|
|
585
|
+
}
|
|
586
|
+
if (!this.options.inherited) break;
|
|
587
|
+
current = Object.getPrototypeOf(current);
|
|
588
|
+
}
|
|
589
|
+
return results;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* Creates a {@link ReflectionContext} for the given target.
|
|
594
|
+
*
|
|
595
|
+
* The `target` can be:
|
|
596
|
+
* - A **constructor function** - reflects the class prototype (instance members). Preferred form.
|
|
597
|
+
* - A **prototype object** (`MyClass.prototype`) - reflects it directly.
|
|
598
|
+
* - Any **object** - reflects the object's own properties directly.
|
|
599
|
+
*
|
|
600
|
+
* @example
|
|
601
|
+
* ```ts
|
|
602
|
+
* import { reflect } from "tyneq/utility";
|
|
603
|
+
*
|
|
604
|
+
* class Service {
|
|
605
|
+
* public name = "svc";
|
|
606
|
+
* public get label(): string { return this.name; }
|
|
607
|
+
* public run(): void { /* ... *\/ }
|
|
608
|
+
* }
|
|
609
|
+
*
|
|
610
|
+
* const ctx = reflect(Service);
|
|
611
|
+
*
|
|
612
|
+
* ctx.methods(); // -> [{ kind: "method", name: "run", ... }]
|
|
613
|
+
* ctx.accessors(); // -> [{ kind: "accessor", name: "label", canRead: true, canWrite: false, ... }]
|
|
614
|
+
*
|
|
615
|
+
* const m = ctx.getMethod("run");
|
|
616
|
+
* m.invoke(new Service()); // calls run()
|
|
617
|
+
* ```
|
|
618
|
+
*
|
|
619
|
+
* Walk the full prototype chain:
|
|
620
|
+
*
|
|
621
|
+
* ```ts
|
|
622
|
+
* const ctx = reflect(DerivedClass, { inherited: true });
|
|
623
|
+
* ctx.members(); // includes members from base classes too
|
|
624
|
+
* ```
|
|
625
|
+
*
|
|
626
|
+
* @group Reflection
|
|
627
|
+
*/
|
|
628
|
+
function reflect(target, options = {}) {
|
|
629
|
+
return new ReflectionContext(resolveProto(target), options);
|
|
630
|
+
}
|
|
631
|
+
function resolveProto(target) {
|
|
632
|
+
if (typeof target === "function") return target.prototype;
|
|
633
|
+
return target;
|
|
634
|
+
}
|
|
635
|
+
function buildDescriptor(name, raw) {
|
|
636
|
+
if ("get" in raw || "set" in raw) return {
|
|
637
|
+
kind: "accessor",
|
|
638
|
+
name,
|
|
639
|
+
get: raw.get,
|
|
640
|
+
set: raw.set,
|
|
641
|
+
configurable: raw.configurable ?? false,
|
|
642
|
+
enumerable: raw.enumerable ?? false,
|
|
643
|
+
canRead: typeof raw.get === "function",
|
|
644
|
+
canWrite: typeof raw.set === "function"
|
|
645
|
+
};
|
|
646
|
+
if (typeof raw.value === "function") {
|
|
647
|
+
const fn = raw.value;
|
|
648
|
+
return {
|
|
649
|
+
kind: "method",
|
|
650
|
+
name,
|
|
651
|
+
value: fn,
|
|
652
|
+
invoke: (thisArg, ...args) => fn.apply(thisArg, args)
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
if ("value" in raw) return {
|
|
656
|
+
kind: "data",
|
|
657
|
+
name,
|
|
658
|
+
value: raw.value,
|
|
659
|
+
writable: raw.writable ?? false,
|
|
660
|
+
configurable: raw.configurable ?? false,
|
|
661
|
+
enumerable: raw.enumerable ?? false
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region src/utility/Lazy.ts
|
|
666
|
+
/**
|
|
667
|
+
* Utility class for lazy initialization of values.
|
|
668
|
+
*
|
|
669
|
+
* @group Utilities
|
|
670
|
+
*/
|
|
671
|
+
var Lazy = class {
|
|
672
|
+
/** The lazily initialized value, or `undefined` if not yet initialized. */
|
|
673
|
+
lazyValue = void 0;
|
|
674
|
+
/** Indicates whether the value has been initialized. */
|
|
675
|
+
initialized = false;
|
|
676
|
+
constructor(factory) {
|
|
677
|
+
this.factory = factory;
|
|
678
|
+
}
|
|
679
|
+
/** Returns the lazily initialized value, initializing it if necessary. */
|
|
680
|
+
get value() {
|
|
681
|
+
if (!this.initialized) {
|
|
682
|
+
this.lazyValue = this.factory();
|
|
683
|
+
this.initialized = true;
|
|
684
|
+
}
|
|
685
|
+
return this.lazyValue;
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
//#endregion
|
|
689
|
+
export { ArgumentUtility as a, ArgumentOutOfRangeError as c, TyneqError as d, nameof as f, ReflectionError as i, ArgumentNullError as l, ReflectionContext as n, TypeGuardUtility as o, reflect as r, ArgumentTypeError as s, Lazy as t, ArgumentError as u };
|
|
690
|
+
|
|
691
|
+
//# sourceMappingURL=Lazy.js.map
|