@ls-stack/utils 3.49.1 → 3.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-Y76LZUOB.js +151 -0
- package/dist/objUtils.cjs +81 -0
- package/dist/objUtils.d.cts +3 -1
- package/dist/objUtils.d.ts +3 -1
- package/dist/objUtils.js +3 -1
- package/dist/partialEqual.cjs +266 -0
- package/dist/partialEqual.d.cts +28 -2
- package/dist/partialEqual.d.ts +28 -2
- package/dist/partialEqual.js +266 -0
- package/dist/testUtils.cjs +1 -0
- package/dist/testUtils.js +1 -1
- package/dist/typeUtils.d.cts +2 -1
- package/dist/typeUtils.d.ts +2 -1
- package/package.json +1 -1
- package/dist/chunk-Y45CE75W.js +0 -71
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
typedObjectEntries
|
|
3
|
+
} from "./chunk-GMJTLFM6.js";
|
|
4
|
+
import {
|
|
5
|
+
sortBy
|
|
6
|
+
} from "./chunk-27AL66CH.js";
|
|
7
|
+
|
|
8
|
+
// src/objUtils.ts
|
|
9
|
+
import { Result } from "t-result";
|
|
10
|
+
function objectTypedEntries(obj) {
|
|
11
|
+
return Object.entries(obj);
|
|
12
|
+
}
|
|
13
|
+
function pick(obj, keys) {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const key of keys) {
|
|
16
|
+
result[key] = obj[key];
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
function mapArrayToObject(array, mapper) {
|
|
21
|
+
return Object.fromEntries(array.map(mapper));
|
|
22
|
+
}
|
|
23
|
+
function mapObjectToObject(obj, mapper) {
|
|
24
|
+
return Object.fromEntries(
|
|
25
|
+
objectTypedEntries(obj).map(([key, value]) => mapper(key, value))
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function omit(obj, keys) {
|
|
29
|
+
const result = {};
|
|
30
|
+
for (const key of Object.keys(obj)) {
|
|
31
|
+
if (!keys.includes(key)) {
|
|
32
|
+
result[key] = obj[key];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function looseGetObjectProperty(obj, key) {
|
|
38
|
+
return obj[key];
|
|
39
|
+
}
|
|
40
|
+
function rejectObjUndefinedValues(obj) {
|
|
41
|
+
const result = {};
|
|
42
|
+
for (const key in obj) {
|
|
43
|
+
if (obj[key] !== void 0) {
|
|
44
|
+
result[key] = obj[key];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
function filterObjectKeys(obj, predicate) {
|
|
50
|
+
return Object.fromEntries(
|
|
51
|
+
Object.entries(obj).filter(
|
|
52
|
+
([key, value]) => predicate(key, value)
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
function sortObjectKeys(obj, sortByFn, options) {
|
|
57
|
+
return Object.fromEntries(
|
|
58
|
+
sortBy(typedObjectEntries(obj), sortByFn, options)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
function getValueFromPath(obj, path) {
|
|
62
|
+
if (!path.trim()) {
|
|
63
|
+
return Result.err(new Error("Path cannot be empty"));
|
|
64
|
+
}
|
|
65
|
+
const segments = parsePath(path);
|
|
66
|
+
let current = obj;
|
|
67
|
+
for (let i = 0; i < segments.length; i++) {
|
|
68
|
+
const segment = segments[i];
|
|
69
|
+
if (!segment) {
|
|
70
|
+
return Result.err(new Error("Invalid empty segment in path"));
|
|
71
|
+
}
|
|
72
|
+
if (current == null) {
|
|
73
|
+
return Result.err(
|
|
74
|
+
new Error(`Cannot access property '${segment}' on null or undefined`)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (isNumericString(segment)) {
|
|
78
|
+
if (!Array.isArray(current)) {
|
|
79
|
+
return Result.err(
|
|
80
|
+
new Error(
|
|
81
|
+
`Cannot access array index '${segment}' on non-array value`
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const index = parseInt(segment, 10);
|
|
86
|
+
if (index < 0 || index >= current.length) {
|
|
87
|
+
return Result.err(new Error(`Array index '${index}' out of bounds`));
|
|
88
|
+
}
|
|
89
|
+
current = current[index];
|
|
90
|
+
} else {
|
|
91
|
+
if (typeof current !== "object" || current === null) {
|
|
92
|
+
return Result.err(
|
|
93
|
+
new Error(`Cannot access property '${segment}' on non-object value`)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (!(segment in current)) {
|
|
97
|
+
return Result.err(new Error(`Property '${segment}' not found`));
|
|
98
|
+
}
|
|
99
|
+
current = current[segment];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return Result.ok(current);
|
|
103
|
+
}
|
|
104
|
+
function parsePath(path) {
|
|
105
|
+
const segments = [];
|
|
106
|
+
let current = "";
|
|
107
|
+
let inBrackets = false;
|
|
108
|
+
for (let i = 0; i < path.length; i++) {
|
|
109
|
+
const char = path[i];
|
|
110
|
+
if (char === "[") {
|
|
111
|
+
if (current) {
|
|
112
|
+
segments.push(current);
|
|
113
|
+
current = "";
|
|
114
|
+
}
|
|
115
|
+
inBrackets = true;
|
|
116
|
+
} else if (char === "]") {
|
|
117
|
+
if (inBrackets && current) {
|
|
118
|
+
segments.push(current);
|
|
119
|
+
current = "";
|
|
120
|
+
}
|
|
121
|
+
inBrackets = false;
|
|
122
|
+
} else if (char === "." && !inBrackets) {
|
|
123
|
+
if (current) {
|
|
124
|
+
segments.push(current);
|
|
125
|
+
current = "";
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
current += char;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (current) {
|
|
132
|
+
segments.push(current);
|
|
133
|
+
}
|
|
134
|
+
return segments;
|
|
135
|
+
}
|
|
136
|
+
function isNumericString(str) {
|
|
137
|
+
return /^\d+$/.test(str);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
objectTypedEntries,
|
|
142
|
+
pick,
|
|
143
|
+
mapArrayToObject,
|
|
144
|
+
mapObjectToObject,
|
|
145
|
+
omit,
|
|
146
|
+
looseGetObjectProperty,
|
|
147
|
+
rejectObjUndefinedValues,
|
|
148
|
+
filterObjectKeys,
|
|
149
|
+
sortObjectKeys,
|
|
150
|
+
getValueFromPath
|
|
151
|
+
};
|
package/dist/objUtils.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var objUtils_exports = {};
|
|
22
22
|
__export(objUtils_exports, {
|
|
23
23
|
filterObjectKeys: () => filterObjectKeys,
|
|
24
|
+
getValueFromPath: () => getValueFromPath,
|
|
24
25
|
looseGetObjectProperty: () => looseGetObjectProperty,
|
|
25
26
|
mapArrayToObject: () => mapArrayToObject,
|
|
26
27
|
mapObjectToObject: () => mapObjectToObject,
|
|
@@ -31,6 +32,7 @@ __export(objUtils_exports, {
|
|
|
31
32
|
sortObjectKeys: () => sortObjectKeys
|
|
32
33
|
});
|
|
33
34
|
module.exports = __toCommonJS(objUtils_exports);
|
|
35
|
+
var import_t_result = require("t-result");
|
|
34
36
|
|
|
35
37
|
// src/arrayUtils.ts
|
|
36
38
|
function sortBy(arr, sortByValue, props = "asc") {
|
|
@@ -115,9 +117,88 @@ function sortObjectKeys(obj, sortByFn, options) {
|
|
|
115
117
|
sortBy(typedObjectEntries(obj), sortByFn, options)
|
|
116
118
|
);
|
|
117
119
|
}
|
|
120
|
+
function getValueFromPath(obj, path) {
|
|
121
|
+
if (!path.trim()) {
|
|
122
|
+
return import_t_result.Result.err(new Error("Path cannot be empty"));
|
|
123
|
+
}
|
|
124
|
+
const segments = parsePath(path);
|
|
125
|
+
let current = obj;
|
|
126
|
+
for (let i = 0; i < segments.length; i++) {
|
|
127
|
+
const segment = segments[i];
|
|
128
|
+
if (!segment) {
|
|
129
|
+
return import_t_result.Result.err(new Error("Invalid empty segment in path"));
|
|
130
|
+
}
|
|
131
|
+
if (current == null) {
|
|
132
|
+
return import_t_result.Result.err(
|
|
133
|
+
new Error(`Cannot access property '${segment}' on null or undefined`)
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
if (isNumericString(segment)) {
|
|
137
|
+
if (!Array.isArray(current)) {
|
|
138
|
+
return import_t_result.Result.err(
|
|
139
|
+
new Error(
|
|
140
|
+
`Cannot access array index '${segment}' on non-array value`
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
const index = parseInt(segment, 10);
|
|
145
|
+
if (index < 0 || index >= current.length) {
|
|
146
|
+
return import_t_result.Result.err(new Error(`Array index '${index}' out of bounds`));
|
|
147
|
+
}
|
|
148
|
+
current = current[index];
|
|
149
|
+
} else {
|
|
150
|
+
if (typeof current !== "object" || current === null) {
|
|
151
|
+
return import_t_result.Result.err(
|
|
152
|
+
new Error(`Cannot access property '${segment}' on non-object value`)
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
if (!(segment in current)) {
|
|
156
|
+
return import_t_result.Result.err(new Error(`Property '${segment}' not found`));
|
|
157
|
+
}
|
|
158
|
+
current = current[segment];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return import_t_result.Result.ok(current);
|
|
162
|
+
}
|
|
163
|
+
function parsePath(path) {
|
|
164
|
+
const segments = [];
|
|
165
|
+
let current = "";
|
|
166
|
+
let inBrackets = false;
|
|
167
|
+
for (let i = 0; i < path.length; i++) {
|
|
168
|
+
const char = path[i];
|
|
169
|
+
if (char === "[") {
|
|
170
|
+
if (current) {
|
|
171
|
+
segments.push(current);
|
|
172
|
+
current = "";
|
|
173
|
+
}
|
|
174
|
+
inBrackets = true;
|
|
175
|
+
} else if (char === "]") {
|
|
176
|
+
if (inBrackets && current) {
|
|
177
|
+
segments.push(current);
|
|
178
|
+
current = "";
|
|
179
|
+
}
|
|
180
|
+
inBrackets = false;
|
|
181
|
+
} else if (char === "." && !inBrackets) {
|
|
182
|
+
if (current) {
|
|
183
|
+
segments.push(current);
|
|
184
|
+
current = "";
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
current += char;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (current) {
|
|
191
|
+
segments.push(current);
|
|
192
|
+
}
|
|
193
|
+
return segments;
|
|
194
|
+
}
|
|
195
|
+
function isNumericString(str) {
|
|
196
|
+
return /^\d+$/.test(str);
|
|
197
|
+
}
|
|
118
198
|
// Annotate the CommonJS export names for ESM import in node:
|
|
119
199
|
0 && (module.exports = {
|
|
120
200
|
filterObjectKeys,
|
|
201
|
+
getValueFromPath,
|
|
121
202
|
looseGetObjectProperty,
|
|
122
203
|
mapArrayToObject,
|
|
123
204
|
mapObjectToObject,
|
package/dist/objUtils.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Result } from 't-result';
|
|
1
2
|
import { SortByValueFn, SortByProps } from './arrayUtils.cjs';
|
|
2
3
|
import { MakeUndefinedKeysOptional } from './typeUtils.cjs';
|
|
3
4
|
|
|
@@ -14,5 +15,6 @@ declare function looseGetObjectProperty<T extends Record<string, unknown>>(obj:
|
|
|
14
15
|
declare function rejectObjUndefinedValues<T extends Record<string, unknown>>(obj: T): MakeUndefinedKeysOptional<T>;
|
|
15
16
|
declare function filterObjectKeys<T extends Record<string, unknown>>(obj: T, predicate: (key: keyof T, value: T[keyof T]) => boolean): Partial<T>;
|
|
16
17
|
declare function sortObjectKeys<T extends Record<string, unknown>>(obj: T, sortByFn: SortByValueFn<[key: keyof T, value: T[keyof T]]>, options?: SortByProps): T;
|
|
18
|
+
declare function getValueFromPath(obj: Record<string, unknown>, path: string): Result<unknown, Error>;
|
|
17
19
|
|
|
18
|
-
export { filterObjectKeys, looseGetObjectProperty, mapArrayToObject, mapObjectToObject, objectTypedEntries, omit, pick, rejectObjUndefinedValues, sortObjectKeys };
|
|
20
|
+
export { filterObjectKeys, getValueFromPath, looseGetObjectProperty, mapArrayToObject, mapObjectToObject, objectTypedEntries, omit, pick, rejectObjUndefinedValues, sortObjectKeys };
|
package/dist/objUtils.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Result } from 't-result';
|
|
1
2
|
import { SortByValueFn, SortByProps } from './arrayUtils.js';
|
|
2
3
|
import { MakeUndefinedKeysOptional } from './typeUtils.js';
|
|
3
4
|
|
|
@@ -14,5 +15,6 @@ declare function looseGetObjectProperty<T extends Record<string, unknown>>(obj:
|
|
|
14
15
|
declare function rejectObjUndefinedValues<T extends Record<string, unknown>>(obj: T): MakeUndefinedKeysOptional<T>;
|
|
15
16
|
declare function filterObjectKeys<T extends Record<string, unknown>>(obj: T, predicate: (key: keyof T, value: T[keyof T]) => boolean): Partial<T>;
|
|
16
17
|
declare function sortObjectKeys<T extends Record<string, unknown>>(obj: T, sortByFn: SortByValueFn<[key: keyof T, value: T[keyof T]]>, options?: SortByProps): T;
|
|
18
|
+
declare function getValueFromPath(obj: Record<string, unknown>, path: string): Result<unknown, Error>;
|
|
17
19
|
|
|
18
|
-
export { filterObjectKeys, looseGetObjectProperty, mapArrayToObject, mapObjectToObject, objectTypedEntries, omit, pick, rejectObjUndefinedValues, sortObjectKeys };
|
|
20
|
+
export { filterObjectKeys, getValueFromPath, looseGetObjectProperty, mapArrayToObject, mapObjectToObject, objectTypedEntries, omit, pick, rejectObjUndefinedValues, sortObjectKeys };
|
package/dist/objUtils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
filterObjectKeys,
|
|
3
|
+
getValueFromPath,
|
|
3
4
|
looseGetObjectProperty,
|
|
4
5
|
mapArrayToObject,
|
|
5
6
|
mapObjectToObject,
|
|
@@ -8,13 +9,14 @@ import {
|
|
|
8
9
|
pick,
|
|
9
10
|
rejectObjUndefinedValues,
|
|
10
11
|
sortObjectKeys
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Y76LZUOB.js";
|
|
12
13
|
import "./chunk-GMJTLFM6.js";
|
|
13
14
|
import "./chunk-27AL66CH.js";
|
|
14
15
|
import "./chunk-C2SVCIWE.js";
|
|
15
16
|
import "./chunk-JF2MDHOJ.js";
|
|
16
17
|
export {
|
|
17
18
|
filterObjectKeys,
|
|
19
|
+
getValueFromPath,
|
|
18
20
|
looseGetObjectProperty,
|
|
19
21
|
mapArrayToObject,
|
|
20
22
|
mapObjectToObject,
|
package/dist/partialEqual.cjs
CHANGED
|
@@ -63,6 +63,18 @@ var match = {
|
|
|
63
63
|
isLessThanOrEqual: (value) => createComparison(["numIsLessThanOrEqual", value]),
|
|
64
64
|
isInRange: (value) => createComparison(["numIsInRange", value])
|
|
65
65
|
},
|
|
66
|
+
array: {
|
|
67
|
+
contains: (elements) => createComparison(["arrayContains", elements]),
|
|
68
|
+
containsInOrder: (elements) => createComparison(["arrayContainsInOrder", elements]),
|
|
69
|
+
startsWith: (elements) => createComparison(["arrayStartsWith", elements]),
|
|
70
|
+
endsWith: (elements) => createComparison(["arrayEndsWith", elements]),
|
|
71
|
+
length: (n) => createComparison(["arrayLength", n]),
|
|
72
|
+
minLength: (n) => createComparison(["arrayMinLength", n]),
|
|
73
|
+
maxLength: (n) => createComparison(["arrayMaxLength", n]),
|
|
74
|
+
includes: (element) => createComparison(["arrayIncludes", element]),
|
|
75
|
+
every: (matcher) => createComparison(["arrayEvery", matcher["~sc"]]),
|
|
76
|
+
some: (matcher) => createComparison(["arraySome", matcher["~sc"]])
|
|
77
|
+
},
|
|
66
78
|
jsonString: {
|
|
67
79
|
hasPartial: (value) => createComparison(["jsonStringHasPartial", value])
|
|
68
80
|
},
|
|
@@ -112,6 +124,18 @@ var match = {
|
|
|
112
124
|
isLessThanOrEqual: (value) => createComparison(["not", ["numIsLessThanOrEqual", value]]),
|
|
113
125
|
isInRange: (value) => createComparison(["not", ["numIsInRange", value]])
|
|
114
126
|
},
|
|
127
|
+
array: {
|
|
128
|
+
contains: (elements) => createComparison(["not", ["arrayContains", elements]]),
|
|
129
|
+
containsInOrder: (elements) => createComparison(["not", ["arrayContainsInOrder", elements]]),
|
|
130
|
+
startsWith: (elements) => createComparison(["not", ["arrayStartsWith", elements]]),
|
|
131
|
+
endsWith: (elements) => createComparison(["not", ["arrayEndsWith", elements]]),
|
|
132
|
+
length: (n) => createComparison(["not", ["arrayLength", n]]),
|
|
133
|
+
minLength: (n) => createComparison(["not", ["arrayMinLength", n]]),
|
|
134
|
+
maxLength: (n) => createComparison(["not", ["arrayMaxLength", n]]),
|
|
135
|
+
includes: (element) => createComparison(["not", ["arrayIncludes", element]]),
|
|
136
|
+
every: (matcher) => createComparison(["not", ["arrayEvery", matcher["~sc"]]]),
|
|
137
|
+
some: (matcher) => createComparison(["not", ["arraySome", matcher["~sc"]]])
|
|
138
|
+
},
|
|
115
139
|
jsonString: {
|
|
116
140
|
hasPartial: (value) => createComparison(["not", ["jsonStringHasPartial", value]])
|
|
117
141
|
},
|
|
@@ -396,6 +420,248 @@ function executeComparison(target, comparison, context) {
|
|
|
396
420
|
return checkNoExtraDefinedKeys(target, value, context, false);
|
|
397
421
|
case "deepNoExtraDefinedKeys":
|
|
398
422
|
return checkNoExtraDefinedKeys(target, value, context, true);
|
|
423
|
+
case "arrayContains": {
|
|
424
|
+
if (!Array.isArray(target)) {
|
|
425
|
+
addError(context, {
|
|
426
|
+
message: "Expected array",
|
|
427
|
+
received: target
|
|
428
|
+
});
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
for (const element of value) {
|
|
432
|
+
let found = false;
|
|
433
|
+
for (const targetElement of target) {
|
|
434
|
+
const tempContext = {
|
|
435
|
+
errors: [],
|
|
436
|
+
path: context.path
|
|
437
|
+
};
|
|
438
|
+
if (partialEqualInternal(targetElement, element, tempContext)) {
|
|
439
|
+
found = true;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (!found) {
|
|
444
|
+
addError(context, {
|
|
445
|
+
message: "Array does not contain expected element",
|
|
446
|
+
received: target,
|
|
447
|
+
expected: element
|
|
448
|
+
});
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
case "arrayContainsInOrder": {
|
|
455
|
+
if (!Array.isArray(target)) {
|
|
456
|
+
addError(context, {
|
|
457
|
+
message: "Expected array",
|
|
458
|
+
received: target
|
|
459
|
+
});
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
let targetIndex = 0;
|
|
463
|
+
for (const element of value) {
|
|
464
|
+
let found = false;
|
|
465
|
+
for (let i = targetIndex; i < target.length; i++) {
|
|
466
|
+
const tempContext = {
|
|
467
|
+
errors: [],
|
|
468
|
+
path: context.path
|
|
469
|
+
};
|
|
470
|
+
if (partialEqualInternal(target[i], element, tempContext)) {
|
|
471
|
+
targetIndex = i + 1;
|
|
472
|
+
found = true;
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (!found) {
|
|
477
|
+
addError(context, {
|
|
478
|
+
message: "Array does not contain expected elements in order",
|
|
479
|
+
received: target,
|
|
480
|
+
expected: value
|
|
481
|
+
});
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
case "arrayStartsWith": {
|
|
488
|
+
if (!Array.isArray(target)) {
|
|
489
|
+
addError(context, {
|
|
490
|
+
message: "Expected array",
|
|
491
|
+
received: target
|
|
492
|
+
});
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
if (target.length < value.length) {
|
|
496
|
+
addError(context, {
|
|
497
|
+
message: `Array too short: expected to start with ${value.length} elements, got ${target.length}`,
|
|
498
|
+
received: target,
|
|
499
|
+
expected: value
|
|
500
|
+
});
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
let allMatch = true;
|
|
504
|
+
for (let i = 0; i < value.length; i++) {
|
|
505
|
+
const oldPath = context.path;
|
|
506
|
+
context.path = [...oldPath, `[${i}]`];
|
|
507
|
+
const result = partialEqualInternal(target[i], value[i], context);
|
|
508
|
+
context.path = oldPath;
|
|
509
|
+
if (!result) allMatch = false;
|
|
510
|
+
}
|
|
511
|
+
return allMatch;
|
|
512
|
+
}
|
|
513
|
+
case "arrayEndsWith": {
|
|
514
|
+
if (!Array.isArray(target)) {
|
|
515
|
+
addError(context, {
|
|
516
|
+
message: "Expected array",
|
|
517
|
+
received: target
|
|
518
|
+
});
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
if (target.length < value.length) {
|
|
522
|
+
addError(context, {
|
|
523
|
+
message: `Array too short: expected to end with ${value.length} elements, got ${target.length}`,
|
|
524
|
+
received: target,
|
|
525
|
+
expected: value
|
|
526
|
+
});
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
let allMatch = true;
|
|
530
|
+
const startIndex = target.length - value.length;
|
|
531
|
+
for (let i = 0; i < value.length; i++) {
|
|
532
|
+
const oldPath = context.path;
|
|
533
|
+
context.path = [...oldPath, `[${startIndex + i}]`];
|
|
534
|
+
const result = partialEqualInternal(
|
|
535
|
+
target[startIndex + i],
|
|
536
|
+
value[i],
|
|
537
|
+
context
|
|
538
|
+
);
|
|
539
|
+
context.path = oldPath;
|
|
540
|
+
if (!result) allMatch = false;
|
|
541
|
+
}
|
|
542
|
+
return allMatch;
|
|
543
|
+
}
|
|
544
|
+
case "arrayLength": {
|
|
545
|
+
if (!Array.isArray(target)) {
|
|
546
|
+
addError(context, {
|
|
547
|
+
message: "Expected array",
|
|
548
|
+
received: target
|
|
549
|
+
});
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
if (target.length !== value) {
|
|
553
|
+
addError(context, {
|
|
554
|
+
message: `Expected array length ${value}, got ${target.length}`,
|
|
555
|
+
received: target
|
|
556
|
+
});
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
case "arrayMinLength": {
|
|
562
|
+
if (!Array.isArray(target)) {
|
|
563
|
+
addError(context, {
|
|
564
|
+
message: "Expected array",
|
|
565
|
+
received: target
|
|
566
|
+
});
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
if (target.length < value) {
|
|
570
|
+
addError(context, {
|
|
571
|
+
message: `Expected array with at least ${value} elements, got ${target.length}`,
|
|
572
|
+
received: target
|
|
573
|
+
});
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
case "arrayMaxLength": {
|
|
579
|
+
if (!Array.isArray(target)) {
|
|
580
|
+
addError(context, {
|
|
581
|
+
message: "Expected array",
|
|
582
|
+
received: target
|
|
583
|
+
});
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
if (target.length > value) {
|
|
587
|
+
addError(context, {
|
|
588
|
+
message: `Expected array with at most ${value} elements, got ${target.length}`,
|
|
589
|
+
received: target
|
|
590
|
+
});
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
case "arrayIncludes": {
|
|
596
|
+
if (!Array.isArray(target)) {
|
|
597
|
+
addError(context, {
|
|
598
|
+
message: "Expected array",
|
|
599
|
+
received: target
|
|
600
|
+
});
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
let found = false;
|
|
604
|
+
for (const targetElement of target) {
|
|
605
|
+
const tempContext = {
|
|
606
|
+
errors: [],
|
|
607
|
+
path: context.path
|
|
608
|
+
};
|
|
609
|
+
if (partialEqualInternal(targetElement, value, tempContext)) {
|
|
610
|
+
found = true;
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (!found) {
|
|
615
|
+
addError(context, {
|
|
616
|
+
message: "Array does not include expected element",
|
|
617
|
+
received: target,
|
|
618
|
+
expected: value
|
|
619
|
+
});
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
case "arrayEvery": {
|
|
625
|
+
if (!Array.isArray(target)) {
|
|
626
|
+
addError(context, {
|
|
627
|
+
message: "Expected array",
|
|
628
|
+
received: target
|
|
629
|
+
});
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
let allMatch = true;
|
|
633
|
+
for (let i = 0; i < target.length; i++) {
|
|
634
|
+
const oldPath = context.path;
|
|
635
|
+
context.path = [...oldPath, `[${i}]`];
|
|
636
|
+
const result = executeComparison(target[i], value, context);
|
|
637
|
+
context.path = oldPath;
|
|
638
|
+
if (!result) allMatch = false;
|
|
639
|
+
}
|
|
640
|
+
return allMatch;
|
|
641
|
+
}
|
|
642
|
+
case "arraySome": {
|
|
643
|
+
if (!Array.isArray(target)) {
|
|
644
|
+
addError(context, {
|
|
645
|
+
message: "Expected array",
|
|
646
|
+
received: target
|
|
647
|
+
});
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
for (let i = 0; i < target.length; i++) {
|
|
651
|
+
const tempContext = {
|
|
652
|
+
errors: [],
|
|
653
|
+
path: [...context.path, `[${i}]`]
|
|
654
|
+
};
|
|
655
|
+
if (executeComparison(target[i], value, tempContext)) {
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
addError(context, {
|
|
660
|
+
message: "No array element matches the condition",
|
|
661
|
+
received: target
|
|
662
|
+
});
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
399
665
|
default:
|
|
400
666
|
throw exhaustiveCheck(type);
|
|
401
667
|
}
|
package/dist/partialEqual.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ import { Result } from 't-result';
|
|
|
3
3
|
type ComparisonsType = [type: 'strStartsWith', value: string] | [type: 'strEndsWith', value: string] | [
|
|
4
4
|
type: 'hasType',
|
|
5
5
|
value: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'function'
|
|
6
|
-
] | [type: 'strContains', value: string] | [type: 'strMatchesRegex', value: RegExp] | [type: 'deepEqual', value: any] | [type: 'numIsGreaterThan', value: number] | [type: 'numIsGreaterThanOrEqual', value: number] | [type: 'numIsLessThan', value: number] | [type: 'numIsLessThanOrEqual', value: number] | [type: 'numIsInRange', value: [number, number]] | [type: 'jsonStringHasPartial', value: any] | [type: 'partialEqual', value: any] | [type: 'custom', value: (target: unknown) => boolean | {
|
|
6
|
+
] | [type: 'strContains', value: string] | [type: 'strMatchesRegex', value: RegExp] | [type: 'deepEqual', value: any] | [type: 'numIsGreaterThan', value: number] | [type: 'numIsGreaterThanOrEqual', value: number] | [type: 'numIsLessThan', value: number] | [type: 'numIsLessThanOrEqual', value: number] | [type: 'numIsInRange', value: [number, number]] | [type: 'arrayContains', value: any[]] | [type: 'arrayContainsInOrder', value: any[]] | [type: 'arrayStartsWith', value: any[]] | [type: 'arrayEndsWith', value: any[]] | [type: 'arrayLength', value: number] | [type: 'arrayMinLength', value: number] | [type: 'arrayMaxLength', value: number] | [type: 'arrayIncludes', value: any] | [type: 'arrayEvery', value: ComparisonsType] | [type: 'arraySome', value: ComparisonsType] | [type: 'jsonStringHasPartial', value: any] | [type: 'partialEqual', value: any] | [type: 'custom', value: (target: unknown) => boolean | {
|
|
7
7
|
error: string;
|
|
8
8
|
}] | [type: 'isInstanceOf', value: new (...args: any[]) => any] | [type: 'keyNotBePresent', value: null] | [type: 'not', value: ComparisonsType] | [type: 'any', value: ComparisonsType[]] | [type: 'all', value: ComparisonsType[]] | [type: 'withNoExtraKeys', partialShape: any] | [type: 'withDeepNoExtraKeys', partialShape: any] | [type: 'noExtraDefinedKeys', partialShape: any] | [type: 'deepNoExtraDefinedKeys', partialShape: any];
|
|
9
9
|
type Comparison = {
|
|
@@ -36,6 +36,18 @@ type BaseMatch = {
|
|
|
36
36
|
isLessThanOrEqual: (value: number) => Comparison;
|
|
37
37
|
isInRange: (value: [number, number]) => Comparison;
|
|
38
38
|
};
|
|
39
|
+
array: {
|
|
40
|
+
contains: (elements: any[]) => Comparison;
|
|
41
|
+
containsInOrder: (elements: any[]) => Comparison;
|
|
42
|
+
startsWith: (elements: any[]) => Comparison;
|
|
43
|
+
endsWith: (elements: any[]) => Comparison;
|
|
44
|
+
length: (n: number) => Comparison;
|
|
45
|
+
minLength: (n: number) => Comparison;
|
|
46
|
+
maxLength: (n: number) => Comparison;
|
|
47
|
+
includes: (element: any) => Comparison;
|
|
48
|
+
every: (matcher: Comparison) => Comparison;
|
|
49
|
+
some: (matcher: Comparison) => Comparison;
|
|
50
|
+
};
|
|
39
51
|
jsonString: {
|
|
40
52
|
hasPartial: (value: any) => Comparison;
|
|
41
53
|
};
|
|
@@ -66,7 +78,21 @@ type PartialError = {
|
|
|
66
78
|
* @example
|
|
67
79
|
* // Basic partial matching
|
|
68
80
|
* partialEqual({ a: 1, b: 2 }, { a: 1 }); // true - sub is subset of target
|
|
69
|
-
* partialEqual([1, 2, 3], [1, 2]); // true - sub array is prefix of target
|
|
81
|
+
* partialEqual([1, 2, 3], [1, 2]); // true - sub array is prefix of target (default behavior)
|
|
82
|
+
*
|
|
83
|
+
* // Array matching (default behavior: prefix matching)
|
|
84
|
+
* partialEqual([1, 2, 3, 4], [1, 2]); // true - checks first 2 elements
|
|
85
|
+
* partialEqual([1, 3, 4], [1, 2]); // false - second element doesn't match
|
|
86
|
+
*
|
|
87
|
+
* // Advanced array matchers for flexible matching
|
|
88
|
+
* partialEqual([1, 2, 3, 4, 5], match.array.contains([3, 1])); // true - contains elements anywhere
|
|
89
|
+
* partialEqual([1, 2, 3, 4, 5], match.array.containsInOrder([2, 4])); // true - contains in order (non-consecutive)
|
|
90
|
+
* partialEqual([1, 2, 3], match.array.startsWith([1, 2])); // true - explicit prefix matching
|
|
91
|
+
* partialEqual([1, 2, 3], match.array.endsWith([2, 3])); // true - suffix matching
|
|
92
|
+
* partialEqual([1, 2, 3], match.array.length(3)); // true - exact length
|
|
93
|
+
* partialEqual([1, 2, 3], match.array.includes(2)); // true - includes element
|
|
94
|
+
* partialEqual([10, 20, 30], match.array.every(match.num.isGreaterThan(5))); // true - all elements match
|
|
95
|
+
* partialEqual([1, 10, 3], match.array.some(match.num.isGreaterThan(8))); // true - at least one matches
|
|
70
96
|
*
|
|
71
97
|
* // Special comparisons
|
|
72
98
|
* partialEqual('hello world', match.str.contains('world')); // true
|
package/dist/partialEqual.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Result } from 't-result';
|
|
|
3
3
|
type ComparisonsType = [type: 'strStartsWith', value: string] | [type: 'strEndsWith', value: string] | [
|
|
4
4
|
type: 'hasType',
|
|
5
5
|
value: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'function'
|
|
6
|
-
] | [type: 'strContains', value: string] | [type: 'strMatchesRegex', value: RegExp] | [type: 'deepEqual', value: any] | [type: 'numIsGreaterThan', value: number] | [type: 'numIsGreaterThanOrEqual', value: number] | [type: 'numIsLessThan', value: number] | [type: 'numIsLessThanOrEqual', value: number] | [type: 'numIsInRange', value: [number, number]] | [type: 'jsonStringHasPartial', value: any] | [type: 'partialEqual', value: any] | [type: 'custom', value: (target: unknown) => boolean | {
|
|
6
|
+
] | [type: 'strContains', value: string] | [type: 'strMatchesRegex', value: RegExp] | [type: 'deepEqual', value: any] | [type: 'numIsGreaterThan', value: number] | [type: 'numIsGreaterThanOrEqual', value: number] | [type: 'numIsLessThan', value: number] | [type: 'numIsLessThanOrEqual', value: number] | [type: 'numIsInRange', value: [number, number]] | [type: 'arrayContains', value: any[]] | [type: 'arrayContainsInOrder', value: any[]] | [type: 'arrayStartsWith', value: any[]] | [type: 'arrayEndsWith', value: any[]] | [type: 'arrayLength', value: number] | [type: 'arrayMinLength', value: number] | [type: 'arrayMaxLength', value: number] | [type: 'arrayIncludes', value: any] | [type: 'arrayEvery', value: ComparisonsType] | [type: 'arraySome', value: ComparisonsType] | [type: 'jsonStringHasPartial', value: any] | [type: 'partialEqual', value: any] | [type: 'custom', value: (target: unknown) => boolean | {
|
|
7
7
|
error: string;
|
|
8
8
|
}] | [type: 'isInstanceOf', value: new (...args: any[]) => any] | [type: 'keyNotBePresent', value: null] | [type: 'not', value: ComparisonsType] | [type: 'any', value: ComparisonsType[]] | [type: 'all', value: ComparisonsType[]] | [type: 'withNoExtraKeys', partialShape: any] | [type: 'withDeepNoExtraKeys', partialShape: any] | [type: 'noExtraDefinedKeys', partialShape: any] | [type: 'deepNoExtraDefinedKeys', partialShape: any];
|
|
9
9
|
type Comparison = {
|
|
@@ -36,6 +36,18 @@ type BaseMatch = {
|
|
|
36
36
|
isLessThanOrEqual: (value: number) => Comparison;
|
|
37
37
|
isInRange: (value: [number, number]) => Comparison;
|
|
38
38
|
};
|
|
39
|
+
array: {
|
|
40
|
+
contains: (elements: any[]) => Comparison;
|
|
41
|
+
containsInOrder: (elements: any[]) => Comparison;
|
|
42
|
+
startsWith: (elements: any[]) => Comparison;
|
|
43
|
+
endsWith: (elements: any[]) => Comparison;
|
|
44
|
+
length: (n: number) => Comparison;
|
|
45
|
+
minLength: (n: number) => Comparison;
|
|
46
|
+
maxLength: (n: number) => Comparison;
|
|
47
|
+
includes: (element: any) => Comparison;
|
|
48
|
+
every: (matcher: Comparison) => Comparison;
|
|
49
|
+
some: (matcher: Comparison) => Comparison;
|
|
50
|
+
};
|
|
39
51
|
jsonString: {
|
|
40
52
|
hasPartial: (value: any) => Comparison;
|
|
41
53
|
};
|
|
@@ -66,7 +78,21 @@ type PartialError = {
|
|
|
66
78
|
* @example
|
|
67
79
|
* // Basic partial matching
|
|
68
80
|
* partialEqual({ a: 1, b: 2 }, { a: 1 }); // true - sub is subset of target
|
|
69
|
-
* partialEqual([1, 2, 3], [1, 2]); // true - sub array is prefix of target
|
|
81
|
+
* partialEqual([1, 2, 3], [1, 2]); // true - sub array is prefix of target (default behavior)
|
|
82
|
+
*
|
|
83
|
+
* // Array matching (default behavior: prefix matching)
|
|
84
|
+
* partialEqual([1, 2, 3, 4], [1, 2]); // true - checks first 2 elements
|
|
85
|
+
* partialEqual([1, 3, 4], [1, 2]); // false - second element doesn't match
|
|
86
|
+
*
|
|
87
|
+
* // Advanced array matchers for flexible matching
|
|
88
|
+
* partialEqual([1, 2, 3, 4, 5], match.array.contains([3, 1])); // true - contains elements anywhere
|
|
89
|
+
* partialEqual([1, 2, 3, 4, 5], match.array.containsInOrder([2, 4])); // true - contains in order (non-consecutive)
|
|
90
|
+
* partialEqual([1, 2, 3], match.array.startsWith([1, 2])); // true - explicit prefix matching
|
|
91
|
+
* partialEqual([1, 2, 3], match.array.endsWith([2, 3])); // true - suffix matching
|
|
92
|
+
* partialEqual([1, 2, 3], match.array.length(3)); // true - exact length
|
|
93
|
+
* partialEqual([1, 2, 3], match.array.includes(2)); // true - includes element
|
|
94
|
+
* partialEqual([10, 20, 30], match.array.every(match.num.isGreaterThan(5))); // true - all elements match
|
|
95
|
+
* partialEqual([1, 10, 3], match.array.some(match.num.isGreaterThan(8))); // true - at least one matches
|
|
70
96
|
*
|
|
71
97
|
* // Special comparisons
|
|
72
98
|
* partialEqual('hello world', match.str.contains('world')); // true
|
package/dist/partialEqual.js
CHANGED
|
@@ -36,6 +36,18 @@ var match = {
|
|
|
36
36
|
isLessThanOrEqual: (value) => createComparison(["numIsLessThanOrEqual", value]),
|
|
37
37
|
isInRange: (value) => createComparison(["numIsInRange", value])
|
|
38
38
|
},
|
|
39
|
+
array: {
|
|
40
|
+
contains: (elements) => createComparison(["arrayContains", elements]),
|
|
41
|
+
containsInOrder: (elements) => createComparison(["arrayContainsInOrder", elements]),
|
|
42
|
+
startsWith: (elements) => createComparison(["arrayStartsWith", elements]),
|
|
43
|
+
endsWith: (elements) => createComparison(["arrayEndsWith", elements]),
|
|
44
|
+
length: (n) => createComparison(["arrayLength", n]),
|
|
45
|
+
minLength: (n) => createComparison(["arrayMinLength", n]),
|
|
46
|
+
maxLength: (n) => createComparison(["arrayMaxLength", n]),
|
|
47
|
+
includes: (element) => createComparison(["arrayIncludes", element]),
|
|
48
|
+
every: (matcher) => createComparison(["arrayEvery", matcher["~sc"]]),
|
|
49
|
+
some: (matcher) => createComparison(["arraySome", matcher["~sc"]])
|
|
50
|
+
},
|
|
39
51
|
jsonString: {
|
|
40
52
|
hasPartial: (value) => createComparison(["jsonStringHasPartial", value])
|
|
41
53
|
},
|
|
@@ -85,6 +97,18 @@ var match = {
|
|
|
85
97
|
isLessThanOrEqual: (value) => createComparison(["not", ["numIsLessThanOrEqual", value]]),
|
|
86
98
|
isInRange: (value) => createComparison(["not", ["numIsInRange", value]])
|
|
87
99
|
},
|
|
100
|
+
array: {
|
|
101
|
+
contains: (elements) => createComparison(["not", ["arrayContains", elements]]),
|
|
102
|
+
containsInOrder: (elements) => createComparison(["not", ["arrayContainsInOrder", elements]]),
|
|
103
|
+
startsWith: (elements) => createComparison(["not", ["arrayStartsWith", elements]]),
|
|
104
|
+
endsWith: (elements) => createComparison(["not", ["arrayEndsWith", elements]]),
|
|
105
|
+
length: (n) => createComparison(["not", ["arrayLength", n]]),
|
|
106
|
+
minLength: (n) => createComparison(["not", ["arrayMinLength", n]]),
|
|
107
|
+
maxLength: (n) => createComparison(["not", ["arrayMaxLength", n]]),
|
|
108
|
+
includes: (element) => createComparison(["not", ["arrayIncludes", element]]),
|
|
109
|
+
every: (matcher) => createComparison(["not", ["arrayEvery", matcher["~sc"]]]),
|
|
110
|
+
some: (matcher) => createComparison(["not", ["arraySome", matcher["~sc"]]])
|
|
111
|
+
},
|
|
88
112
|
jsonString: {
|
|
89
113
|
hasPartial: (value) => createComparison(["not", ["jsonStringHasPartial", value]])
|
|
90
114
|
},
|
|
@@ -369,6 +393,248 @@ function executeComparison(target, comparison, context) {
|
|
|
369
393
|
return checkNoExtraDefinedKeys(target, value, context, false);
|
|
370
394
|
case "deepNoExtraDefinedKeys":
|
|
371
395
|
return checkNoExtraDefinedKeys(target, value, context, true);
|
|
396
|
+
case "arrayContains": {
|
|
397
|
+
if (!Array.isArray(target)) {
|
|
398
|
+
addError(context, {
|
|
399
|
+
message: "Expected array",
|
|
400
|
+
received: target
|
|
401
|
+
});
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
for (const element of value) {
|
|
405
|
+
let found = false;
|
|
406
|
+
for (const targetElement of target) {
|
|
407
|
+
const tempContext = {
|
|
408
|
+
errors: [],
|
|
409
|
+
path: context.path
|
|
410
|
+
};
|
|
411
|
+
if (partialEqualInternal(targetElement, element, tempContext)) {
|
|
412
|
+
found = true;
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (!found) {
|
|
417
|
+
addError(context, {
|
|
418
|
+
message: "Array does not contain expected element",
|
|
419
|
+
received: target,
|
|
420
|
+
expected: element
|
|
421
|
+
});
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
case "arrayContainsInOrder": {
|
|
428
|
+
if (!Array.isArray(target)) {
|
|
429
|
+
addError(context, {
|
|
430
|
+
message: "Expected array",
|
|
431
|
+
received: target
|
|
432
|
+
});
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
let targetIndex = 0;
|
|
436
|
+
for (const element of value) {
|
|
437
|
+
let found = false;
|
|
438
|
+
for (let i = targetIndex; i < target.length; i++) {
|
|
439
|
+
const tempContext = {
|
|
440
|
+
errors: [],
|
|
441
|
+
path: context.path
|
|
442
|
+
};
|
|
443
|
+
if (partialEqualInternal(target[i], element, tempContext)) {
|
|
444
|
+
targetIndex = i + 1;
|
|
445
|
+
found = true;
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (!found) {
|
|
450
|
+
addError(context, {
|
|
451
|
+
message: "Array does not contain expected elements in order",
|
|
452
|
+
received: target,
|
|
453
|
+
expected: value
|
|
454
|
+
});
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
460
|
+
case "arrayStartsWith": {
|
|
461
|
+
if (!Array.isArray(target)) {
|
|
462
|
+
addError(context, {
|
|
463
|
+
message: "Expected array",
|
|
464
|
+
received: target
|
|
465
|
+
});
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
if (target.length < value.length) {
|
|
469
|
+
addError(context, {
|
|
470
|
+
message: `Array too short: expected to start with ${value.length} elements, got ${target.length}`,
|
|
471
|
+
received: target,
|
|
472
|
+
expected: value
|
|
473
|
+
});
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
let allMatch = true;
|
|
477
|
+
for (let i = 0; i < value.length; i++) {
|
|
478
|
+
const oldPath = context.path;
|
|
479
|
+
context.path = [...oldPath, `[${i}]`];
|
|
480
|
+
const result = partialEqualInternal(target[i], value[i], context);
|
|
481
|
+
context.path = oldPath;
|
|
482
|
+
if (!result) allMatch = false;
|
|
483
|
+
}
|
|
484
|
+
return allMatch;
|
|
485
|
+
}
|
|
486
|
+
case "arrayEndsWith": {
|
|
487
|
+
if (!Array.isArray(target)) {
|
|
488
|
+
addError(context, {
|
|
489
|
+
message: "Expected array",
|
|
490
|
+
received: target
|
|
491
|
+
});
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
if (target.length < value.length) {
|
|
495
|
+
addError(context, {
|
|
496
|
+
message: `Array too short: expected to end with ${value.length} elements, got ${target.length}`,
|
|
497
|
+
received: target,
|
|
498
|
+
expected: value
|
|
499
|
+
});
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
let allMatch = true;
|
|
503
|
+
const startIndex = target.length - value.length;
|
|
504
|
+
for (let i = 0; i < value.length; i++) {
|
|
505
|
+
const oldPath = context.path;
|
|
506
|
+
context.path = [...oldPath, `[${startIndex + i}]`];
|
|
507
|
+
const result = partialEqualInternal(
|
|
508
|
+
target[startIndex + i],
|
|
509
|
+
value[i],
|
|
510
|
+
context
|
|
511
|
+
);
|
|
512
|
+
context.path = oldPath;
|
|
513
|
+
if (!result) allMatch = false;
|
|
514
|
+
}
|
|
515
|
+
return allMatch;
|
|
516
|
+
}
|
|
517
|
+
case "arrayLength": {
|
|
518
|
+
if (!Array.isArray(target)) {
|
|
519
|
+
addError(context, {
|
|
520
|
+
message: "Expected array",
|
|
521
|
+
received: target
|
|
522
|
+
});
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
if (target.length !== value) {
|
|
526
|
+
addError(context, {
|
|
527
|
+
message: `Expected array length ${value}, got ${target.length}`,
|
|
528
|
+
received: target
|
|
529
|
+
});
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
case "arrayMinLength": {
|
|
535
|
+
if (!Array.isArray(target)) {
|
|
536
|
+
addError(context, {
|
|
537
|
+
message: "Expected array",
|
|
538
|
+
received: target
|
|
539
|
+
});
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
if (target.length < value) {
|
|
543
|
+
addError(context, {
|
|
544
|
+
message: `Expected array with at least ${value} elements, got ${target.length}`,
|
|
545
|
+
received: target
|
|
546
|
+
});
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
case "arrayMaxLength": {
|
|
552
|
+
if (!Array.isArray(target)) {
|
|
553
|
+
addError(context, {
|
|
554
|
+
message: "Expected array",
|
|
555
|
+
received: target
|
|
556
|
+
});
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
if (target.length > value) {
|
|
560
|
+
addError(context, {
|
|
561
|
+
message: `Expected array with at most ${value} elements, got ${target.length}`,
|
|
562
|
+
received: target
|
|
563
|
+
});
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
return true;
|
|
567
|
+
}
|
|
568
|
+
case "arrayIncludes": {
|
|
569
|
+
if (!Array.isArray(target)) {
|
|
570
|
+
addError(context, {
|
|
571
|
+
message: "Expected array",
|
|
572
|
+
received: target
|
|
573
|
+
});
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
let found = false;
|
|
577
|
+
for (const targetElement of target) {
|
|
578
|
+
const tempContext = {
|
|
579
|
+
errors: [],
|
|
580
|
+
path: context.path
|
|
581
|
+
};
|
|
582
|
+
if (partialEqualInternal(targetElement, value, tempContext)) {
|
|
583
|
+
found = true;
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (!found) {
|
|
588
|
+
addError(context, {
|
|
589
|
+
message: "Array does not include expected element",
|
|
590
|
+
received: target,
|
|
591
|
+
expected: value
|
|
592
|
+
});
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
case "arrayEvery": {
|
|
598
|
+
if (!Array.isArray(target)) {
|
|
599
|
+
addError(context, {
|
|
600
|
+
message: "Expected array",
|
|
601
|
+
received: target
|
|
602
|
+
});
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
let allMatch = true;
|
|
606
|
+
for (let i = 0; i < target.length; i++) {
|
|
607
|
+
const oldPath = context.path;
|
|
608
|
+
context.path = [...oldPath, `[${i}]`];
|
|
609
|
+
const result = executeComparison(target[i], value, context);
|
|
610
|
+
context.path = oldPath;
|
|
611
|
+
if (!result) allMatch = false;
|
|
612
|
+
}
|
|
613
|
+
return allMatch;
|
|
614
|
+
}
|
|
615
|
+
case "arraySome": {
|
|
616
|
+
if (!Array.isArray(target)) {
|
|
617
|
+
addError(context, {
|
|
618
|
+
message: "Expected array",
|
|
619
|
+
received: target
|
|
620
|
+
});
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
for (let i = 0; i < target.length; i++) {
|
|
624
|
+
const tempContext = {
|
|
625
|
+
errors: [],
|
|
626
|
+
path: [...context.path, `[${i}]`]
|
|
627
|
+
};
|
|
628
|
+
if (executeComparison(target[i], value, tempContext)) {
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
addError(context, {
|
|
633
|
+
message: "No array element matches the condition",
|
|
634
|
+
received: target
|
|
635
|
+
});
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
372
638
|
default:
|
|
373
639
|
throw exhaustiveCheck(type);
|
|
374
640
|
}
|
package/dist/testUtils.cjs
CHANGED
package/dist/testUtils.js
CHANGED
package/dist/typeUtils.d.cts
CHANGED
|
@@ -56,5 +56,6 @@ type PickRequiredKeys<T> = {
|
|
|
56
56
|
[K in keyof T]: undefined extends T[K] ? never : K;
|
|
57
57
|
}[keyof T];
|
|
58
58
|
type MakeUndefinedKeysOptional<T> = Prettify<Partial<Pick<T, PickUndefinedKeys<T>>> & Pick<T, PickRequiredKeys<T>>>;
|
|
59
|
+
type StringWithAutoComplete<T extends string> = T | (string & {});
|
|
59
60
|
|
|
60
|
-
export type { DeepPrettify, DeepReplaceValue, DefaultSkipTransverseDeepReplace, IsAny, MakeUndefinedKeysOptional, NonPartial, ObjKeysWithValuesOfType, PartialPossiblyUndefinedValues, PartialRecord, Prettify };
|
|
61
|
+
export type { DeepPrettify, DeepReplaceValue, DefaultSkipTransverseDeepReplace, IsAny, MakeUndefinedKeysOptional, NonPartial, ObjKeysWithValuesOfType, PartialPossiblyUndefinedValues, PartialRecord, Prettify, StringWithAutoComplete };
|
package/dist/typeUtils.d.ts
CHANGED
|
@@ -56,5 +56,6 @@ type PickRequiredKeys<T> = {
|
|
|
56
56
|
[K in keyof T]: undefined extends T[K] ? never : K;
|
|
57
57
|
}[keyof T];
|
|
58
58
|
type MakeUndefinedKeysOptional<T> = Prettify<Partial<Pick<T, PickUndefinedKeys<T>>> & Pick<T, PickRequiredKeys<T>>>;
|
|
59
|
+
type StringWithAutoComplete<T extends string> = T | (string & {});
|
|
59
60
|
|
|
60
|
-
export type { DeepPrettify, DeepReplaceValue, DefaultSkipTransverseDeepReplace, IsAny, MakeUndefinedKeysOptional, NonPartial, ObjKeysWithValuesOfType, PartialPossiblyUndefinedValues, PartialRecord, Prettify };
|
|
61
|
+
export type { DeepPrettify, DeepReplaceValue, DefaultSkipTransverseDeepReplace, IsAny, MakeUndefinedKeysOptional, NonPartial, ObjKeysWithValuesOfType, PartialPossiblyUndefinedValues, PartialRecord, Prettify, StringWithAutoComplete };
|
package/package.json
CHANGED
package/dist/chunk-Y45CE75W.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
typedObjectEntries
|
|
3
|
-
} from "./chunk-GMJTLFM6.js";
|
|
4
|
-
import {
|
|
5
|
-
sortBy
|
|
6
|
-
} from "./chunk-27AL66CH.js";
|
|
7
|
-
|
|
8
|
-
// src/objUtils.ts
|
|
9
|
-
function objectTypedEntries(obj) {
|
|
10
|
-
return Object.entries(obj);
|
|
11
|
-
}
|
|
12
|
-
function pick(obj, keys) {
|
|
13
|
-
const result = {};
|
|
14
|
-
for (const key of keys) {
|
|
15
|
-
result[key] = obj[key];
|
|
16
|
-
}
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
function mapArrayToObject(array, mapper) {
|
|
20
|
-
return Object.fromEntries(array.map(mapper));
|
|
21
|
-
}
|
|
22
|
-
function mapObjectToObject(obj, mapper) {
|
|
23
|
-
return Object.fromEntries(
|
|
24
|
-
objectTypedEntries(obj).map(([key, value]) => mapper(key, value))
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
function omit(obj, keys) {
|
|
28
|
-
const result = {};
|
|
29
|
-
for (const key of Object.keys(obj)) {
|
|
30
|
-
if (!keys.includes(key)) {
|
|
31
|
-
result[key] = obj[key];
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return result;
|
|
35
|
-
}
|
|
36
|
-
function looseGetObjectProperty(obj, key) {
|
|
37
|
-
return obj[key];
|
|
38
|
-
}
|
|
39
|
-
function rejectObjUndefinedValues(obj) {
|
|
40
|
-
const result = {};
|
|
41
|
-
for (const key in obj) {
|
|
42
|
-
if (obj[key] !== void 0) {
|
|
43
|
-
result[key] = obj[key];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return result;
|
|
47
|
-
}
|
|
48
|
-
function filterObjectKeys(obj, predicate) {
|
|
49
|
-
return Object.fromEntries(
|
|
50
|
-
Object.entries(obj).filter(
|
|
51
|
-
([key, value]) => predicate(key, value)
|
|
52
|
-
)
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
function sortObjectKeys(obj, sortByFn, options) {
|
|
56
|
-
return Object.fromEntries(
|
|
57
|
-
sortBy(typedObjectEntries(obj), sortByFn, options)
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export {
|
|
62
|
-
objectTypedEntries,
|
|
63
|
-
pick,
|
|
64
|
-
mapArrayToObject,
|
|
65
|
-
mapObjectToObject,
|
|
66
|
-
omit,
|
|
67
|
-
looseGetObjectProperty,
|
|
68
|
-
rejectObjUndefinedValues,
|
|
69
|
-
filterObjectKeys,
|
|
70
|
-
sortObjectKeys
|
|
71
|
-
};
|