@nestia/e2e 14.0.1 → 14.0.2

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.
@@ -1 +1,22 @@
1
+ /**
2
+ * Compares two values through their JSON form and returns the accessors that
3
+ * differ.
4
+ *
5
+ * The comparison walks the keys of the first value, skipping keys whose value
6
+ * is `undefined` and keys the exception predicate accepts, so a key only the
7
+ * second value has is not a difference. Values with a `toJSON` are compared by
8
+ * it, functions are ignored, `null` differs from every object, and arrays must
9
+ * have the same length. An empty result means no difference.
10
+ *
11
+ * Processing cost: The walker traverses the first value and matching
12
+ * second-value positions, recording differing accessors. Object keys and
13
+ * recursion require space proportional to visited structure and depth; toJSON
14
+ * and exception callback costs belong to their implementations. Cyclic inputs
15
+ * are unsupported.
16
+ *
17
+ * @evidence contracts/common.md#principled-implementation Each pair is first read through `toJSON`, then separated by type, by `null`, by array against non-array, and by key walking, so the differences are the accessors where the JSON values differ over the keys of the first value; reading through `toJSON` compares a `Date` by its instant instead of treating every two dates as equal.
18
+ * @evidence contracts/common.md#clear-and-simple-design One curried function with three inner walkers (value, array, object) that append to one accessor list.
19
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The exception predicate is the caller's, and no key or type name is special-cased.
20
+ * @evidence contracts/common.md#meaningful-documentation The comment states the comparison rules and what the result means.
21
+ */
1
22
  export declare const json_equal_to: (exception: (key: string) => boolean) => <T>(x: T) => (y: T | null | undefined) => string[];
@@ -1,6 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.json_equal_to = void 0;
4
+ /**
5
+ * Compares two values through their JSON form and returns the accessors that
6
+ * differ.
7
+ *
8
+ * The comparison walks the keys of the first value, skipping keys whose value
9
+ * is `undefined` and keys the exception predicate accepts, so a key only the
10
+ * second value has is not a difference. Values with a `toJSON` are compared by
11
+ * it, functions are ignored, `null` differs from every object, and arrays must
12
+ * have the same length. An empty result means no difference.
13
+ *
14
+ * Processing cost: The walker traverses the first value and matching
15
+ * second-value positions, recording differing accessors. Object keys and
16
+ * recursion require space proportional to visited structure and depth; toJSON
17
+ * and exception callback costs belong to their implementations. Cyclic inputs
18
+ * are unsupported.
19
+ *
20
+ * @evidence contracts/common.md#principled-implementation Each pair is first read through `toJSON`, then separated by type, by `null`, by array against non-array, and by key walking, so the differences are the accessors where the JSON values differ over the keys of the first value; reading through `toJSON` compares a `Date` by its instant instead of treating every two dates as equal.
21
+ * @evidence contracts/common.md#clear-and-simple-design One curried function with three inner walkers (value, array, object) that append to one accessor list.
22
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The exception predicate is the caller's, and no key or type name is special-cased.
23
+ * @evidence contracts/common.md#meaningful-documentation The comment states the comparison rules and what the result means.
24
+ */
4
25
  const json_equal_to = (exception) => (x) => (y) => {
5
26
  const container = [];
6
27
  const iterate = (accessor) => (x) => (y) => {
@@ -21,12 +42,11 @@ const json_equal_to = (exception) => (x) => (y) => {
21
42
  if (x !== y)
22
43
  container.push(accessor);
23
44
  }
24
- else if (x instanceof Array)
25
- if (!(y instanceof Array))
26
- container.push(accessor);
27
- else
28
- array(accessor)(x)(y);
29
- else if (x instanceof Object)
45
+ else if (Array.isArray(x) !== Array.isArray(y))
46
+ container.push(accessor);
47
+ else if (Array.isArray(x))
48
+ array(accessor)(x)(y);
49
+ else if (typeof x === "object")
30
50
  object(accessor)(x)(y);
31
51
  else if (x !== y)
32
52
  container.push(accessor);
@@ -1 +1 @@
1
- {"version":3,"file":"json_equal_to.js","sourceRoot":"","sources":["../../src/internal/json_equal_to.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"json_equal_to.js","sourceRoot":"","sources":["../../src/internal/json_equal_to.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestia/e2e",
3
- "version": "14.0.1",
3
+ "version": "14.0.2",
4
4
  "description": "E2E test utilify functions",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -44,7 +44,8 @@
44
44
  },
45
45
  "scripts": {
46
46
  "build": "rimraf lib && ttsc",
47
- "dev": "rimraf lib && ttsc --watch"
47
+ "dev": "rimraf lib && ttsc --watch",
48
+ "evidence": "evidence"
48
49
  },
49
50
  "types": "lib/index.d.ts"
50
51
  }
package/src/ArrayUtil.ts CHANGED
@@ -6,16 +6,30 @@
6
6
  * in functional programming style. Functions use direct parameter passing for
7
7
  * simplicity while maintaining functional programming principles.
8
8
  *
9
+ * Processing cost: Sequential array operations visit each required position
10
+ * once; has short-circuits, and subsets materializes the exponential power-set
11
+ * output. Async helpers await one user callback per position and preserve its
12
+ * ordering rather than assuming callbacks are independent.
13
+ *
14
+ * Resource ownership: Async helpers await one callback at a time and keep their
15
+ * input and partial output until settlement; results transfer to the caller.
16
+ * Synchronous helpers retain only their local arrays and recursion state.
17
+ * Callback resources and cancellation belong to the caller.
18
+ *
9
19
  * @author Jeongho Nam - https://github.com/samchon
10
20
  * @example
11
- * ```typescript
12
21
  * // Asynchronous filtering example
13
22
  * const numbers = [1, 2, 3, 4, 5];
14
- * const evenNumbers = await ArrayUtil.asyncFilter(numbers,
15
- * async (num) => num % 2 === 0
23
+ * const evenNumbers = await ArrayUtil.asyncFilter(
24
+ * numbers,
25
+ * async (num) => num % 2 === 0,
16
26
  * );
17
27
  * console.log(evenNumbers); // [2, 4]
18
- * ```;
28
+ *
29
+ * @evidence contracts/common.md#principled-implementation Asynchronous filtering and mapping share sequential `asyncForEach`; repetition awaits each index and collects its results. Synchronous helpers use loops and native methods, and `subsets` enumerates the include or exclude choice per position.
30
+ * @evidence contracts/common.md#clear-and-simple-design Filtering and mapping share iteration without allocating unused results; repetition separately collects its results, with one private count validator.
31
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts No function special-cases a value, a fixture, or a caller; ordering and short-circuiting follow from the loop and the native `some`.
32
+ * @evidence contracts/common.md#meaningful-documentation The namespace prose states the sequential, functional style, and each function documents its parameters, its result, and an example.
19
33
  */
20
34
  export namespace ArrayUtil {
21
35
  /**
@@ -26,28 +40,39 @@ export namespace ArrayUtil {
26
40
  * predicate function receives the element, index, and the full array as
27
41
  * parameters.
28
42
  *
43
+ * Processing cost: Each of N elements invokes its predicate once in sequence;
44
+ * array bookkeeping is O(N), with O(M) output for M accepted elements.
45
+ *
46
+ * Resource ownership: The invocation awaits one callback at a time and
47
+ * retains only its partial output and current call; success transfers the
48
+ * output to the caller and rejection releases local state. Callback-owned
49
+ * external resources remain the callback owner’s responsibility.
50
+ *
29
51
  * @example
30
- * ```typescript
31
52
  * const users = [
32
- * { id: 1, name: 'Alice', active: true },
33
- * { id: 2, name: 'Bob', active: false },
34
- * { id: 3, name: 'Charlie', active: true }
53
+ * { id: 1, name: "Alice", active: true },
54
+ * { id: 2, name: "Bob", active: false },
55
+ * { id: 3, name: "Charlie", active: true },
35
56
  * ];
36
57
  *
37
- * const activeUsers = await ArrayUtil.asyncFilter(users,
58
+ * const activeUsers = await ArrayUtil.asyncFilter(
59
+ * users,
38
60
  * async (user) => {
39
61
  * // Async validation logic (e.g., API call)
40
- * await new Promise(resolve => setTimeout(resolve, 100));
62
+ * await new Promise((resolve) => setTimeout(resolve, 100));
41
63
  * return user.active;
42
- * }
64
+ * },
43
65
  * );
44
66
  * console.log(activeUsers); // [{ id: 1, name: 'Alice', active: true }, { id: 3, name: 'Charlie', active: true }]
45
- * ```;
46
67
  *
47
68
  * @template Input - The type of elements in the input array
48
69
  * @param elements - The readonly array to filter
49
70
  * @param pred - The asynchronous predicate function to test each element
50
71
  * @returns A Promise resolving to the filtered array
72
+ * @evidence contracts/common.md#principled-implementation The predicate runs on each element in order and the next call starts after the previous promise settles; an element is kept only when the awaited result is exactly `true`, which the `Promise<boolean>` type guarantees for well-typed callers, and a rejection stops the iteration and rejects the result.
73
+ * @evidence contracts/common.md#clear-and-simple-design It composes `asyncForEach` with one push instead of reimplementing the loop.
74
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The predicate alone decides inclusion; no element is skipped or retried.
75
+ * @evidence contracts/common.md#meaningful-documentation The comment states the sequential order, the predicate arguments, and the result, with an example.
51
76
  */
52
77
  export const asyncFilter = async <Input>(
53
78
  elements: readonly Input[],
@@ -74,23 +99,33 @@ export namespace ArrayUtil {
74
99
  * performs sequential processing rather than parallel processing, making it
75
100
  * suitable for operations where order matters.
76
101
  *
102
+ * Processing cost: Each of N elements invokes its callback once in sequence:
103
+ * O(N) bookkeeping with no result array.
104
+ *
105
+ * Resource ownership: The invocation retains its input while awaiting one
106
+ * callback at a time, discards callback results and releases local state on
107
+ * completion or rejection. Callback-owned external resources remain the
108
+ * callback owner’s responsibility.
109
+ *
77
110
  * @example
78
- * ```typescript
79
- * const urls = ['url1', 'url2', 'url3'];
111
+ * const urls = ["url1", "url2", "url3"];
80
112
  *
81
113
  * await ArrayUtil.asyncForEach(urls, async (url, index) => {
82
- * console.log(`Processing ${index}: ${url}`);
83
- * const data = await fetch(url);
84
- * await processData(data);
85
- * console.log(`Completed ${index}: ${url}`);
114
+ * console.log(`Processing ${index}: ${url}`);
115
+ * const data = await fetch(url);
116
+ * await processData(data);
117
+ * console.log(`Completed ${index}: ${url}`);
86
118
  * });
87
- * console.log('All URLs processed sequentially');
88
- * ```
119
+ * console.log("All URLs processed sequentially");
89
120
  *
90
121
  * @template Input - The type of elements in the input array
91
122
  * @param elements - The readonly array to process
92
123
  * @param closure - The asynchronous function to execute for each element
93
124
  * @returns A Promise<void> that resolves when all operations complete
125
+ * @evidence contracts/common.md#principled-implementation The initial array length determines the visited indices, and each callback receives the current element, index and original array. Each call is awaited before advancing, so rejection ends iteration and propagates.
126
+ * @evidence contracts/common.md#clear-and-simple-design One sequential loop discards callback results without collecting an unused array.
127
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The closure receives every element exactly once and no error is swallowed.
128
+ * @evidence contracts/common.md#meaningful-documentation The comment contrasts it with the native forEach, states the sequential semantics, and gives an example.
94
129
  */
95
130
  export const asyncForEach = async <Input>(
96
131
  elements: readonly Input[],
@@ -100,9 +135,9 @@ export namespace ArrayUtil {
100
135
  array: readonly Input[],
101
136
  ) => Promise<any>,
102
137
  ): Promise<void> => {
103
- await asyncRepeat(elements.length, (index) =>
104
- closure(elements[index]!, index, elements),
105
- );
138
+ const length: number = elements.length;
139
+ for (let index: number = 0; index < length; ++index)
140
+ await closure(elements[index]!, index, elements);
106
141
  };
107
142
 
108
143
  /**
@@ -111,27 +146,40 @@ export namespace ArrayUtil {
111
146
  *
112
147
  * Similar to JavaScript's native map but processes asynchronous functions
113
148
  * sequentially. Each element's transformation is completed before proceeding
114
- * to the next element, ensuring order is maintained. This function still
115
- * maintains the currying pattern for composition.
149
+ * to the next element, ensuring order is maintained.
150
+ *
151
+ * Processing cost: Each of N elements invokes its mapper once in sequence and
152
+ * stores one result: O(N) bookkeeping and output space.
153
+ *
154
+ * Resource ownership: The invocation awaits one callback at a time and
155
+ * retains only its partial output and current call; success transfers the
156
+ * output to the caller and rejection releases local state. Callback-owned
157
+ * external resources remain the callback owner’s responsibility.
116
158
  *
117
159
  * @example
118
- * ```typescript
119
160
  * const userIds = [1, 2, 3, 4, 5];
120
161
  *
121
- * const userDetails = await ArrayUtil.asyncMap(userIds)(
122
- * async (id, index) => {
123
- * console.log(`Fetching user ${id} (${index + 1}/${userIds.length})`);
124
- * const response = await fetch(`/api/users/${id}`);
125
- * return await response.json();
126
- * }
162
+ * const userDetails = await ArrayUtil.asyncMap(
163
+ * userIds,
164
+ * async (id, index) => {
165
+ * console.log(
166
+ * `Fetching user ${id} (${index + 1}/${userIds.length})`,
167
+ * );
168
+ * const response = await fetch(`/api/users/${id}`);
169
+ * return await response.json();
170
+ * },
127
171
  * );
128
- * console.log('All users fetched:', userDetails);
129
- * ```
172
+ * console.log("All users fetched:", userDetails);
130
173
  *
131
174
  * @template Input - The type of elements in the input array
175
+ * @template Output - The type of elements in the resulting array
132
176
  * @param elements - The readonly array to transform
133
- * @returns A function that takes a transformation function and returns a
134
- * Promise resolving to the transformed array
177
+ * @param closure - The asynchronous function that transforms each element
178
+ * @returns A Promise resolving to the transformed array
179
+ * @evidence contracts/common.md#principled-implementation The closure result of each element is pushed in iteration order, so the output order equals the input order, which holds because the calls are sequential.
180
+ * @evidence contracts/common.md#clear-and-simple-design It composes `asyncForEach` with one push.
181
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Every element is transformed by the caller's closure, with no memoization or skipping.
182
+ * @evidence contracts/common.md#meaningful-documentation The comment states the sequential order and the parameters, and the example calls the two-argument form the function has.
135
183
  */
136
184
  export const asyncMap = async <Input, Output>(
137
185
  elements: readonly Input[],
@@ -156,32 +204,43 @@ export namespace ArrayUtil {
156
204
  * execution is performed sequentially, and all results are collected into an
157
205
  * array.
158
206
  *
207
+ * Processing cost: The callback runs once for each of N indices, in sequence,
208
+ * with O(N) result storage.
209
+ *
210
+ * Resource ownership: The invocation awaits one callback at a time and
211
+ * retains only its partial output and current call; success transfers the
212
+ * output to the caller and rejection releases local state. Callback-owned
213
+ * external resources remain the callback owner’s responsibility.
214
+ *
159
215
  * @example
160
- * ```typescript
161
216
  * // Generate random data 5 times
162
217
  * const randomData = await ArrayUtil.asyncRepeat(5, async (index) => {
163
- * await new Promise(resolve => setTimeout(resolve, 100)); // Wait 0.1 seconds
218
+ * await new Promise((resolve) => setTimeout(resolve, 100)); // Wait 0.1 seconds
164
219
  * return {
165
220
  * id: index,
166
221
  * value: Math.random(),
167
- * timestamp: new Date().toISOString()
222
+ * timestamp: new Date().toISOString(),
168
223
  * };
169
224
  * });
170
- * console.log('Generated data:', randomData);
171
- * ```;
225
+ * console.log("Generated data:", randomData);
172
226
  *
173
227
  * @template T - The type of the result from each execution
174
- * @param count - The number of times to repeat (non-negative integer)
228
+ * @param count - The number of times to repeat (integer from 0 to 2^32 - 1)
175
229
  * @param closure - The asynchronous function to execute repeatedly
176
230
  * @returns A Promise resolving to an array of results
231
+ * @evidence contracts/common.md#principled-implementation A count outside the integer range 0 through 2^32 - 1 is refused with a `RangeError` before any callback, because JavaScript arrays cannot represent a larger length; otherwise the closure is awaited for each index from 0 to count minus one and the results are collected in order, so the cost is linear in the count with no index array.
232
+ * @evidence contracts/common.md#clear-and-simple-design One validation and one loop; the validator is shared with `repeat`.
233
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The loop is the direct implementation of the documented behavior, and an invalid count is an error, not a coerced number.
234
+ * @evidence contracts/common.md#meaningful-documentation The comment states the index range, the sequential execution, and the result, and the count must be a non-negative integer as documented.
177
235
  */
178
236
  export const asyncRepeat = async <T>(
179
237
  count: number,
180
238
  closure: (index: number) => Promise<T>,
181
239
  ): Promise<T[]> => {
182
- const indexes: number[] = new Array(count).fill(1).map((_, index) => index);
240
+ validate("asyncRepeat", count);
183
241
  const output: T[] = [];
184
- for (const index of indexes) output.push(await closure(index));
242
+ for (let index: number = 0; index < count; ++index)
243
+ output.push(await closure(index));
185
244
  return output;
186
245
  };
187
246
 
@@ -191,29 +250,40 @@ export namespace ArrayUtil {
191
250
  * Similar to JavaScript's native some() method. Returns true immediately when
192
251
  * the first element satisfying the condition is found.
193
252
  *
253
+ * Processing cost: Native some stops at the first matching element:
254
+ * worst-case N predicate calls and constant auxiliary storage.
255
+ *
194
256
  * @example
195
- * ```typescript
196
257
  * const numbers = [1, 3, 5, 7, 8, 9];
197
258
  * const products = [
198
- * { name: 'Apple', price: 100, inStock: true },
199
- * { name: 'Banana', price: 50, inStock: false },
200
- * { name: 'Orange', price: 80, inStock: true }
259
+ * { name: "Apple", price: 100, inStock: true },
260
+ * { name: "Banana", price: 50, inStock: false },
261
+ * { name: "Orange", price: 80, inStock: true },
201
262
  * ];
202
263
  *
203
- * const hasEvenNumber = ArrayUtil.has(numbers, num => num % 2 === 0);
264
+ * const hasEvenNumber = ArrayUtil.has(numbers, (num) => num % 2 === 0);
204
265
  * console.log(hasEvenNumber); // true (8 exists)
205
266
  *
206
- * const hasExpensiveItem = ArrayUtil.has(products, product => product.price > 90);
267
+ * const hasExpensiveItem = ArrayUtil.has(
268
+ * products,
269
+ * (product) => product.price > 90,
270
+ * );
207
271
  * console.log(hasExpensiveItem); // true (Apple costs 100)
208
272
  *
209
- * const hasOutOfStock = ArrayUtil.has(products, product => !product.inStock);
273
+ * const hasOutOfStock = ArrayUtil.has(
274
+ * products,
275
+ * (product) => !product.inStock,
276
+ * );
210
277
  * console.log(hasOutOfStock); // true (Banana is out of stock)
211
- * ```;
212
278
  *
213
279
  * @template T - The type of elements in the array
214
280
  * @param elements - The readonly array to check
215
281
  * @param pred - The predicate function to test elements
216
282
  * @returns Boolean indicating if any element satisfies the condition
283
+ * @evidence contracts/common.md#principled-implementation The native `some` implements the existential search and returns at the first satisfying element, and the predicate receives only the element.
284
+ * @evidence contracts/common.md#clear-and-simple-design A one-expression delegation that keeps the native short-circuit visible.
285
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The predicate alone decides membership.
286
+ * @evidence contracts/common.md#meaningful-documentation The comment states the short-circuit and gives examples.
217
287
  */
218
288
  export const has = <T>(
219
289
  elements: readonly T[],
@@ -227,17 +297,19 @@ export namespace ArrayUtil {
227
297
  * A synchronous repetition function that executes the given function for each
228
298
  * index (from 0 to count-1) and collects the results into an array.
229
299
  *
300
+ * Processing cost: The callback runs once for each of N indices, with O(N)
301
+ * output storage.
302
+ *
230
303
  * @example
231
- * ```typescript
232
304
  * // Generate an array of squares from 1 to 5
233
- * const squares = ArrayUtil.repeat(5, index => (index + 1) ** 2);
305
+ * const squares = ArrayUtil.repeat(5, (index) => (index + 1) ** 2);
234
306
  * console.log(squares); // [1, 4, 9, 16, 25]
235
307
  *
236
308
  * // Generate an array of default user objects
237
- * const users = ArrayUtil.repeat(3, index => ({
238
- * id: index + 1,
239
- * name: `User${index + 1}`,
240
- * email: `user${index + 1}@example.com`
309
+ * const users = ArrayUtil.repeat(3, (index) => ({
310
+ * id: index + 1,
311
+ * name: `User${index + 1}`,
312
+ * email: `user${index + 1}@example.com`,
241
313
  * }));
242
314
  * console.log(users);
243
315
  * // [
@@ -245,59 +317,76 @@ export namespace ArrayUtil {
245
317
  * // { id: 2, name: 'User2', email: 'user2@example.com' },
246
318
  * // { id: 3, name: 'User3', email: 'user3@example.com' }
247
319
  * // ]
248
- * ```
249
320
  *
250
321
  * @template T - The type of the result from each execution
251
- * @param count - The number of times to repeat (non-negative integer)
322
+ * @param count - The number of times to repeat (integer from 0 to 2^32 - 1)
252
323
  * @param closure - The function to execute repeatedly
253
324
  * @returns An array of results
325
+ * @evidence contracts/common.md#principled-implementation An invalid count is refused with a `RangeError`, and otherwise the closure is called for each index from 0 to count minus one and the results are collected in order, with cost linear in the count.
326
+ * @evidence contracts/common.md#clear-and-simple-design The synchronous counterpart of `asyncRepeat`, sharing its validator.
327
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The loop implements the documented behavior directly.
328
+ * @evidence contracts/common.md#meaningful-documentation The comment states the index range and the result, with examples.
254
329
  */
255
330
  export const repeat = <T>(
256
331
  count: number,
257
332
  closure: (index: number) => T,
258
- ): T[] => new Array(count).fill("").map((_, index) => closure(index));
333
+ ): T[] => {
334
+ validate("repeat", count);
335
+ const output: T[] = [];
336
+ for (let index: number = 0; index < count; ++index)
337
+ output.push(closure(index));
338
+ return output;
339
+ };
259
340
 
260
341
  /**
261
342
  * Generates all possible subsets of a given array.
262
343
  *
263
344
  * Implements the mathematical concept of power set, generating 2^n subsets
264
345
  * from an array of n elements. Uses depth-first search (DFS) algorithm to
265
- * calculate all possible combinations of including or excluding each
266
- * element.
346
+ * calculate all possible combinations of including or excluding each element.
347
+ * Each element is included before it is excluded, so the first subset is the
348
+ * whole array and the last one is empty.
349
+ *
350
+ * Processing cost: The DFS visits the include/exclude tree and filters N
351
+ * input positions at each of 2^N leaves. This is O(N 2^N) time and
352
+ * materialized output space, the scale required by returning every subset,
353
+ * with O(N) recursion/mask state.
267
354
  *
268
355
  * @example
269
- * ```typescript
270
356
  * const numbers = [1, 2, 3];
271
357
  * const allSubsets = ArrayUtil.subsets(numbers);
272
358
  * console.log(allSubsets);
273
359
  * // [
274
- * // [], // empty set
275
- * // [3], // {3}
276
- * // [2], // {2}
277
- * // [2, 3], // {2, 3}
278
- * // [1], // {1}
279
- * // [1, 3], // {1, 3}
360
+ * // [1, 2, 3], // {1, 2, 3}
280
361
  * // [1, 2], // {1, 2}
281
- * // [1, 2, 3] // {1, 2, 3}
362
+ * // [1, 3], // {1, 3}
363
+ * // [1], // {1}
364
+ * // [2, 3], // {2, 3}
365
+ * // [2], // {2}
366
+ * // [3], // {3}
367
+ * // [] // empty set
282
368
  * // ]
283
369
  *
284
- * const colors = ['red', 'blue'];
370
+ * const colors = ["red", "blue"];
285
371
  * const colorSubsets = ArrayUtil.subsets(colors);
286
372
  * console.log(colorSubsets);
287
373
  * // [
288
- * // [],
289
- * // ['blue'],
374
+ * // ['red', 'blue'],
290
375
  * // ['red'],
291
- * // ['red', 'blue']
376
+ * // ['blue'],
377
+ * // []
292
378
  * // ]
293
379
  *
294
380
  * // Warning: Result size grows exponentially with array size
295
381
  * // Example: 10 elements → 1,024 subsets, 20 elements → 1,048,576 subsets
296
- * ```;
297
382
  *
298
383
  * @template T - The type of elements in the array
299
384
  * @param array - The array to generate subsets from
300
385
  * @returns An array containing all possible subsets
386
+ * @evidence contracts/common.md#principled-implementation A depth-first search decides for each position whether the element is in the subset, including it first, and each leaf materializes the chosen elements with `filter`, so the 2^n subsets appear in a fixed order, the whole array first and the empty array last; the recursion depth is the array length and the output size is exponential, which bounds the useful input size.
387
+ * @evidence contracts/common.md#clear-and-simple-design One recursive function over a mask, with no options.
388
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It enumerates every subset without sampling or a size cap, and the array is not mutated.
389
+ * @evidence contracts/common.md#meaningful-documentation The comment states the power-set meaning, the exact enumeration order, and the exponential growth warning, and the examples show that order.
301
390
  */
302
391
  export const subsets = <T>(array: T[]): T[][] => {
303
392
  const check: boolean[] = new Array(array.length).fill(false);
@@ -317,4 +406,11 @@ export namespace ArrayUtil {
317
406
  dfs(0);
318
407
  return output;
319
408
  };
409
+
410
+ const validate = (method: string, count: number): void => {
411
+ if (!Number.isSafeInteger(count) || count < 0 || count > 0xffffffff)
412
+ throw new RangeError(
413
+ `ArrayUtil.${method}(): count must be a non-negative integer.`,
414
+ );
415
+ };
320
416
  }