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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +319 -0
  3. package/dist/Lazy.cjs +762 -0
  4. package/dist/Lazy.cjs.map +1 -0
  5. package/dist/Lazy.js +691 -0
  6. package/dist/Lazy.js.map +1 -0
  7. package/dist/TyneqCachedTerminalOperator.cjs +4950 -0
  8. package/dist/TyneqCachedTerminalOperator.cjs.map +1 -0
  9. package/dist/TyneqCachedTerminalOperator.d.cts +724 -0
  10. package/dist/TyneqCachedTerminalOperator.d.cts.map +1 -0
  11. package/dist/TyneqCachedTerminalOperator.d.ts +724 -0
  12. package/dist/TyneqCachedTerminalOperator.d.ts.map +1 -0
  13. package/dist/TyneqCachedTerminalOperator.js +4741 -0
  14. package/dist/TyneqCachedTerminalOperator.js.map +1 -0
  15. package/dist/ValidationBuilder.cjs +80 -0
  16. package/dist/ValidationBuilder.cjs.map +1 -0
  17. package/dist/ValidationBuilder.d.cts +319 -0
  18. package/dist/ValidationBuilder.d.cts.map +1 -0
  19. package/dist/ValidationBuilder.d.ts +319 -0
  20. package/dist/ValidationBuilder.d.ts.map +1 -0
  21. package/dist/ValidationBuilder.js +69 -0
  22. package/dist/ValidationBuilder.js.map +1 -0
  23. package/dist/core.d.cts +1393 -0
  24. package/dist/core.d.cts.map +1 -0
  25. package/dist/core.d.ts +1393 -0
  26. package/dist/core.d.ts.map +1 -0
  27. package/dist/index.cjs +863 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +1038 -0
  30. package/dist/index.d.cts.map +1 -0
  31. package/dist/index.d.ts +1038 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +809 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/plugin/index.cjs +24 -0
  36. package/dist/plugin/index.d.cts +89 -0
  37. package/dist/plugin/index.d.cts.map +1 -0
  38. package/dist/plugin/index.d.ts +89 -0
  39. package/dist/plugin/index.d.ts.map +1 -0
  40. package/dist/plugin/index.js +2 -0
  41. package/dist/utility/index.cjs +9 -0
  42. package/dist/utility/index.d.cts +2 -0
  43. package/dist/utility/index.d.ts +2 -0
  44. package/dist/utility/index.js +3 -0
  45. 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