@rimbu/deep 0.14.5 → 1.0.0-alpha.1

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 (86) hide show
  1. package/{src/deep.ts → dist/bun/deep.mts} +7 -7
  2. package/{src/index.ts → dist/bun/index.mts} +5 -5
  3. package/dist/bun/internal.mts +8 -0
  4. package/{src/match.ts → dist/bun/match.mts} +6 -6
  5. package/{src/patch.ts → dist/bun/patch.mts} +9 -4
  6. package/{src/path.ts → dist/bun/path.mts} +2 -2
  7. package/{src/selector.ts → dist/bun/selector.mts} +1 -1
  8. package/dist/cjs/deep.js +590 -0
  9. package/dist/cjs/index.js +663 -0
  10. package/dist/cjs/internal.js +583 -0
  11. package/dist/cjs/match.js +376 -0
  12. package/dist/cjs/patch.js +105 -0
  13. package/dist/cjs/path.js +585 -0
  14. package/dist/cjs/protected.js +18 -0
  15. package/dist/cjs/selector.js +581 -0
  16. package/dist/cjs/tuple.js +73 -0
  17. package/dist/{module/deep.js → esm/deep.mjs} +6 -6
  18. package/dist/esm/deep.mjs.map +1 -0
  19. package/dist/{module/index.js → esm/index.mjs} +5 -5
  20. package/dist/esm/index.mjs.map +1 -0
  21. package/dist/esm/internal.mjs +5 -0
  22. package/dist/esm/internal.mjs.map +1 -0
  23. package/dist/{module/match.js → esm/match.mjs} +21 -21
  24. package/dist/esm/match.mjs.map +1 -0
  25. package/dist/{module/patch.js → esm/patch.mjs} +5 -5
  26. package/dist/esm/patch.mjs.map +1 -0
  27. package/dist/{module/path.js → esm/path.mjs} +2 -2
  28. package/dist/esm/path.mjs.map +1 -0
  29. package/dist/esm/protected.mjs +2 -0
  30. package/dist/esm/protected.mjs.map +1 -0
  31. package/dist/{module/selector.js → esm/selector.mjs} +2 -2
  32. package/dist/esm/selector.mjs.map +1 -0
  33. package/dist/{module/tuple.js → esm/tuple.mjs} +1 -1
  34. package/dist/esm/tuple.mjs.map +1 -0
  35. package/dist/types/{deep.d.ts → deep.d.mts} +6 -6
  36. package/dist/types/{index.d.ts → index.d.mts} +5 -5
  37. package/dist/types/internal.d.mts +7 -0
  38. package/dist/types/{match.d.ts → match.d.mts} +3 -3
  39. package/dist/types/{patch.d.ts → patch.d.mts} +3 -3
  40. package/dist/types/{path.d.ts → path.d.mts} +2 -2
  41. package/dist/types/{selector.d.ts → selector.d.mts} +1 -1
  42. package/package.json +29 -23
  43. package/src/deep.mts +364 -0
  44. package/src/index.mts +23 -0
  45. package/src/internal.mts +8 -0
  46. package/src/match.mts +700 -0
  47. package/src/patch.mts +262 -0
  48. package/src/path.mts +430 -0
  49. package/src/protected.mts +30 -0
  50. package/src/selector.mts +90 -0
  51. package/src/tuple.mts +197 -0
  52. package/dist/main/deep.js +0 -211
  53. package/dist/main/deep.js.map +0 -1
  54. package/dist/main/index.js +0 -19
  55. package/dist/main/index.js.map +0 -1
  56. package/dist/main/internal.js +0 -9
  57. package/dist/main/internal.js.map +0 -1
  58. package/dist/main/match.js +0 -284
  59. package/dist/main/match.js.map +0 -1
  60. package/dist/main/patch.js +0 -133
  61. package/dist/main/patch.js.map +0 -1
  62. package/dist/main/path.js +0 -126
  63. package/dist/main/path.js.map +0 -1
  64. package/dist/main/protected.js +0 -3
  65. package/dist/main/protected.js.map +0 -1
  66. package/dist/main/selector.js +0 -40
  67. package/dist/main/selector.js.map +0 -1
  68. package/dist/main/tuple.js +0 -164
  69. package/dist/main/tuple.js.map +0 -1
  70. package/dist/module/deep.js.map +0 -1
  71. package/dist/module/index.js.map +0 -1
  72. package/dist/module/internal.js +0 -4
  73. package/dist/module/internal.js.map +0 -1
  74. package/dist/module/match.js.map +0 -1
  75. package/dist/module/patch.js.map +0 -1
  76. package/dist/module/path.js.map +0 -1
  77. package/dist/module/protected.js +0 -2
  78. package/dist/module/protected.js.map +0 -1
  79. package/dist/module/selector.js.map +0 -1
  80. package/dist/module/tuple.js.map +0 -1
  81. package/dist/types/internal.d.ts +0 -7
  82. package/src/internal.ts +0 -8
  83. /package/{src/protected.ts → dist/bun/protected.mts} +0 -0
  84. /package/{src/tuple.ts → dist/bun/tuple.mts} +0 -0
  85. /package/dist/types/{protected.d.ts → protected.d.mts} +0 -0
  86. /package/dist/types/{tuple.d.ts → tuple.d.mts} +0 -0
package/src/match.mts ADDED
@@ -0,0 +1,700 @@
1
+ import {
2
+ type IsAnyFunc,
3
+ type IsArray,
4
+ isPlainObj,
5
+ type IsPlainObj,
6
+ type NotIterable,
7
+ } from '@rimbu/base';
8
+ import type { Protected } from './internal.mjs';
9
+ import type { Tuple } from './tuple.mjs';
10
+
11
+ /**
12
+ * The type to determine the allowed input values for the `match` function.
13
+ * @typeparam T - the type of value to match
14
+ * @typeparam C - utility type
15
+ */
16
+ export type Match<T, C extends Partial<T> = Partial<T>> = Match.Entry<
17
+ T,
18
+ C,
19
+ T,
20
+ T
21
+ >;
22
+
23
+ export namespace Match {
24
+ /**
25
+ * Determines the various allowed match types for given type `T`.
26
+ * @typeparam T - the input value type
27
+ * @typeparam C - utility type
28
+ * @typeparam P - the parent type
29
+ * @typeparam R - the root object type
30
+ */
31
+ export type Entry<T, C, P, R> = IsAnyFunc<T> extends true
32
+ ? // function can only be directly matched
33
+ T
34
+ : IsPlainObj<T> extends true
35
+ ? // determine allowed match values for object
36
+ Match.WithResult<T, P, R, Match.Obj<T, C, P, R>>
37
+ : IsArray<T> extends true
38
+ ? // determine allowed match values for array or tuple
39
+ | Match.Arr<T, C, P, R>
40
+ | Match.Entry<T[number & keyof T], C[number & keyof C], P, R>[]
41
+ | Match.Func<
42
+ T,
43
+ P,
44
+ R,
45
+ | Match.Arr<T, C, P, R>
46
+ | Match.Entry<T[number & keyof T], C[number & keyof C], P, R>[]
47
+ >
48
+ : // only accept values with same interface
49
+ Match.WithResult<T, P, R, { [K in keyof C]: C[K & keyof T] }>;
50
+
51
+ /**
52
+ * The type that determines allowed matchers for objects.
53
+ * @typeparam T - the input value type
54
+ * @typeparam C - utility type
55
+ * @typeparam P - the parent type
56
+ * @typeparam R - the root object type
57
+ */
58
+ export type Obj<T, C, P, R> =
59
+ | Match.ObjProps<T, C, R>
60
+ | Match.CompoundForObj<T, C, P, R>;
61
+
62
+ /**
63
+ * The type to determine allowed matchers for object properties.
64
+ * @typeparam T - the input value type
65
+ * @typeparam C - utility type
66
+ * @typeparam R - the root object type
67
+ */
68
+ export type ObjProps<T, C, R> = {
69
+ [K in keyof C]?: K extends keyof T ? Match.Entry<T[K], C[K], T, R> : never;
70
+ };
71
+
72
+ /**
73
+ * The type that determines allowed matchers for arrays/tuples.
74
+ * @typeparam T - the input value type
75
+ * @typeparam C - utility type
76
+ * @typeparam P - the parent type
77
+ * @typeparam R - the root object type
78
+ */
79
+ export type Arr<T, C, P, R> =
80
+ | C
81
+ | Match.CompoundForArr<T, C, P, R>
82
+ | Match.TraversalForArr<T, C, R>
83
+ | (Match.TupIndices<T, C, R> & {
84
+ [K in Match.CompoundType | Match.ArrayTraversalType]?: never;
85
+ });
86
+
87
+ /**
88
+ * A type that either directly results in result type `S` or is a function taking the value, parent, and root values, and
89
+ * returns a value of type `S`.
90
+ * @typeparam T - the input value type
91
+ * @typeparam P - the parent type
92
+ * @typeparam R - the root object type
93
+ * @typeparam S - the result type
94
+ */
95
+ export type WithResult<T, P, R, S> = S | Match.Func<T, P, R, S>;
96
+
97
+ /**
98
+ * Type used to determine the allowed function types. Always includes booleans.
99
+ * @typeparam T - the input value type
100
+ * @typeparam P - the parent type
101
+ * @typeparam R - the root object type
102
+ * @typeparam S - the allowed return value type
103
+ */
104
+ export type Func<T, P, R, S> = (
105
+ current: Protected<T>,
106
+ parent: Protected<P>,
107
+ root: Protected<R>
108
+ ) => boolean | S;
109
+
110
+ /**
111
+ * Type used to indicate an object containing matches for tuple indices.
112
+ * @typeparam T - the input value type
113
+ * @typeparam C - utility type
114
+ * @typeparam R - the root object type
115
+ */
116
+ export type TupIndices<T, C, R> = {
117
+ [K in Tuple.KeysOf<C>]?: Match.Entry<T[K & keyof T], C[K], T, R>;
118
+ } & NotIterable;
119
+
120
+ /**
121
+ * Compound keys used to indicate the type of compound.
122
+ */
123
+ export type CompoundType = 'every' | 'some' | 'none' | 'single';
124
+
125
+ /**
126
+ * Keys used to indicate an array match traversal.
127
+ */
128
+ export type ArrayTraversalType = `${CompoundType}Item`;
129
+
130
+ /**
131
+ * Compount matcher for objects, can only be an array staring with a compound type keyword.
132
+ * @typeparam T - the input value type
133
+ * @typeparam C - utility type
134
+ * @typeparam P - the parent type
135
+ * @typeparam R - the root object type
136
+ */
137
+ export type CompoundForObj<T, C, P, R> = [
138
+ Match.CompoundType,
139
+ ...Match.Entry<T, C, P, R>[]
140
+ ];
141
+
142
+ /**
143
+ * Defines an object containing exactly one `CompoundType` key, having an array of matchers.
144
+ * @typeparam T - the input value type
145
+ * @typeparam C - utility type
146
+ * @typeparam P - the parent type
147
+ * @typeparam R - the root object type
148
+ */
149
+ export type CompoundForArr<T, C, P, R> = {
150
+ [K in Match.CompoundType]: {
151
+ [K2 in Match.CompoundType]?: K2 extends K
152
+ ? Match.Entry<T, C, P, R>[]
153
+ : never;
154
+ };
155
+ }[Match.CompoundType];
156
+
157
+ /**
158
+ * Defines an object containing exactly one `TraversalType` key, having a matcher for the array element type.
159
+ * @typeparam T - the input value type
160
+ * @typeparam C - utility type
161
+ * @typeparam R - the root object type
162
+ */
163
+ export type TraversalForArr<T, C, R> = {
164
+ [K in Match.ArrayTraversalType]: {
165
+ [K2 in Match.ArrayTraversalType]?: K2 extends K
166
+ ? Match.Entry<T[number & keyof T], C[number & keyof C], T, R>
167
+ : never;
168
+ };
169
+ }[Match.ArrayTraversalType];
170
+
171
+ /**
172
+ * Utility type for collecting match failure reasons
173
+ */
174
+ export type FailureLog = string[];
175
+ }
176
+
177
+ /**
178
+ * Returns true if the given `value` object matches the given `matcher`, false otherwise.
179
+ * @typeparam T - the input value type
180
+ * @typeparam C - utility type
181
+ * @param source - the value to match (should be a plain object)
182
+ * @param matcher - a matcher object or a function taking the matcher API and returning a match object
183
+ * @param failureLog - (optional) a string array that can be passed to collect reasons why the match failed
184
+ * @example
185
+ * ```ts
186
+ * const input = { a: 1, b: { c: true, d: 'a' } }
187
+ * match(input, { a: 1 }) // => true
188
+ * match(input, { a: 2 }) // => false
189
+ * match(input, { a: (v) => v > 10 }) // => false
190
+ * match(input, { b: { c: true }}) // => true
191
+ * match(input, (['every', { a: (v) => v > 0 }, { b: { c: true } }]) // => true
192
+ * match(input, { b: { c: (v, parent, root) => v && parent.d.length > 0 && root.a > 0 } })
193
+ * // => true
194
+ * ```
195
+ */
196
+ export function match<T, C extends Partial<T> = Partial<T>>(
197
+ source: T,
198
+ matcher: Match<T, C>,
199
+ failureLog?: Match.FailureLog
200
+ ): boolean {
201
+ return matchEntry(source, source, source, matcher as any, failureLog);
202
+ }
203
+
204
+ /**
205
+ * Match a generic match entry against the given source.
206
+ */
207
+ function matchEntry<T, C, P, R>(
208
+ source: T,
209
+ parent: P,
210
+ root: R,
211
+ matcher: Match.Entry<T, C, P, R>,
212
+ failureLog?: Match.FailureLog
213
+ ): boolean {
214
+ if (Object.is(source, matcher)) {
215
+ // value and target are exactly the same, always will be true
216
+ return true;
217
+ }
218
+
219
+ if (matcher === null || matcher === undefined) {
220
+ // these matchers can only be direct matches, and previously it was determined that
221
+ // they are not equal
222
+ failureLog?.push(
223
+ `value ${JSON.stringify(source)} did not match matcher ${matcher}`
224
+ );
225
+
226
+ return false;
227
+ }
228
+
229
+ if (typeof source === 'function') {
230
+ // function source values can only be directly matched
231
+ const result = Object.is(source, matcher);
232
+
233
+ if (!result) {
234
+ failureLog?.push(
235
+ `both value and matcher are functions, but they do not have the same reference`
236
+ );
237
+ }
238
+
239
+ return result;
240
+ }
241
+
242
+ if (typeof matcher === 'function') {
243
+ // resolve match function first
244
+ const matcherResult = matcher(source, parent, root);
245
+
246
+ if (typeof matcherResult === 'boolean') {
247
+ // function resulted in a direct match result
248
+
249
+ if (!matcherResult) {
250
+ failureLog?.push(
251
+ `function matcher returned false for value ${JSON.stringify(source)}`
252
+ );
253
+ }
254
+
255
+ return matcherResult;
256
+ }
257
+
258
+ // function resulted in a value that needs to be further matched
259
+ return matchEntry(source, parent, root, matcherResult, failureLog);
260
+ }
261
+
262
+ if (isPlainObj(source)) {
263
+ // source ia a plain object, can be partially matched
264
+ return matchPlainObj(source, parent, root, matcher as any, failureLog);
265
+ }
266
+
267
+ if (Array.isArray(source)) {
268
+ // source is an array
269
+ return matchArr(source, parent, root, matcher as any, failureLog);
270
+ }
271
+
272
+ // already determined above that the source and matcher are not equal
273
+
274
+ failureLog?.push(
275
+ `value ${JSON.stringify(
276
+ source
277
+ )} does not match given matcher ${JSON.stringify(matcher)}`
278
+ );
279
+
280
+ return false;
281
+ }
282
+
283
+ /**
284
+ * Match an array matcher against the given source.
285
+ */
286
+ function matchArr<T extends any[], C, P, R>(
287
+ source: T,
288
+ parent: P,
289
+ root: R,
290
+ matcher: Match.Arr<T, C, P, R>,
291
+ failureLog?: Match.FailureLog
292
+ ): boolean {
293
+ if (Array.isArray(matcher)) {
294
+ // directly compare array contents
295
+ const length = source.length;
296
+
297
+ if (length !== matcher.length) {
298
+ // if lengths not equal, arrays are not equal
299
+
300
+ failureLog?.push(
301
+ `array lengths are not equal: value length ${source.length} !== matcher length ${matcher.length}`
302
+ );
303
+
304
+ return false;
305
+ }
306
+
307
+ // loop over arrays, matching every value
308
+ let index = -1;
309
+ while (++index < length) {
310
+ if (
311
+ !matchEntry(source[index], source, root, matcher[index], failureLog)
312
+ ) {
313
+ // item did not match, return false
314
+
315
+ failureLog?.push(
316
+ `index ${index} does not match with value ${JSON.stringify(
317
+ source[index]
318
+ )} and matcher ${matcher[index]}`
319
+ );
320
+
321
+ return false;
322
+ }
323
+ }
324
+
325
+ // all items are equal
326
+ return true;
327
+ }
328
+
329
+ // matcher is plain object
330
+
331
+ if (typeof matcher === 'object' && null !== matcher) {
332
+ if (`every` in matcher) {
333
+ return matchCompound(
334
+ source,
335
+ parent,
336
+ root,
337
+ ['every', ...(matcher.every as any)],
338
+ failureLog
339
+ );
340
+ }
341
+ if (`some` in matcher) {
342
+ return matchCompound(
343
+ source,
344
+ parent,
345
+ root,
346
+ ['some', ...(matcher.some as any)],
347
+ failureLog
348
+ );
349
+ }
350
+ if (`none` in matcher) {
351
+ return matchCompound(
352
+ source,
353
+ parent,
354
+ root,
355
+ ['none', ...(matcher.none as any)],
356
+ failureLog
357
+ );
358
+ }
359
+ if (`single` in matcher) {
360
+ return matchCompound(
361
+ source,
362
+ parent,
363
+ root,
364
+ ['single', ...(matcher.single as any)],
365
+ failureLog
366
+ );
367
+ }
368
+ if (`someItem` in matcher) {
369
+ return matchTraversal(
370
+ source,
371
+ root,
372
+ 'someItem',
373
+ matcher.someItem as any,
374
+ failureLog
375
+ );
376
+ }
377
+ if (`everyItem` in matcher) {
378
+ return matchTraversal(
379
+ source,
380
+ root,
381
+ 'everyItem',
382
+ matcher.everyItem as any,
383
+ failureLog
384
+ );
385
+ }
386
+ if (`noneItem` in matcher) {
387
+ return matchTraversal(
388
+ source,
389
+ root,
390
+ 'noneItem',
391
+ matcher.noneItem as any,
392
+ failureLog
393
+ );
394
+ }
395
+ if (`singleItem` in matcher) {
396
+ return matchTraversal(
397
+ source,
398
+ root,
399
+ 'singleItem',
400
+ matcher.singleItem as any,
401
+ failureLog
402
+ );
403
+ }
404
+ }
405
+
406
+ // matcher is plain object with index keys
407
+
408
+ for (const index in matcher as any) {
409
+ const matcherAtIndex = (matcher as any)[index];
410
+
411
+ if (!(index in source)) {
412
+ // source does not have item at given index
413
+
414
+ failureLog?.push(
415
+ `index ${index} does not exist in source ${JSON.stringify(
416
+ source
417
+ )} but should match matcher ${JSON.stringify(matcherAtIndex)}`
418
+ );
419
+
420
+ return false;
421
+ }
422
+
423
+ // match the source item at the given index
424
+ const result = matchEntry(
425
+ (source as any)[index],
426
+ source,
427
+ root,
428
+ matcherAtIndex,
429
+ failureLog
430
+ );
431
+
432
+ if (!result) {
433
+ // item did not match
434
+
435
+ failureLog?.push(
436
+ `index ${index} does not match with value ${JSON.stringify(
437
+ (source as any)[index]
438
+ )} and matcher ${JSON.stringify(matcherAtIndex)}`
439
+ );
440
+
441
+ return false;
442
+ }
443
+ }
444
+
445
+ // all items match
446
+
447
+ return true;
448
+ }
449
+
450
+ /**
451
+ * Match an object matcher against the given source.
452
+ */
453
+ function matchPlainObj<T extends object, C, P, R>(
454
+ source: T,
455
+ parent: P,
456
+ root: R,
457
+ matcher: Match.Obj<T, C, P, R>,
458
+ failureLog?: Match.FailureLog
459
+ ): boolean {
460
+ if (Array.isArray(matcher)) {
461
+ // the matcher is of compound type
462
+ return matchCompound(source, parent, root, matcher as any, failureLog);
463
+ }
464
+
465
+ // partial object props matcher
466
+
467
+ for (const key in matcher) {
468
+ if (!(key in source)) {
469
+ // the source does not have the given key
470
+
471
+ failureLog?.push(
472
+ `key ${key} is specified in matcher but not present in value ${JSON.stringify(
473
+ source
474
+ )}`
475
+ );
476
+
477
+ return false;
478
+ }
479
+
480
+ // match the source value at the given key with the matcher at given key
481
+ const result = matchEntry(
482
+ (source as any)[key],
483
+ source,
484
+ root,
485
+ matcher[key],
486
+ failureLog
487
+ );
488
+
489
+ if (!result) {
490
+ failureLog?.push(
491
+ `key ${key} does not match in value ${JSON.stringify(
492
+ (source as any)[key]
493
+ )} with matcher ${JSON.stringify(matcher[key])}`
494
+ );
495
+ return false;
496
+ }
497
+ }
498
+
499
+ // all properties match
500
+
501
+ return true;
502
+ }
503
+
504
+ /**
505
+ * Match a compound matcher against the given source.
506
+ */
507
+ function matchCompound<T, C, P, R>(
508
+ source: T,
509
+ parent: P,
510
+ root: R,
511
+ compound: [Match.CompoundType, ...Match.Entry<T, C, P, R>[]],
512
+ failureLog?: Match.FailureLog
513
+ ): boolean {
514
+ // first item indicates compound match type
515
+ const matchType = compound[0];
516
+
517
+ const length = compound.length;
518
+
519
+ // start at index 1
520
+ let index = 0;
521
+
522
+ type Entry = Match.Entry<T, C, P, R>;
523
+
524
+ switch (matchType) {
525
+ case 'every': {
526
+ while (++index < length) {
527
+ // if any item does not match, return false
528
+ const result = matchEntry(
529
+ source,
530
+ parent,
531
+ root,
532
+ compound[index] as Entry,
533
+ failureLog
534
+ );
535
+
536
+ if (!result) {
537
+ failureLog?.push(
538
+ `in compound "every": match at index ${index} failed`
539
+ );
540
+
541
+ return false;
542
+ }
543
+ }
544
+
545
+ return true;
546
+ }
547
+ case 'none': {
548
+ // if any item matches, return false
549
+ while (++index < length) {
550
+ const result = matchEntry(
551
+ source,
552
+ parent,
553
+ root,
554
+ compound[index] as Entry,
555
+ failureLog
556
+ );
557
+
558
+ if (result) {
559
+ failureLog?.push(
560
+ `in compound "none": match at index ${index} succeeded`
561
+ );
562
+
563
+ return false;
564
+ }
565
+ }
566
+
567
+ return true;
568
+ }
569
+ case 'single': {
570
+ // if not exactly one item matches, return false
571
+ let onePassed = false;
572
+
573
+ while (++index < length) {
574
+ const result = matchEntry(
575
+ source,
576
+ parent,
577
+ root,
578
+ compound[index] as Entry,
579
+ failureLog
580
+ );
581
+
582
+ if (result) {
583
+ if (onePassed) {
584
+ failureLog?.push(
585
+ `in compound "single": multiple matches succeeded`
586
+ );
587
+
588
+ return false;
589
+ }
590
+
591
+ onePassed = true;
592
+ }
593
+ }
594
+
595
+ if (!onePassed) {
596
+ failureLog?.push(`in compound "single": no matches succeeded`);
597
+ }
598
+
599
+ return onePassed;
600
+ }
601
+ case 'some': {
602
+ // if any item matches, return true
603
+ while (++index < length) {
604
+ const result = matchEntry(
605
+ source,
606
+ parent,
607
+ root,
608
+ compound[index] as Entry,
609
+ failureLog
610
+ );
611
+
612
+ if (result) {
613
+ return true;
614
+ }
615
+ }
616
+
617
+ failureLog?.push(`in compound "some": no matches succeeded`);
618
+
619
+ return false;
620
+ }
621
+ }
622
+ }
623
+
624
+ function matchTraversal<T extends any[], C extends any[], R>(
625
+ source: T,
626
+ root: R,
627
+ matchType: Match.ArrayTraversalType,
628
+ matcher: Match.Entry<T[keyof T], C[keyof C], T, R>,
629
+ failureLog?: Match.FailureLog
630
+ ): boolean {
631
+ let index = -1;
632
+ const length = source.length;
633
+
634
+ switch (matchType) {
635
+ case 'someItem': {
636
+ while (++index < length) {
637
+ if (matchEntry(source[index], source, root, matcher, failureLog)) {
638
+ return true;
639
+ }
640
+ }
641
+
642
+ failureLog?.push(
643
+ `in array traversal "someItem": no items matched given matcher`
644
+ );
645
+
646
+ return false;
647
+ }
648
+ case 'everyItem': {
649
+ while (++index < length) {
650
+ if (!matchEntry(source[index], source, root, matcher, failureLog)) {
651
+ failureLog?.push(
652
+ `in array traversal "everyItem": at least one item did not match given matcher`
653
+ );
654
+ return false;
655
+ }
656
+ }
657
+
658
+ return true;
659
+ }
660
+ case 'noneItem': {
661
+ while (++index < length) {
662
+ if (matchEntry(source[index], source, root, matcher, failureLog)) {
663
+ failureLog?.push(
664
+ `in array traversal "noneItem": at least one item matched given matcher`
665
+ );
666
+ return false;
667
+ }
668
+ }
669
+
670
+ return true;
671
+ }
672
+ case 'singleItem': {
673
+ let singleMatched = false;
674
+
675
+ while (++index < length) {
676
+ if (matchEntry(source[index], source, root, matcher, failureLog)) {
677
+ if (singleMatched) {
678
+ failureLog?.push(
679
+ `in array traversal "singleItem": more than one item matched given matcher`
680
+ );
681
+
682
+ return false;
683
+ }
684
+
685
+ singleMatched = true;
686
+ }
687
+ }
688
+
689
+ if (!singleMatched) {
690
+ failureLog?.push(
691
+ `in array traversal "singleItem": no item matched given matcher`
692
+ );
693
+
694
+ return false;
695
+ }
696
+
697
+ return true;
698
+ }
699
+ }
700
+ }