quetch 0.30.0 → 0.31.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 (171) hide show
  1. package/dist/tools/comparatorFieldValues.d.ts +8 -0
  2. package/dist/tools/comparatorFieldValues.js +26 -0
  3. package/dist/tools/comparatorFieldValues.js.map +1 -0
  4. package/dist/tools/filterChildren.d.ts +2 -1
  5. package/dist/tools/filterChildren.js +3 -2
  6. package/dist/tools/filterChildren.js.map +1 -1
  7. package/dist/tools/get.d.ts +4 -4
  8. package/dist/tools/get.js +6 -2
  9. package/dist/tools/get.js.map +1 -1
  10. package/dist/tools/querySettings.d.ts +8 -0
  11. package/dist/tools/querySettings.js +16 -0
  12. package/dist/tools/querySettings.js.map +1 -0
  13. package/dist/tools/sortItemList.d.ts +4 -4
  14. package/dist/tools/sortItemList.js +17 -24
  15. package/dist/tools/sortItemList.js.map +1 -1
  16. package/dist/tools/testFilter.js +1 -2
  17. package/dist/tools/testFilter.js.map +1 -1
  18. package/dist/tools/transformerFilterChildren.d.ts +2 -22
  19. package/dist/tools/transformerFilterChildren.js +2 -5
  20. package/dist/tools/transformerFilterChildren.js.map +1 -1
  21. package/dist/tools.d.ts +2 -0
  22. package/dist/tools.js +2 -0
  23. package/dist/tools.js.map +1 -1
  24. package/dist/types/CombineUnion.d.ts +1 -1
  25. package/dist/types/Decrement.d.ts +4 -0
  26. package/dist/types/Decrement.js +1 -0
  27. package/dist/types/Decrement.js.map +1 -0
  28. package/dist/types/DepthLimit.d.ts +1 -0
  29. package/dist/types/DepthLimit.js +1 -0
  30. package/dist/types/DepthLimit.js.map +1 -0
  31. package/dist/types/FieldKey.d.ts +2 -1
  32. package/dist/types/Get.d.ts +3 -1
  33. package/dist/types/KeyFiltered.d.ts +1 -1
  34. package/dist/types/NormalizedPathFieldSettings.d.ts +24 -0
  35. package/dist/types/NormalizedPathFieldSettings.js +1 -0
  36. package/dist/types/NormalizedPathFieldSettings.js.map +1 -0
  37. package/dist/types/Path.d.ts +4 -3
  38. package/dist/types/PathFiltered.d.ts +4 -3
  39. package/dist/types/QuerySettings.d.ts +12 -17
  40. package/dist/types.d.ts +3 -1
  41. package/doc/README.md +5 -1
  42. package/doc/classes/RequestError.md +5 -5
  43. package/doc/functions/aggregate.md +1 -1
  44. package/doc/functions/branch.md +1 -1
  45. package/doc/functions/cache.md +1 -1
  46. package/doc/functions/combine.md +1 -1
  47. package/doc/functions/comparatorFieldValues.md +33 -0
  48. package/doc/functions/cork.md +1 -1
  49. package/doc/functions/defineCheckQuery.md +1 -1
  50. package/doc/functions/defineCustomFetch.md +1 -1
  51. package/doc/functions/defineGenericFetch.md +1 -1
  52. package/doc/functions/escapeRegex.md +1 -1
  53. package/doc/functions/fetchExternal.md +1 -1
  54. package/doc/functions/fetchLocal.md +1 -1
  55. package/doc/functions/fieldListFromFilter.md +1 -1
  56. package/doc/functions/filterChildren.md +8 -2
  57. package/doc/functions/filterFromValue.md +1 -1
  58. package/doc/functions/get.md +2 -2
  59. package/doc/functions/groupFilters.md +1 -1
  60. package/doc/functions/identity.md +1 -1
  61. package/doc/functions/intrinsicFilter.md +1 -1
  62. package/doc/functions/isFilterGroup.md +1 -1
  63. package/doc/functions/log.md +1 -1
  64. package/doc/functions/normalizeOrder.md +1 -1
  65. package/doc/functions/queryItemList.md +1 -1
  66. package/doc/functions/querySettings.md +33 -0
  67. package/doc/functions/retry.md +1 -1
  68. package/doc/functions/reverseOrder.md +1 -1
  69. package/doc/functions/sameField.md +1 -1
  70. package/doc/functions/sortItemList.md +2 -2
  71. package/doc/functions/splitPath.md +2 -2
  72. package/doc/functions/testFilter.md +1 -1
  73. package/doc/functions/transformerFilterChildren.md +2 -2
  74. package/doc/interfaces/CustomFetch.md +1 -1
  75. package/doc/type-aliases/AggregateFunction.md +1 -1
  76. package/doc/type-aliases/AggregateFunctionOperator.md +1 -1
  77. package/doc/type-aliases/CombineUnion.md +2 -2
  78. package/doc/type-aliases/Context.md +1 -1
  79. package/doc/type-aliases/CustomFieldAggregateMap.md +1 -1
  80. package/doc/type-aliases/CustomFieldMap.md +1 -1
  81. package/doc/type-aliases/Decrement.md +17 -0
  82. package/doc/type-aliases/DepthLimit.md +13 -0
  83. package/doc/type-aliases/Field.md +1 -1
  84. package/doc/type-aliases/FieldFiltered.md +1 -1
  85. package/doc/type-aliases/FieldFunction.md +1 -1
  86. package/doc/type-aliases/FieldFunctionCustom.md +1 -1
  87. package/doc/type-aliases/FieldFunctionFormatDate.md +1 -1
  88. package/doc/type-aliases/FieldFunctionReturn.md +1 -1
  89. package/doc/type-aliases/FieldKey.md +2 -2
  90. package/doc/type-aliases/FieldMap.md +1 -1
  91. package/doc/type-aliases/Filter.md +1 -1
  92. package/doc/type-aliases/FilterArray.md +1 -1
  93. package/doc/type-aliases/FilterBoolean.md +1 -1
  94. package/doc/type-aliases/FilterChildren.md +1 -1
  95. package/doc/type-aliases/FilterCustom.md +1 -1
  96. package/doc/type-aliases/FilterField.md +1 -1
  97. package/doc/type-aliases/FilterGroup.md +1 -1
  98. package/doc/type-aliases/FilterNumber.md +1 -1
  99. package/doc/type-aliases/FilterOperator.md +1 -1
  100. package/doc/type-aliases/FilterString.md +1 -1
  101. package/doc/type-aliases/FilterStringIntersect.md +1 -1
  102. package/doc/type-aliases/FilterStringMatch.md +1 -1
  103. package/doc/type-aliases/Get.md +5 -3
  104. package/doc/type-aliases/Group.md +1 -1
  105. package/doc/type-aliases/Handler.md +1 -1
  106. package/doc/type-aliases/Immutable.md +1 -1
  107. package/doc/type-aliases/InjectCustomFields.md +1 -1
  108. package/doc/type-aliases/IntersectUnion.md +1 -1
  109. package/doc/type-aliases/IntrinsicFilter.md +1 -1
  110. package/doc/type-aliases/Item.md +1 -1
  111. package/doc/type-aliases/Join.md +1 -1
  112. package/doc/type-aliases/Key.md +1 -1
  113. package/doc/type-aliases/KeyFiltered.md +2 -2
  114. package/doc/type-aliases/KeyFromUnion.md +1 -1
  115. package/doc/type-aliases/Locale.md +1 -1
  116. package/doc/type-aliases/NextHandler.md +1 -1
  117. package/doc/type-aliases/NormalizedPathFieldSettings.md +57 -0
  118. package/doc/type-aliases/Order.md +1 -1
  119. package/doc/type-aliases/OrderNormalized.md +1 -1
  120. package/doc/type-aliases/Parameters.md +1 -1
  121. package/doc/type-aliases/Path.md +3 -3
  122. package/doc/type-aliases/PathFiltered.md +3 -3
  123. package/doc/type-aliases/Primitive.md +1 -1
  124. package/doc/type-aliases/PrimitiveObject.md +1 -1
  125. package/doc/type-aliases/Query.md +1 -1
  126. package/doc/type-aliases/QueryAggregate.md +1 -1
  127. package/doc/type-aliases/QueryCreate.md +1 -1
  128. package/doc/type-aliases/QueryCreateMultiple.md +1 -1
  129. package/doc/type-aliases/QueryDelete.md +1 -1
  130. package/doc/type-aliases/QueryDeleteMultiple.md +1 -1
  131. package/doc/type-aliases/QueryMethod.md +1 -1
  132. package/doc/type-aliases/QueryRead.md +1 -1
  133. package/doc/type-aliases/QueryReadMultiple.md +1 -1
  134. package/doc/type-aliases/QuerySettings.md +36 -30
  135. package/doc/type-aliases/QueryUpdate.md +1 -1
  136. package/doc/type-aliases/QueryUpdateMultiple.md +1 -1
  137. package/doc/type-aliases/Result.md +1 -1
  138. package/doc/type-aliases/Store.md +1 -1
  139. package/doc/type-aliases/Value.md +1 -1
  140. package/doc/type-aliases/ValueMap.md +1 -1
  141. package/doc/variables/CACHE.md +1 -1
  142. package/doc/variables/FILTER_ANY.md +1 -1
  143. package/doc/variables/FILTER_NONE.md +1 -1
  144. package/doc/variables/SELF.md +1 -1
  145. package/lib/tools/comparatorFieldValues.ts +46 -0
  146. package/lib/tools/filterChildren.ts +3 -1
  147. package/lib/tools/get.ts +9 -4
  148. package/lib/tools/querySettings.ts +20 -0
  149. package/lib/tools/sortItemList.test.ts +31 -8
  150. package/lib/tools/sortItemList.ts +21 -41
  151. package/lib/tools/testFilter.test.ts +35 -12
  152. package/lib/tools/testFilter.ts +1 -2
  153. package/lib/tools/transformerFilterChildren.ts +4 -26
  154. package/lib/tools.ts +2 -0
  155. package/lib/types/CombineUnion.ts +12 -10
  156. package/lib/types/Decrement.ts +5 -0
  157. package/lib/types/DepthLimit.ts +1 -0
  158. package/lib/types/FieldKey.ts +6 -1
  159. package/lib/types/Get.ts +17 -9
  160. package/lib/types/KeyFiltered.ts +14 -10
  161. package/lib/types/NormalizedPathFieldSettings.ts +25 -0
  162. package/lib/types/Path.ts +18 -15
  163. package/lib/types/PathFiltered.ts +20 -17
  164. package/lib/types/QuerySettings.ts +16 -17
  165. package/lib/types.ts +3 -1
  166. package/package.json +2 -2
  167. package/dist/types/Increment.d.ts +0 -4
  168. package/dist/types/Increment.js +0 -1
  169. package/dist/types/Increment.js.map +0 -1
  170. package/doc/type-aliases/Increment.md +0 -17
  171. package/lib/types/Increment.ts +0 -5
@@ -0,0 +1,46 @@
1
+ import { EMPTY_OBJECT } from "unchangeable";
2
+
3
+ import type {
4
+ FieldFiltered,
5
+ NormalizedPathFieldSettings,
6
+ QuerySettings,
7
+ } from "../types";
8
+
9
+ import { escapeRegex } from "./escapeRegex.js";
10
+ import { sameField } from "./sameField.js";
11
+
12
+ /**
13
+ * Returns a function that transforms a `FilterChildren` into a `FilterStringMatch`.
14
+ *
15
+ * @param options - Options for the transformer.
16
+ * @returns A function that takes a `FilterChildren` and returns a `FilterStringMatch` that matches the paths of the children of the item specified in the `FilterChildren`.
17
+ */
18
+ export function comparatorFieldValues<T>({
19
+ pathField = "path" as FieldFiltered<T, string>,
20
+ pathFieldSeparator = "/",
21
+ pathFieldSeparatorEscape = "\\",
22
+ }: NormalizedPathFieldSettings<T> = EMPTY_OBJECT): QuerySettings<T>["compareFieldValues"] {
23
+ const fieldSeparatorRegexp = new RegExp(
24
+ !pathFieldSeparatorEscape
25
+ ? escapeRegex(pathFieldSeparator)
26
+ : `(?<!${escapeRegex(pathFieldSeparatorEscape)})${escapeRegex(pathFieldSeparator)}`,
27
+ "g",
28
+ );
29
+ return (field, a, b) => {
30
+ if (!sameField(field, pathField)) {
31
+ return undefined;
32
+ }
33
+ const normalizedA = (a as string).replaceAll?.(
34
+ fieldSeparatorRegexp,
35
+ "\x00",
36
+ );
37
+ const normalizedB = (b as string).replaceAll?.(
38
+ fieldSeparatorRegexp,
39
+ "\x00",
40
+ );
41
+ if (normalizedA > normalizedB) {
42
+ return 1;
43
+ }
44
+ return -1;
45
+ };
46
+ }
@@ -10,6 +10,7 @@ import { escapeRegex } from "./escapeRegex.js";
10
10
  * @param minDepth - The minimum depth of the child items relative to the parent.
11
11
  * @param maxDepth - The maximum depth of the child items relative to the parent.
12
12
  * @param pathSeparator - The character used to separate path segments.
13
+ * @param not - If true, generates a filter that matches items that are not children of the given parent path.
13
14
  * @returns A filter that can be used to match child items.
14
15
  */
15
16
  export function filterChildren<T>(
@@ -18,6 +19,7 @@ export function filterChildren<T>(
18
19
  minDepth = 1,
19
20
  maxDepth = Infinity,
20
21
  pathSeparator = "/",
22
+ not = false,
21
23
  ): FilterStringMatch<T> {
22
24
  const escapedSeparator = escapeRegex(pathSeparator);
23
25
  const segment = `${escapedSeparator}[^${escapedSeparator}]+`;
@@ -27,7 +29,7 @@ export function filterChildren<T>(
27
29
  : `{${minDepth},${maxDepth === Infinity ? "" : maxDepth}}`;
28
30
  return {
29
31
  field: pathFieldKey,
30
- operator: "match",
32
+ operator: not ? "notMatch" : "match",
31
33
  value: `^${escapeRegex(parentPath)}(?:${segment})${quantifier}$`,
32
34
  };
33
35
  }
package/lib/tools/get.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { SELF } from "../constants/SELF.js";
2
- import type { Get, Path } from "../types";
2
+ import type { Field, Get } from "../types";
3
+
4
+ const { isArray } = Array;
3
5
 
4
6
  /**
5
7
  * Gets the property value of the given `value` at the specified `path` (an array of object property names or array indexes).
@@ -7,11 +9,11 @@ import type { Get, Path } from "../types";
7
9
  * If the `path` is a string, it is considered as a path with one item.
8
10
  * If the `path` leads to an unknown property, returns `undefined`.
9
11
  *
10
- * @param value The value from which to get the property value.
11
- * @param path The path leading to the property value or a property name or `undefined`.
12
+ * @param value - The value from which to get the property value.
13
+ * @param path - The path leading to the property value or a property name or `undefined`.
12
14
  * @returns The property value found at the given path, or `undefined` if it cannot be found.
13
15
  */
14
- export function get<const T, const P extends Path<T> | keyof T>(
16
+ export function get<const T, const P extends Field<T>>(
15
17
  value: T,
16
18
  path?: P,
17
19
  ): Get<T, P> {
@@ -24,6 +26,9 @@ export function get<const T, const P extends Path<T> | keyof T>(
24
26
  case "symbol":
25
27
  return (value as any)?.[path];
26
28
  default: {
29
+ if (!isArray(path)) {
30
+ return value as any;
31
+ }
27
32
  switch (path.length as number) {
28
33
  case 0:
29
34
  return value as any;
@@ -0,0 +1,20 @@
1
+ import { EMPTY_OBJECT } from "unchangeable";
2
+
3
+ import type { NormalizedPathFieldSettings, QuerySettings } from "../types";
4
+
5
+ import { comparatorFieldValues } from "./comparatorFieldValues.js";
6
+ import { transformerFilterChildren } from "./transformerFilterChildren.js";
7
+ /**
8
+ * Returns query settings for path fields.
9
+ *
10
+ * @param settings - Settings for normalizing path fields.
11
+ * @returns Query settings for path fields.
12
+ */
13
+ export function querySettings<T>(
14
+ settings: NormalizedPathFieldSettings<T> = EMPTY_OBJECT,
15
+ ): QuerySettings<T> {
16
+ return {
17
+ compareFieldValues: comparatorFieldValues(settings),
18
+ transformFilterChildren: transformerFilterChildren(settings),
19
+ };
20
+ }
@@ -1,5 +1,6 @@
1
1
  import { expect, test } from "vitest";
2
2
 
3
+ import { querySettings } from "./querySettings.js";
3
4
  import { sortItemList } from "./sortItemList.js";
4
5
 
5
6
  test("sorts items", () => {
@@ -76,10 +77,7 @@ test("sorts items with separator setting", () => {
76
77
  { path: "a\\/b.c" },
77
78
  { path: "a.b/c" },
78
79
  ],
79
- {
80
- pathField: "path",
81
- pathFieldSeparator: "/",
82
- },
80
+ querySettings(),
83
81
  ),
84
82
  ).toEqual([
85
83
  { path: "a" },
@@ -104,10 +102,7 @@ test("sorts items with separator setting", () => {
104
102
  { path: "a\\/b.c" },
105
103
  { path: "a.b/c" },
106
104
  ],
107
- {
108
- pathField: "path",
109
- pathFieldSeparator: "/",
110
- },
105
+ querySettings(),
111
106
  ),
112
107
  ).toEqual([
113
108
  { path: "a" },
@@ -119,4 +114,32 @@ test("sorts items with separator setting", () => {
119
114
  { path: "a.b.c" },
120
115
  { path: "a\\/b.c" },
121
116
  ]);
117
+
118
+ expect(
119
+ sortItemList(
120
+ [{ descending: false, field: "path" }],
121
+ [
122
+ { path: "a" },
123
+ { path: "a/b" },
124
+ { path: "a.b" },
125
+ { path: "a/b/c" },
126
+ { path: "a.b.c" },
127
+ { path: "a/b.c" },
128
+ { path: "a\\.b.c" },
129
+ { path: "a.b/c" },
130
+ ],
131
+ querySettings({
132
+ pathFieldSeparator: ".",
133
+ }),
134
+ ),
135
+ ).toEqual([
136
+ { path: "a" },
137
+ { path: "a.b" },
138
+ { path: "a.b.c" },
139
+ { path: "a.b/c" },
140
+ { path: "a/b" },
141
+ { path: "a/b.c" },
142
+ { path: "a/b/c" },
143
+ { path: "a\\.b.c" },
144
+ ]);
122
145
  });
@@ -1,73 +1,53 @@
1
+ import { EMPTY_OBJECT } from "unchangeable";
2
+
1
3
  import type { Order, QuerySettings } from "../types";
2
4
 
3
- import { escapeRegex } from "./escapeRegex.js";
4
5
  import { get } from "./get.js";
5
6
  import { normalizeOrder } from "./normalizeOrder.js";
6
- import { sameField } from "./sameField.js";
7
7
 
8
8
  /**
9
9
  * Sorts provided `value` array according to the `orderList`.
10
10
  *
11
- * @param orderList The order to use for sorting.
12
- * @param value The array to sort.
13
- * @param settings Optional query settings.
11
+ * @param orderList - The order to use for sorting.
12
+ * @param value - The array to sort.
13
+ * @param settings - Optional query settings.
14
14
  * @returns A new sorted array.
15
15
  */
16
16
  export function sortItemList<T>(
17
- orderList: readonly Order<T>[] | undefined,
17
+ orderList: NoInfer<readonly Order<T>[]> | undefined,
18
18
  value: readonly T[],
19
19
  settings?: QuerySettings<T>,
20
20
  ) {
21
- const {
22
- pathField,
23
- pathFieldSeparator = "/",
24
- pathFieldSeparatorEscape,
25
- } = settings ?? {};
26
21
  if (orderList === undefined || orderList.length === 0) {
27
22
  return value;
28
23
  }
24
+ const { compareFieldValues } = settings ?? EMPTY_OBJECT;
29
25
  const normalizedOrder = orderList.map(normalizeOrder);
30
- const fieldSeparatorRegexp =
31
- pathField == null || pathFieldSeparator == null
32
- ? null
33
- : new RegExp(
34
- !pathFieldSeparatorEscape
35
- ? escapeRegex(pathFieldSeparator)
36
- : `(?<!${escapeRegex(pathFieldSeparatorEscape)})${escapeRegex(pathFieldSeparator)}`,
37
- "g",
38
- );
39
26
  return value.toSorted((a, b) => {
40
27
  for (let index = 0; index < normalizedOrder.length; index++) {
41
28
  const { field, descending } = normalizedOrder[index]!;
42
- const valueA = get(a, field as any);
43
- const valueB = get(b, field as any);
29
+ const valueA = get(a, field);
30
+ const valueB = get(b, field);
44
31
  if (valueA === valueB) {
45
32
  continue;
46
33
  }
47
- if (fieldSeparatorRegexp != null && sameField(field, pathField!)) {
48
- if (valueA == null) {
49
- return valueB == null ? 0 : descending ? 1 : -1;
50
- }
51
- if (valueB == null) {
52
- return descending ? -1 : 1;
53
- }
54
- const normalizedA = (valueA as string).replaceAll(
55
- fieldSeparatorRegexp,
56
- "\x00",
57
- );
58
- const normalizedB = (valueB as string).replaceAll(
59
- fieldSeparatorRegexp,
60
- "\x00",
61
- );
62
- if (normalizedA > normalizedB) {
34
+ if (valueA == null) {
35
+ return valueB == null ? 0 : descending ? 1 : -1;
36
+ }
37
+ if (valueB == null) {
38
+ return descending ? -1 : 1;
39
+ }
40
+ const comparison = compareFieldValues?.(field, valueA, valueB);
41
+ if (comparison === undefined) {
42
+ if (valueA > valueB) {
63
43
  return descending ? -1 : 1;
64
44
  }
65
45
  return descending ? 1 : -1;
66
46
  }
67
- if (valueA > valueB) {
68
- return descending ? -1 : 1;
47
+ if (comparison === 0) {
48
+ continue;
69
49
  }
70
- return descending ? 1 : -1;
50
+ return descending ? -comparison : comparison;
71
51
  }
72
52
  return 0;
73
53
  });
@@ -5,6 +5,7 @@ import { SELF } from "../constants.js";
5
5
  import type { FilterChildren } from "../types.js";
6
6
 
7
7
  import { filterFromValue } from "./filterFromValue.js";
8
+ import { querySettings } from "./querySettings.js";
8
9
  import { testFilter } from "./testFilter.js";
9
10
 
10
11
  test("tests filter lists", () => {
@@ -360,27 +361,37 @@ test("tests filter with children predicates", () => {
360
361
  { id: "a" },
361
362
  ),
362
363
  ).toBe(true);
364
+
365
+ // Always true if `transformFilterChildren` is not provided, to avoid false negatives
363
366
  expect(
364
367
  testFilter({ operator: "notChildren", value: { id: "a" } }, { id: "a/b" }),
368
+ ).toBe(true);
369
+ expect(
370
+ testFilter(
371
+ { operator: "notChildren", value: { id: "a" } },
372
+ { id: "a/b" },
373
+ querySettings({ pathField: "id" }),
374
+ ),
365
375
  ).toBe(false);
376
+
366
377
  expect(
367
378
  testFilter(
368
379
  { operator: "children", value: { path: ".a" } },
369
380
  { path: ".a.b" },
370
- {
381
+ querySettings({
371
382
  pathField: "path",
372
383
  pathFieldSeparator: ".",
373
- },
384
+ }),
374
385
  ),
375
386
  ).toBe(true);
376
387
  expect(
377
388
  testFilter(
378
389
  { operator: "notChildren", value: { path: ".a" } },
379
390
  { path: ".a.b" },
380
- {
391
+ querySettings({
381
392
  pathField: "path",
382
393
  pathFieldSeparator: ".",
383
- },
394
+ }),
384
395
  ),
385
396
  ).toBe(false);
386
397
  const filterChildren: FilterChildren<{ path: string }> = {
@@ -397,7 +408,7 @@ test("tests filter with children predicates", () => {
397
408
  field: "path",
398
409
  operator: "startWith",
399
410
  value: `.${filter.value?.path}.`,
400
- };
411
+ } as const;
401
412
  },
402
413
  },
403
414
  ),
@@ -415,36 +426,48 @@ test("tests filter with children predicates", () => {
415
426
  field: "path",
416
427
  operator: "startWith",
417
428
  value: `.${filter.value?.path}.`,
418
- };
429
+ } as const;
419
430
  },
420
431
  },
421
432
  ),
422
433
  ).toBe(true);
423
434
  expect(filterChildren[CACHE]).toBeDefined();
424
435
  expect(
425
- testFilter({ operator: "children", value: { id: "b" } }, { id: "a/b" }),
436
+ testFilter(
437
+ { operator: "children", value: { id: "b" } },
438
+ { id: "a/b" },
439
+ querySettings({
440
+ pathField: "id",
441
+ }),
442
+ ),
426
443
  ).toBe(false);
427
444
  expect(
428
- testFilter({ operator: "notChildren", value: { id: "b" } }, { id: "a/b" }),
445
+ testFilter(
446
+ { operator: "notChildren", value: { id: "b" } },
447
+ { id: "a/b" },
448
+ querySettings({
449
+ pathField: "id",
450
+ }),
451
+ ),
429
452
  ).toBe(true);
430
453
  expect(
431
454
  testFilter(
432
455
  { operator: "children", value: { path: "ba" } },
433
456
  { path: ".a.b" },
434
- {
457
+ querySettings({
435
458
  pathField: "path",
436
459
  pathFieldSeparator: ".",
437
- },
460
+ }),
438
461
  ),
439
462
  ).toBe(false);
440
463
  expect(
441
464
  testFilter(
442
465
  { operator: "notChildren", value: { path: "ba" } },
443
466
  { path: ".a.b" },
444
- {
467
+ querySettings({
445
468
  pathField: "path",
446
469
  pathFieldSeparator: ".",
447
- },
470
+ }),
448
471
  ),
449
472
  ).toBe(true);
450
473
  });
@@ -121,7 +121,6 @@ export function testFilter<T>(
121
121
  }
122
122
  case "children":
123
123
  case "notChildren": {
124
- const not = filter.operator[0] === "n";
125
124
  if (filter[CACHE] === undefined) {
126
125
  switch (true) {
127
126
  case settings?.transformFilterChildren !== undefined:
@@ -133,7 +132,7 @@ export function testFilter<T>(
133
132
  }
134
133
  }
135
134
  }
136
- return negate(testFilter(filter[CACHE], value, settings), not);
135
+ return testFilter(filter[CACHE], value, settings);
137
136
  }
138
137
  case "custom": {
139
138
  return filter.value(value);
@@ -4,32 +4,12 @@ import type {
4
4
  FieldFiltered,
5
5
  FilterChildren,
6
6
  FilterStringMatch,
7
+ NormalizedPathFieldSettings,
7
8
  } from "../types";
8
9
 
9
10
  import { filterChildren } from "./filterChildren.js";
10
11
  import { get } from "./get.js";
11
12
 
12
- export type TransformerFilterChildrenOptions<T> = {
13
- /**
14
- * Path to the field that contains the path value of an item, used for displaying items in a tree.
15
- *
16
- * @default "path"
17
- */
18
- pathField?: FieldFiltered<T, string>;
19
- /**
20
- * String used to escape the separator.
21
- *
22
- * @default "\\"
23
- */
24
- pathFieldSeparatorEscape?: string;
25
- /**
26
- * Maps path fields to a string used to separate the path nodes of a field value.
27
- *
28
- * @default "/"
29
- */
30
- pathFieldSeparator?: string;
31
- };
32
-
33
13
  /**
34
14
  * Returns a function that transforms a `FilterChildren` into a `FilterStringMatch`.
35
15
  *
@@ -39,19 +19,17 @@ export type TransformerFilterChildrenOptions<T> = {
39
19
  export function transformerFilterChildren<T>({
40
20
  pathField = "path" as FieldFiltered<T, string>,
41
21
  pathFieldSeparator = "/",
42
- }: TransformerFilterChildrenOptions<T> = EMPTY_OBJECT) {
22
+ }: NormalizedPathFieldSettings<T> = EMPTY_OBJECT) {
43
23
  return (filter: FilterChildren<T>): FilterStringMatch<T> => {
44
24
  const { value, minDepth = 1, maxDepth = Infinity } = filter;
45
- if (value === undefined) {
46
- throw new Error("FilterChildren must have a value");
47
- }
48
- const parentPath = get(value, pathField as any) as string;
25
+ const parentPath = (get(value, pathField as any) ?? "") as string;
49
26
  return filterChildren(
50
27
  parentPath,
51
28
  pathField,
52
29
  minDepth,
53
30
  maxDepth,
54
31
  pathFieldSeparator,
32
+ filter.operator[0] === "n",
55
33
  );
56
34
  };
57
35
  }
package/lib/tools.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  // File automatically generated by `vite-plugin-module-list`
2
+ export { comparatorFieldValues } from "./tools/comparatorFieldValues.js";
2
3
  export { cork } from "./tools/cork.js";
3
4
  export { defineCheckQuery } from "./tools/defineCheckQuery.js";
4
5
  export { defineCustomFetch } from "./tools/defineCustomFetch.js";
@@ -13,6 +14,7 @@ export { intrinsicFilter } from "./tools/intrinsicFilter.js";
13
14
  export { isFilterGroup } from "./tools/isFilterGroup.js";
14
15
  export { normalizeOrder } from "./tools/normalizeOrder.js";
15
16
  export { queryItemList } from "./tools/queryItemList.js";
17
+ export { querySettings } from "./tools/querySettings.js";
16
18
  export { reverseOrder } from "./tools/reverseOrder.js";
17
19
  export { sameField } from "./tools/sameField.js";
18
20
  export { sortItemList } from "./tools/sortItemList.js";
@@ -1,17 +1,19 @@
1
1
  import type { KeyFromUnion } from "./KeyFromUnion";
2
2
  import type { Primitive } from "./Primitive";
3
3
 
4
- export type CombineUnion<U> = [0] extends [1 & U]
5
- ? any
6
- : [U] extends [Function | readonly Function[]]
7
- ? undefined
8
- : [U] extends [Primitive]
9
- ? U
10
- : [U] extends readonly [Array<any>]
4
+ export type CombineUnion<U> = [unknown] extends [U]
5
+ ? unknown
6
+ : [0] extends [1 & U]
7
+ ? any
8
+ : [U] extends [Function | readonly Function[]]
9
+ ? undefined
10
+ : [U] extends [Primitive]
11
11
  ? U
12
- : {
13
- [K in KeyFromUnion<U>]: Continue<Combine<U, K>>;
14
- };
12
+ : [U] extends readonly [Array<any>]
13
+ ? U
14
+ : {
15
+ [K in KeyFromUnion<U>]: Continue<Combine<U, K>>;
16
+ };
15
17
 
16
18
  type Combine<U, K extends string | number | symbol> = Exclude<
17
19
  Extract<U, { [k in K]?: any }>[K],
@@ -0,0 +1,5 @@
1
+ type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
2
+
3
+ type NextDigit = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
4
+
5
+ export type Decrement<D> = D extends Digit ? NextDigit[D] : -1;
@@ -0,0 +1 @@
1
+ export type DepthLimit = 4;
@@ -1,5 +1,10 @@
1
1
  import type { SELF } from "../constants/SELF.ts";
2
2
 
3
+ import type { Key } from "./Key.ts";
3
4
  import type { Primitive } from "./Primitive";
4
5
 
5
- export type FieldKey<T> = T extends Primitive ? typeof SELF : keyof T;
6
+ export type FieldKey<T> = T extends Primitive
7
+ ? typeof SELF
8
+ : [unknown] extends [T]
9
+ ? Key
10
+ : keyof T;
package/lib/types/Get.ts CHANGED
@@ -1,14 +1,22 @@
1
+ import type { Decrement } from "./Decrement";
2
+ import type { DepthLimit } from "./DepthLimit";
1
3
  import type { Path } from "./Path";
2
4
 
3
5
  /**
4
6
  * Returns the type of the property at the specified `P` path.
5
7
  */
6
- export type Get<T, P> = [P] extends [readonly [infer K, ...infer R]]
7
- ? K extends keyof T
8
- ? R extends Path<T[K]>
9
- ? Get<T[K], R>
10
- : T[K]
11
- : never
12
- : [P] extends [keyof T]
13
- ? T[P]
14
- : T;
8
+ export type Get<T, P, D = DepthLimit> = [unknown] extends [T]
9
+ ? unknown
10
+ : [0] extends [1 & T]
11
+ ? any
12
+ : D extends -1
13
+ ? any
14
+ : [P] extends [readonly [infer K, ...infer R]]
15
+ ? K extends keyof T
16
+ ? R extends Path<T[K]>
17
+ ? Get<T[K], R, Decrement<D>>
18
+ : T[K]
19
+ : never
20
+ : [P] extends [keyof T]
21
+ ? T[P]
22
+ : T;
@@ -7,14 +7,18 @@ type SymbolSelf = typeof SELF;
7
7
  /**
8
8
  * Returns union of keys whose mapped value extend the provided `P` type.
9
9
  */
10
- export type KeyFiltered<T, P> = [0] extends [1 & T]
10
+ export type KeyFiltered<T, P> = [unknown] extends [T]
11
11
  ? Key | SymbolSelf
12
- : T extends string | number | boolean | bigint | symbol
13
- ? T extends P
14
- ? SymbolSelf
15
- : never
16
- : T extends object
17
- ? keyof {
18
- [K in keyof T as Extract<T[K], P> extends never ? never : K]-?: T[K];
19
- }
20
- : never;
12
+ : [0] extends [1 & T]
13
+ ? Key | SymbolSelf
14
+ : T extends string | number | boolean | bigint | symbol
15
+ ? T extends P
16
+ ? SymbolSelf
17
+ : never
18
+ : T extends object
19
+ ? keyof {
20
+ [K in keyof T as Extract<T[K], P> extends never
21
+ ? never
22
+ : K]-?: T[K];
23
+ }
24
+ : never;
@@ -0,0 +1,25 @@
1
+ import type { FieldFiltered } from "./FieldFiltered";
2
+
3
+ /**
4
+ * Settings for fields that contain path values of items, used for displaying items in a tree.
5
+ */
6
+ export type NormalizedPathFieldSettings<T> = {
7
+ /**
8
+ * Path to the field that contains the path value of an item, used for displaying items in a tree.
9
+ *
10
+ * @default "path"
11
+ */
12
+ pathField?: FieldFiltered<T, string>;
13
+ /**
14
+ * String used to escape the separator.
15
+ *
16
+ * @default "\\"
17
+ */
18
+ pathFieldSeparatorEscape?: string;
19
+ /**
20
+ * Maps path fields to a string used to separate the path nodes of a field value.
21
+ *
22
+ * @default "/"
23
+ */
24
+ pathFieldSeparator?: string;
25
+ };
package/lib/types/Path.ts CHANGED
@@ -1,19 +1,22 @@
1
- import type { Increment } from "./Increment";
1
+ import type { Decrement } from "./Decrement";
2
+ import type { DepthLimit } from "./DepthLimit";
2
3
  import type { Key } from "./Key";
3
4
  import type { Primitive } from "./Primitive";
4
5
 
5
- export type Path<T, D = 7> = [0] extends [1 & T]
6
+ export type Path<T, D = DepthLimit> = [unknown] extends [T]
6
7
  ? readonly (Key | never)[]
7
- : D extends -1
8
- ? never
9
- : T extends Primitive
10
- ? readonly never[]
11
- : T extends Array<infer P>
12
- ? readonly [number] | readonly [number, ...Path<P, Increment<D>>]
13
- : T extends object
14
- ? {
15
- [K in keyof T]:
16
- | readonly [K]
17
- | readonly [K, ...Path<T[K], Increment<D>>];
18
- }[keyof T]
19
- : never;
8
+ : [0] extends [1 & T]
9
+ ? readonly (Key | never)[]
10
+ : D extends -1
11
+ ? never
12
+ : T extends Primitive
13
+ ? readonly never[]
14
+ : T extends Array<infer P>
15
+ ? readonly [number] | readonly [number, ...Path<P, Decrement<D>>]
16
+ : T extends object
17
+ ? {
18
+ [K in keyof T]:
19
+ | readonly [K]
20
+ | readonly [K, ...Path<T[K], Decrement<D>>];
21
+ }[keyof T]
22
+ : never;