@ls-stack/utils 3.24.1 → 3.25.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/docs/_media/modules.md +1 -0
- package/docs/arrayUtils/-internal-.md +1 -1
- package/docs/arrayUtils/README.md +12 -12
- package/docs/consoleFmt.md +2 -2
- package/docs/exhaustiveMatch/-internal-.md +1 -1
- package/docs/exhaustiveMatch/README.md +1 -1
- package/docs/filterObjectOrArrayKeys.md +80 -0
- package/docs/modules.md +1 -0
- package/docs/objUtils.md +7 -7
- package/docs/parallelAsyncCalls/-internal-.md +3 -3
- package/docs/parallelAsyncCalls/README.md +1 -1
- package/docs/retryOnError/README.md +1 -1
- package/docs/runShellCmd/README.md +9 -9
- package/docs/safeJson.md +2 -2
- package/docs/saferTyping.md +7 -7
- package/docs/stringUtils/README.md +6 -6
- package/docs/testUtils.md +40 -6
- package/docs/time.md +1 -1
- package/docs/tsResult/README.md +17 -11
- package/docs/typingFnUtils/-internal-.md +1 -1
- package/docs/typingFnUtils/README.md +8 -10
- package/lib/arrayUtils.d.cts +6 -1
- package/lib/arrayUtils.d.ts +6 -1
- package/lib/{chunk-JAPKLFIK.js → chunk-QLD7KG5I.js} +34 -20
- package/lib/chunk-XXYTMSFH.js +240 -0
- package/lib/filterObjectOrArrayKeys.cjs +275 -0
- package/lib/filterObjectOrArrayKeys.d.cts +42 -0
- package/lib/filterObjectOrArrayKeys.d.ts +42 -0
- package/lib/filterObjectOrArrayKeys.js +7 -0
- package/lib/objUtils.d.cts +4 -1
- package/lib/objUtils.d.ts +4 -1
- package/lib/parallelAsyncCalls.cjs +4 -1
- package/lib/parallelAsyncCalls.d.cts +4 -1
- package/lib/parallelAsyncCalls.d.ts +4 -1
- package/lib/parallelAsyncCalls.js +4 -1
- package/lib/retryOnError.d.cts +2 -0
- package/lib/retryOnError.d.ts +2 -0
- package/lib/runShellCmd.d.cts +17 -0
- package/lib/runShellCmd.d.ts +17 -0
- package/lib/safeJson.d.cts +8 -2
- package/lib/safeJson.d.ts +8 -2
- package/lib/saferTyping.d.cts +3 -0
- package/lib/saferTyping.d.ts +3 -0
- package/lib/stringUtils.d.cts +1 -0
- package/lib/stringUtils.d.ts +1 -0
- package/lib/testUtils.cjs +273 -144
- package/lib/testUtils.d.cts +40 -12
- package/lib/testUtils.d.ts +40 -12
- package/lib/testUtils.js +10 -125
- package/lib/tsResult.d.cts +31 -7
- package/lib/tsResult.d.ts +31 -7
- package/lib/typingFnUtils.d.cts +20 -6
- package/lib/typingFnUtils.d.ts +20 -6
- package/lib/yamlStringify.cjs +34 -20
- package/lib/yamlStringify.js +1 -1
- package/package.json +5 -1
package/lib/testUtils.cjs
CHANGED
|
@@ -131,6 +131,239 @@ function deepEqual(foo, bar, maxDepth = 20) {
|
|
|
131
131
|
return foo !== foo && bar !== bar;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
// src/filterObjectOrArrayKeys.ts
|
|
135
|
+
function filterObjectOrArrayKeys(objOrArray, {
|
|
136
|
+
filterKeys,
|
|
137
|
+
rejectKeys,
|
|
138
|
+
rejectEmptyObjectsInArray = true
|
|
139
|
+
}) {
|
|
140
|
+
const toArray = (v) => v === void 0 ? [] : Array.isArray(v) ? v : [v];
|
|
141
|
+
const filterPatternsRaw = toArray(filterKeys);
|
|
142
|
+
const rejectPatternsRaw = toArray(rejectKeys);
|
|
143
|
+
const hasFilters = filterPatternsRaw.length > 0;
|
|
144
|
+
const hasRejects = rejectPatternsRaw.length > 0;
|
|
145
|
+
function parsePattern(pattern) {
|
|
146
|
+
const tokens = [];
|
|
147
|
+
let i = 0;
|
|
148
|
+
const n = pattern.length;
|
|
149
|
+
const pushKey = (name) => {
|
|
150
|
+
if (name.length === 0) return;
|
|
151
|
+
tokens.push({ type: "KEY", name });
|
|
152
|
+
};
|
|
153
|
+
while (i < n) {
|
|
154
|
+
const ch = pattern[i];
|
|
155
|
+
if (ch === ".") {
|
|
156
|
+
i += 1;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (ch === "[") {
|
|
160
|
+
const end = pattern.indexOf("]", i + 1);
|
|
161
|
+
const inside = end === -1 ? pattern.slice(i + 1) : pattern.slice(i + 1, end);
|
|
162
|
+
if (inside === "*") {
|
|
163
|
+
tokens.push({ type: "INDEX_ANY" });
|
|
164
|
+
} else if (inside.includes("-")) {
|
|
165
|
+
const parts = inside.split("-");
|
|
166
|
+
const startStr = parts[0] ?? "";
|
|
167
|
+
const endStr = parts[1] ?? "";
|
|
168
|
+
const start = parseInt(startStr, 10);
|
|
169
|
+
const endNum = endStr === "*" ? null : parseInt(endStr, 10);
|
|
170
|
+
tokens.push({
|
|
171
|
+
type: "INDEX_RANGE",
|
|
172
|
+
start,
|
|
173
|
+
end: endNum === null || Number.isFinite(endNum) ? endNum : null
|
|
174
|
+
});
|
|
175
|
+
} else if (inside.length > 0) {
|
|
176
|
+
const idx = parseInt(inside, 10);
|
|
177
|
+
tokens.push({ type: "INDEX", index: idx });
|
|
178
|
+
}
|
|
179
|
+
i = end === -1 ? n : end + 1;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (ch === "*") {
|
|
183
|
+
if (pattern[i + 1] === "*") {
|
|
184
|
+
tokens.push({ type: "WILDCARD_ANY" });
|
|
185
|
+
i += 2;
|
|
186
|
+
let j2 = i;
|
|
187
|
+
while (j2 < n) {
|
|
188
|
+
const c = pattern[j2];
|
|
189
|
+
if (c === "." || c === "[") break;
|
|
190
|
+
j2 += 1;
|
|
191
|
+
}
|
|
192
|
+
if (j2 > i) {
|
|
193
|
+
pushKey(pattern.slice(i, j2));
|
|
194
|
+
i = j2;
|
|
195
|
+
}
|
|
196
|
+
continue;
|
|
197
|
+
} else {
|
|
198
|
+
tokens.push({ type: "WILDCARD_ONE" });
|
|
199
|
+
i += 1;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
let j = i;
|
|
204
|
+
while (j < n) {
|
|
205
|
+
const c = pattern[j];
|
|
206
|
+
if (c === "." || c === "[") break;
|
|
207
|
+
j += 1;
|
|
208
|
+
}
|
|
209
|
+
pushKey(pattern.slice(i, j));
|
|
210
|
+
i = j;
|
|
211
|
+
}
|
|
212
|
+
return tokens;
|
|
213
|
+
}
|
|
214
|
+
const filterPatterns = filterPatternsRaw.map(parsePattern);
|
|
215
|
+
const rejectPatterns = rejectPatternsRaw.map(parsePattern);
|
|
216
|
+
function matchPath(path, pattern) {
|
|
217
|
+
function rec(pi, pti) {
|
|
218
|
+
if (pti >= pattern.length) return pi === path.length;
|
|
219
|
+
const pt = pattern[pti];
|
|
220
|
+
if (pt.type === "WILDCARD_ANY") {
|
|
221
|
+
if (rec(pi, pti + 1)) return true;
|
|
222
|
+
if (pi < path.length) return rec(pi + 1, pti);
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
if (pt.type === "WILDCARD_ONE") {
|
|
226
|
+
let j = pi;
|
|
227
|
+
let sawKey = false;
|
|
228
|
+
while (j < path.length) {
|
|
229
|
+
if (path[j].type === "KEY") sawKey = true;
|
|
230
|
+
if (sawKey && rec(j, pti + 1)) return true;
|
|
231
|
+
j += 1;
|
|
232
|
+
}
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
if (pi >= path.length) return false;
|
|
236
|
+
const ct = path[pi];
|
|
237
|
+
switch (pt.type) {
|
|
238
|
+
case "KEY":
|
|
239
|
+
if (ct.type === "KEY" && ct.name === pt.name)
|
|
240
|
+
return rec(pi + 1, pti + 1);
|
|
241
|
+
if (ct.type === "INDEX") return rec(pi + 1, pti);
|
|
242
|
+
return false;
|
|
243
|
+
case "INDEX":
|
|
244
|
+
if (ct.type === "INDEX" && ct.index === pt.index)
|
|
245
|
+
return rec(pi + 1, pti + 1);
|
|
246
|
+
return false;
|
|
247
|
+
case "INDEX_ANY":
|
|
248
|
+
if (ct.type === "INDEX") return rec(pi + 1, pti + 1);
|
|
249
|
+
return false;
|
|
250
|
+
case "INDEX_RANGE":
|
|
251
|
+
if (ct.type === "INDEX") {
|
|
252
|
+
const okLower = ct.index >= pt.start;
|
|
253
|
+
const okUpper = pt.end === null ? true : ct.index <= pt.end;
|
|
254
|
+
if (okLower && okUpper) return rec(pi + 1, pti + 1);
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return rec(0, 0);
|
|
260
|
+
}
|
|
261
|
+
const matchesAnyFilter = (path) => filterPatterns.some((p) => matchPath(path, p));
|
|
262
|
+
const matchesAnyReject = (path) => rejectPatterns.some((p) => matchPath(path, p));
|
|
263
|
+
const build = (value, path, allowedByFilter, stack2, isRoot, parentIsArray) => {
|
|
264
|
+
if (Array.isArray(value)) {
|
|
265
|
+
if (stack2.has(value)) {
|
|
266
|
+
throw new TypeError("Circular references are not supported");
|
|
267
|
+
}
|
|
268
|
+
stack2.add(value);
|
|
269
|
+
const out = [];
|
|
270
|
+
const includeAllChildren = allowedByFilter || !hasFilters;
|
|
271
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
272
|
+
const childPath = path.concat({ type: "INDEX", index });
|
|
273
|
+
if (hasRejects && matchesAnyReject(childPath)) continue;
|
|
274
|
+
const child = value[index];
|
|
275
|
+
const directInclude = hasFilters ? matchesAnyFilter(childPath) : true;
|
|
276
|
+
const childAllowed = includeAllChildren || directInclude;
|
|
277
|
+
if (isPlainObject(child) || Array.isArray(child)) {
|
|
278
|
+
const builtChild = build(
|
|
279
|
+
child,
|
|
280
|
+
childPath,
|
|
281
|
+
childAllowed,
|
|
282
|
+
stack2,
|
|
283
|
+
false,
|
|
284
|
+
true
|
|
285
|
+
);
|
|
286
|
+
if (builtChild !== void 0) {
|
|
287
|
+
out.push(builtChild);
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
if (childAllowed) {
|
|
291
|
+
out.push(child);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
stack2.delete(value);
|
|
296
|
+
const filteredOut = rejectEmptyObjectsInArray ? out.filter(
|
|
297
|
+
(item) => !(isPlainObject(item) && Object.keys(item).length === 0)
|
|
298
|
+
) : out;
|
|
299
|
+
if (filteredOut.length === 0 && !allowedByFilter && !isRoot)
|
|
300
|
+
return void 0;
|
|
301
|
+
return filteredOut;
|
|
302
|
+
}
|
|
303
|
+
if (isPlainObject(value)) {
|
|
304
|
+
if (stack2.has(value)) {
|
|
305
|
+
throw new TypeError("Circular references are not supported");
|
|
306
|
+
}
|
|
307
|
+
stack2.add(value);
|
|
308
|
+
const result = {};
|
|
309
|
+
const includeAllChildren = allowedByFilter || !hasFilters;
|
|
310
|
+
for (const key of Object.keys(value)) {
|
|
311
|
+
const childPath = path.concat({ type: "KEY", name: key });
|
|
312
|
+
if (hasRejects && matchesAnyReject(childPath)) continue;
|
|
313
|
+
const val = value[key];
|
|
314
|
+
const directInclude = hasFilters ? matchesAnyFilter(childPath) : true;
|
|
315
|
+
const childAllowed = includeAllChildren || directInclude;
|
|
316
|
+
if (isPlainObject(val) || Array.isArray(val)) {
|
|
317
|
+
const builtChild = build(
|
|
318
|
+
val,
|
|
319
|
+
childPath,
|
|
320
|
+
childAllowed,
|
|
321
|
+
stack2,
|
|
322
|
+
false,
|
|
323
|
+
false
|
|
324
|
+
);
|
|
325
|
+
if (builtChild === void 0) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (Array.isArray(builtChild) && builtChild.length === 0 && !childAllowed) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (isPlainObject(builtChild) && Object.keys(builtChild).length === 0 && !childAllowed) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
result[key] = builtChild;
|
|
335
|
+
} else {
|
|
336
|
+
if (childAllowed) {
|
|
337
|
+
result[key] = val;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
stack2.delete(value);
|
|
342
|
+
if (Object.keys(result).length === 0 && !allowedByFilter && !isRoot) {
|
|
343
|
+
if (parentIsArray && !rejectEmptyObjectsInArray) {
|
|
344
|
+
return {};
|
|
345
|
+
}
|
|
346
|
+
return void 0;
|
|
347
|
+
}
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
350
|
+
return allowedByFilter || !hasFilters ? value : void 0;
|
|
351
|
+
};
|
|
352
|
+
const startPath = [];
|
|
353
|
+
const initialAllowed = !hasFilters;
|
|
354
|
+
const stack = /* @__PURE__ */ new WeakSet();
|
|
355
|
+
const built = build(
|
|
356
|
+
objOrArray,
|
|
357
|
+
startPath,
|
|
358
|
+
initialAllowed,
|
|
359
|
+
stack,
|
|
360
|
+
true,
|
|
361
|
+
false
|
|
362
|
+
);
|
|
363
|
+
if (built === void 0) return Array.isArray(objOrArray) ? [] : {};
|
|
364
|
+
return built;
|
|
365
|
+
}
|
|
366
|
+
|
|
134
367
|
// src/mathUtils.ts
|
|
135
368
|
function clampMin(value, min) {
|
|
136
369
|
return value < min ? min : value;
|
|
@@ -197,12 +430,12 @@ function yamlStringify(obj, {
|
|
|
197
430
|
addRootObjSpaces = "beforeAndAfter"
|
|
198
431
|
} = {}) {
|
|
199
432
|
if (isObject(obj) || Array.isArray(obj) || typeof obj === "function") {
|
|
200
|
-
return `${stringifyValue(obj, "", maxLineLength, !!showUndefined, maxDepth, 0, collapseObjects, addRootObjSpaces)}
|
|
433
|
+
return `${stringifyValue(obj, "", maxLineLength, !!showUndefined, maxDepth, 0, collapseObjects, addRootObjSpaces, false)}
|
|
201
434
|
`;
|
|
202
435
|
}
|
|
203
436
|
return JSON.stringify(obj) || "undefined";
|
|
204
437
|
}
|
|
205
|
-
function stringifyValue(value, indent, maxLineLength, showUndefined, maxDepth, depth, collapseObjects, addObjSpaces) {
|
|
438
|
+
function stringifyValue(value, indent, maxLineLength, showUndefined, maxDepth, depth, collapseObjects, addObjSpaces, isArrayItem) {
|
|
206
439
|
let result = "";
|
|
207
440
|
const childIndent = `${indent} `;
|
|
208
441
|
if (isPlainObject(value)) {
|
|
@@ -221,7 +454,8 @@ function stringifyValue(value, indent, maxLineLength, showUndefined, maxDepth, d
|
|
|
221
454
|
return typeof val === "number" || typeof val === "boolean" || val === null || val === void 0;
|
|
222
455
|
}
|
|
223
456
|
);
|
|
224
|
-
|
|
457
|
+
const shouldCollapse = isArrayItem ? entries.length > 1 : entries.length > 0;
|
|
458
|
+
if (isSimpleObject && shouldCollapse) {
|
|
225
459
|
let line = "{ ";
|
|
226
460
|
line += entries.map(([key, val]) => {
|
|
227
461
|
let valueStr;
|
|
@@ -268,20 +502,29 @@ function stringifyValue(value, indent, maxLineLength, showUndefined, maxDepth, d
|
|
|
268
502
|
maxDepth,
|
|
269
503
|
depth + 1,
|
|
270
504
|
collapseObjects,
|
|
271
|
-
addObjSpaces
|
|
505
|
+
addObjSpaces,
|
|
506
|
+
false
|
|
272
507
|
);
|
|
273
|
-
const willBeCollapsed = isObject(objVal) && (Object.keys(objVal).length === 0 || collapseObjects && depth + 1 > 0 &&
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
508
|
+
const willBeCollapsed = isObject(objVal) && (Object.keys(objVal).length === 0 || collapseObjects && depth + 1 > 0 && (() => {
|
|
509
|
+
const filteredEntries = Object.entries(objVal).filter(([, val]) => val !== void 0 || showUndefined);
|
|
510
|
+
const shouldCollapseThis = isArrayItem ? filteredEntries.length > 1 : filteredEntries.length > 0;
|
|
511
|
+
return shouldCollapseThis && filteredEntries.every(([, val]) => {
|
|
512
|
+
if (typeof val === "string") {
|
|
513
|
+
return !val.includes("'") && !val.includes('"') && !val.includes("\\");
|
|
514
|
+
}
|
|
515
|
+
return typeof val === "number" || typeof val === "boolean" || val === null || val === void 0;
|
|
516
|
+
});
|
|
517
|
+
})());
|
|
518
|
+
const prevWasCollapsed = prevValue && isObject(prevValue) && (Object.keys(prevValue).length === 0 || collapseObjects && depth + 1 > 0 && (() => {
|
|
519
|
+
const filteredEntries = Object.entries(prevValue).filter(([, val]) => val !== void 0 || showUndefined);
|
|
520
|
+
const shouldCollapseThis = isArrayItem ? filteredEntries.length > 1 : filteredEntries.length > 0;
|
|
521
|
+
return shouldCollapseThis && filteredEntries.every(([, val]) => {
|
|
522
|
+
if (typeof val === "string") {
|
|
523
|
+
return !val.includes("'") && !val.includes('"') && !val.includes("\\");
|
|
524
|
+
}
|
|
525
|
+
return typeof val === "number" || typeof val === "boolean" || val === null || val === void 0;
|
|
526
|
+
});
|
|
527
|
+
})());
|
|
285
528
|
if (!afterSpaceWasAdded && indent === "" && isObject(objVal) && !willBeCollapsed && prevValue && !prevWasCollapsed && (addObjSpaces === "before" || addObjSpaces === "beforeAndAfter")) {
|
|
286
529
|
result += "\n";
|
|
287
530
|
}
|
|
@@ -344,7 +587,8 @@ function stringifyValue(value, indent, maxLineLength, showUndefined, maxDepth, d
|
|
|
344
587
|
maxDepth,
|
|
345
588
|
depth + 1,
|
|
346
589
|
collapseObjects,
|
|
347
|
-
addObjSpaces
|
|
590
|
+
addObjSpaces,
|
|
591
|
+
true
|
|
348
592
|
);
|
|
349
593
|
}).join(", ");
|
|
350
594
|
line += "]";
|
|
@@ -368,7 +612,8 @@ function stringifyValue(value, indent, maxLineLength, showUndefined, maxDepth, d
|
|
|
368
612
|
maxDepth,
|
|
369
613
|
depth + 1,
|
|
370
614
|
collapseObjects,
|
|
371
|
-
addObjSpaces
|
|
615
|
+
addObjSpaces,
|
|
616
|
+
true
|
|
372
617
|
);
|
|
373
618
|
arrayString = arrayString.trimStart();
|
|
374
619
|
result += arrayString;
|
|
@@ -381,7 +626,8 @@ function stringifyValue(value, indent, maxLineLength, showUndefined, maxDepth, d
|
|
|
381
626
|
maxDepth,
|
|
382
627
|
depth + 1,
|
|
383
628
|
collapseObjects,
|
|
384
|
-
addObjSpaces
|
|
629
|
+
addObjSpaces,
|
|
630
|
+
true
|
|
385
631
|
);
|
|
386
632
|
}
|
|
387
633
|
result += "\n";
|
|
@@ -435,7 +681,8 @@ ${indent}${line}
|
|
|
435
681
|
maxDepth,
|
|
436
682
|
depth + 1,
|
|
437
683
|
collapseObjects,
|
|
438
|
-
addObjSpaces
|
|
684
|
+
addObjSpaces,
|
|
685
|
+
false
|
|
439
686
|
);
|
|
440
687
|
}
|
|
441
688
|
return JSON.stringify(value);
|
|
@@ -753,126 +1000,6 @@ function waitController() {
|
|
|
753
1000
|
}
|
|
754
1001
|
};
|
|
755
1002
|
}
|
|
756
|
-
function matchesKeyPattern(fullPath, key, pattern, currentPath) {
|
|
757
|
-
if (fullPath === pattern) {
|
|
758
|
-
return true;
|
|
759
|
-
}
|
|
760
|
-
if (pattern.startsWith("*.")) {
|
|
761
|
-
const propName = pattern.slice(2);
|
|
762
|
-
return currentPath !== "" && key === propName;
|
|
763
|
-
}
|
|
764
|
-
if (pattern.startsWith("*") && !pattern.startsWith("*.")) {
|
|
765
|
-
const propName = pattern.slice(1);
|
|
766
|
-
return key === propName;
|
|
767
|
-
}
|
|
768
|
-
if (!pattern.includes("*")) {
|
|
769
|
-
return currentPath === "" && key === pattern;
|
|
770
|
-
}
|
|
771
|
-
return false;
|
|
772
|
-
}
|
|
773
|
-
function isParentOfPattern(path, pattern) {
|
|
774
|
-
if (pattern.includes("*")) {
|
|
775
|
-
const patternParts = pattern.split(".");
|
|
776
|
-
const pathParts = path.split(".");
|
|
777
|
-
if (pathParts.length >= patternParts.length) {
|
|
778
|
-
return false;
|
|
779
|
-
}
|
|
780
|
-
for (let i = 0; i < pathParts.length; i++) {
|
|
781
|
-
const pathPart = pathParts[i];
|
|
782
|
-
const patternPart = patternParts[i];
|
|
783
|
-
if (patternPart === "*") {
|
|
784
|
-
continue;
|
|
785
|
-
}
|
|
786
|
-
if (pathPart !== patternPart) {
|
|
787
|
-
return false;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
return true;
|
|
791
|
-
} else {
|
|
792
|
-
return pattern.startsWith(`${path}.`);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
function applyKeyFiltering(value, { rejectKeys, filterKeys }, currentPath = "", visited = /* @__PURE__ */ new Set()) {
|
|
796
|
-
if (!isPlainObject(value) && !Array.isArray(value)) {
|
|
797
|
-
return value;
|
|
798
|
-
}
|
|
799
|
-
if (Array.isArray(value)) {
|
|
800
|
-
if (visited.has(value)) {
|
|
801
|
-
throw new Error(
|
|
802
|
-
"Circular reference detected in array during key filtering"
|
|
803
|
-
);
|
|
804
|
-
}
|
|
805
|
-
visited.add(value);
|
|
806
|
-
try {
|
|
807
|
-
return value.map(
|
|
808
|
-
(item, index) => applyKeyFiltering(
|
|
809
|
-
item,
|
|
810
|
-
{ rejectKeys, filterKeys },
|
|
811
|
-
currentPath ? `${currentPath}[${index}]` : `[${index}]`,
|
|
812
|
-
visited
|
|
813
|
-
)
|
|
814
|
-
);
|
|
815
|
-
} finally {
|
|
816
|
-
visited.delete(value);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
if (isPlainObject(value)) {
|
|
820
|
-
if (visited.has(value)) {
|
|
821
|
-
throw new Error(
|
|
822
|
-
"Circular reference detected in object during key filtering"
|
|
823
|
-
);
|
|
824
|
-
}
|
|
825
|
-
visited.add(value);
|
|
826
|
-
try {
|
|
827
|
-
const result = {};
|
|
828
|
-
for (const [key, itemValue] of Object.entries(value)) {
|
|
829
|
-
const fullPath = currentPath ? `${currentPath}.${key}` : key;
|
|
830
|
-
if (rejectKeys?.some(
|
|
831
|
-
(rejectPath) => matchesKeyPattern(fullPath, key, rejectPath, currentPath)
|
|
832
|
-
)) {
|
|
833
|
-
continue;
|
|
834
|
-
}
|
|
835
|
-
if (filterKeys) {
|
|
836
|
-
const exactMatch = filterKeys.some(
|
|
837
|
-
(filterPath) => matchesKeyPattern(fullPath, key, filterPath, currentPath)
|
|
838
|
-
);
|
|
839
|
-
const isParent = filterKeys.some(
|
|
840
|
-
(filterPath) => isParentOfPattern(fullPath, filterPath)
|
|
841
|
-
);
|
|
842
|
-
if (!exactMatch && !isParent) {
|
|
843
|
-
continue;
|
|
844
|
-
}
|
|
845
|
-
if (exactMatch) {
|
|
846
|
-
result[key] = applyKeyFiltering(
|
|
847
|
-
itemValue,
|
|
848
|
-
{ rejectKeys },
|
|
849
|
-
fullPath,
|
|
850
|
-
visited
|
|
851
|
-
);
|
|
852
|
-
} else {
|
|
853
|
-
result[key] = applyKeyFiltering(
|
|
854
|
-
itemValue,
|
|
855
|
-
{ rejectKeys, filterKeys },
|
|
856
|
-
fullPath,
|
|
857
|
-
visited
|
|
858
|
-
);
|
|
859
|
-
}
|
|
860
|
-
} else {
|
|
861
|
-
result[key] = applyKeyFiltering(
|
|
862
|
-
itemValue,
|
|
863
|
-
{ rejectKeys, filterKeys },
|
|
864
|
-
fullPath,
|
|
865
|
-
visited
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
return result;
|
|
870
|
-
} finally {
|
|
871
|
-
visited.delete(value);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
return value;
|
|
875
|
-
}
|
|
876
1003
|
function compactSnapshot(value, {
|
|
877
1004
|
collapseObjects = true,
|
|
878
1005
|
maxLineLength = 100,
|
|
@@ -884,10 +1011,12 @@ function compactSnapshot(value, {
|
|
|
884
1011
|
} = {}) {
|
|
885
1012
|
let processedValue = value;
|
|
886
1013
|
if (rejectKeys || filterKeys) {
|
|
887
|
-
processedValue
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1014
|
+
if (isPlainObject(processedValue) || Array.isArray(processedValue)) {
|
|
1015
|
+
processedValue = filterObjectOrArrayKeys(processedValue, {
|
|
1016
|
+
rejectKeys,
|
|
1017
|
+
filterKeys
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
891
1020
|
}
|
|
892
1021
|
processedValue = showBooleansAs ? replaceBooleansWithEmoji(processedValue, showBooleansAs) : processedValue;
|
|
893
1022
|
return `
|
package/lib/testUtils.d.cts
CHANGED
|
@@ -41,6 +41,46 @@ declare function waitController(): {
|
|
|
41
41
|
stopWaiting: () => void;
|
|
42
42
|
stopWaitingAfter: (ms: number) => void;
|
|
43
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Produces a more compact and readable snapshot of a value using yaml.
|
|
46
|
+
* By default booleans are shown as `✅` and `❌`, use `showBooleansAs` to disable/configure this.
|
|
47
|
+
*
|
|
48
|
+
* Filtering patterns in `rejectKeys` and `filterKeys`:
|
|
49
|
+
* - `'prop'` - Only root-level properties named 'prop'
|
|
50
|
+
* - `'**prop'` - Any property named exactly 'prop' at any level (root or nested)
|
|
51
|
+
* - `'*.prop'` - Any nested property named 'prop' at second level (excludes root-level matches)
|
|
52
|
+
* - `'test.*.prop'` - Any property named 'prop' at second level of 'test'
|
|
53
|
+
* - `'test.*.test.**prop'` - Any property named 'prop' inside of 'test.*.test'
|
|
54
|
+
* - `'prop.nested'` - Exact nested property paths like `obj.prop.nested`
|
|
55
|
+
* - `'prop.**nested'` - All nested properties inside root `prop` with name `nested`
|
|
56
|
+
* - `'prop[0]'` - The first item of the `prop` array
|
|
57
|
+
* - `'prop[*]'` - All items of the `prop` array
|
|
58
|
+
* - `'prop[0].nested'` - `nested` prop of the first item of the `prop` array
|
|
59
|
+
* - `'prop[*].nested'` - `nested` prop of all items of the `prop` array
|
|
60
|
+
* - `'prop[*]**nested'` - all `nested` props of all items of the `prop` array
|
|
61
|
+
* - `'prop[0-2]'` - The first three items of the `prop` array
|
|
62
|
+
* - `'prop[4-*]'` - All items of the `prop` array from the fourth index to the end
|
|
63
|
+
* - `'prop[0-2].nested.**prop'` - Combining multiple nested patterns is supported
|
|
64
|
+
* - Root array:
|
|
65
|
+
* - `'[0]'` - The first item of the root array
|
|
66
|
+
* - `'[*]'` - All items of the array
|
|
67
|
+
* - `'[0].nested'` - `nested` prop of the first item of the array
|
|
68
|
+
* - `'[*].nested'` - `nested` prop of all items of the array
|
|
69
|
+
* - `'[*]**nested'` - all `nested` props of all items of the array
|
|
70
|
+
* - `'[0-2]'` - The first three items of the array
|
|
71
|
+
* - `'[4-*]'` - All items of the array from the fourth index to the end
|
|
72
|
+
*
|
|
73
|
+
* @param value - The value to snapshot.
|
|
74
|
+
* @param options - The options for the snapshot.
|
|
75
|
+
* @param options.collapseObjects - Whether to collapse objects into a single line.
|
|
76
|
+
* @param options.maxLineLength - The maximum length of a line.
|
|
77
|
+
* @param options.showUndefined - Whether to show undefined values.
|
|
78
|
+
* @param options.showBooleansAs - Whether to show booleans as text, by default true is `✅` and false is `❌`
|
|
79
|
+
* @param options.rejectKeys - The keys to reject.
|
|
80
|
+
* @param options.filterKeys - The keys to filter.
|
|
81
|
+
* @param options.ignoreProps - The props to ignore.
|
|
82
|
+
* @returns The compact snapshot of the value.
|
|
83
|
+
*/
|
|
44
84
|
declare function compactSnapshot(value: unknown, { collapseObjects, maxLineLength, showUndefined, showBooleansAs, rejectKeys, filterKeys, ...options }?: YamlStringifyOptions & {
|
|
45
85
|
showBooleansAs?: boolean | {
|
|
46
86
|
props?: Record<string, {
|
|
@@ -54,12 +94,6 @@ declare function compactSnapshot(value: unknown, { collapseObjects, maxLineLengt
|
|
|
54
94
|
/**
|
|
55
95
|
* Reject (exclude) keys from the snapshot using pattern matching.
|
|
56
96
|
*
|
|
57
|
-
* **Pattern Syntax:**
|
|
58
|
-
* - `'prop'` - Only root-level properties named 'prop'
|
|
59
|
-
* - `'prop.nested'` - Exact nested property paths like `obj.prop.nested`
|
|
60
|
-
* - `'*prop'` - Any property named exactly 'prop' at any level (root or nested)
|
|
61
|
-
* - `'*.prop'` - Any nested property named 'prop' (excludes root-level matches)
|
|
62
|
-
*
|
|
63
97
|
* **Examples:**
|
|
64
98
|
* ```typescript
|
|
65
99
|
* // Reject root-level 'secret' only
|
|
@@ -79,12 +113,6 @@ declare function compactSnapshot(value: unknown, { collapseObjects, maxLineLengt
|
|
|
79
113
|
/**
|
|
80
114
|
* Filter (include only) keys that match the specified patterns.
|
|
81
115
|
*
|
|
82
|
-
* **Pattern Syntax:** (same as rejectKeys)
|
|
83
|
-
* - `'prop'` - Only root-level properties named 'prop'
|
|
84
|
-
* - `'prop.nested'` - Exact nested property paths like `obj.prop.nested`
|
|
85
|
-
* - `'*prop'` - Any property named exactly 'prop' at any level (root or nested)
|
|
86
|
-
* - `'*.prop'` - Any nested property named 'prop' (excludes root-level matches)
|
|
87
|
-
*
|
|
88
116
|
* **Examples:**
|
|
89
117
|
* ```typescript
|
|
90
118
|
* // Include only root-level 'user'
|
package/lib/testUtils.d.ts
CHANGED
|
@@ -41,6 +41,46 @@ declare function waitController(): {
|
|
|
41
41
|
stopWaiting: () => void;
|
|
42
42
|
stopWaitingAfter: (ms: number) => void;
|
|
43
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Produces a more compact and readable snapshot of a value using yaml.
|
|
46
|
+
* By default booleans are shown as `✅` and `❌`, use `showBooleansAs` to disable/configure this.
|
|
47
|
+
*
|
|
48
|
+
* Filtering patterns in `rejectKeys` and `filterKeys`:
|
|
49
|
+
* - `'prop'` - Only root-level properties named 'prop'
|
|
50
|
+
* - `'**prop'` - Any property named exactly 'prop' at any level (root or nested)
|
|
51
|
+
* - `'*.prop'` - Any nested property named 'prop' at second level (excludes root-level matches)
|
|
52
|
+
* - `'test.*.prop'` - Any property named 'prop' at second level of 'test'
|
|
53
|
+
* - `'test.*.test.**prop'` - Any property named 'prop' inside of 'test.*.test'
|
|
54
|
+
* - `'prop.nested'` - Exact nested property paths like `obj.prop.nested`
|
|
55
|
+
* - `'prop.**nested'` - All nested properties inside root `prop` with name `nested`
|
|
56
|
+
* - `'prop[0]'` - The first item of the `prop` array
|
|
57
|
+
* - `'prop[*]'` - All items of the `prop` array
|
|
58
|
+
* - `'prop[0].nested'` - `nested` prop of the first item of the `prop` array
|
|
59
|
+
* - `'prop[*].nested'` - `nested` prop of all items of the `prop` array
|
|
60
|
+
* - `'prop[*]**nested'` - all `nested` props of all items of the `prop` array
|
|
61
|
+
* - `'prop[0-2]'` - The first three items of the `prop` array
|
|
62
|
+
* - `'prop[4-*]'` - All items of the `prop` array from the fourth index to the end
|
|
63
|
+
* - `'prop[0-2].nested.**prop'` - Combining multiple nested patterns is supported
|
|
64
|
+
* - Root array:
|
|
65
|
+
* - `'[0]'` - The first item of the root array
|
|
66
|
+
* - `'[*]'` - All items of the array
|
|
67
|
+
* - `'[0].nested'` - `nested` prop of the first item of the array
|
|
68
|
+
* - `'[*].nested'` - `nested` prop of all items of the array
|
|
69
|
+
* - `'[*]**nested'` - all `nested` props of all items of the array
|
|
70
|
+
* - `'[0-2]'` - The first three items of the array
|
|
71
|
+
* - `'[4-*]'` - All items of the array from the fourth index to the end
|
|
72
|
+
*
|
|
73
|
+
* @param value - The value to snapshot.
|
|
74
|
+
* @param options - The options for the snapshot.
|
|
75
|
+
* @param options.collapseObjects - Whether to collapse objects into a single line.
|
|
76
|
+
* @param options.maxLineLength - The maximum length of a line.
|
|
77
|
+
* @param options.showUndefined - Whether to show undefined values.
|
|
78
|
+
* @param options.showBooleansAs - Whether to show booleans as text, by default true is `✅` and false is `❌`
|
|
79
|
+
* @param options.rejectKeys - The keys to reject.
|
|
80
|
+
* @param options.filterKeys - The keys to filter.
|
|
81
|
+
* @param options.ignoreProps - The props to ignore.
|
|
82
|
+
* @returns The compact snapshot of the value.
|
|
83
|
+
*/
|
|
44
84
|
declare function compactSnapshot(value: unknown, { collapseObjects, maxLineLength, showUndefined, showBooleansAs, rejectKeys, filterKeys, ...options }?: YamlStringifyOptions & {
|
|
45
85
|
showBooleansAs?: boolean | {
|
|
46
86
|
props?: Record<string, {
|
|
@@ -54,12 +94,6 @@ declare function compactSnapshot(value: unknown, { collapseObjects, maxLineLengt
|
|
|
54
94
|
/**
|
|
55
95
|
* Reject (exclude) keys from the snapshot using pattern matching.
|
|
56
96
|
*
|
|
57
|
-
* **Pattern Syntax:**
|
|
58
|
-
* - `'prop'` - Only root-level properties named 'prop'
|
|
59
|
-
* - `'prop.nested'` - Exact nested property paths like `obj.prop.nested`
|
|
60
|
-
* - `'*prop'` - Any property named exactly 'prop' at any level (root or nested)
|
|
61
|
-
* - `'*.prop'` - Any nested property named 'prop' (excludes root-level matches)
|
|
62
|
-
*
|
|
63
97
|
* **Examples:**
|
|
64
98
|
* ```typescript
|
|
65
99
|
* // Reject root-level 'secret' only
|
|
@@ -79,12 +113,6 @@ declare function compactSnapshot(value: unknown, { collapseObjects, maxLineLengt
|
|
|
79
113
|
/**
|
|
80
114
|
* Filter (include only) keys that match the specified patterns.
|
|
81
115
|
*
|
|
82
|
-
* **Pattern Syntax:** (same as rejectKeys)
|
|
83
|
-
* - `'prop'` - Only root-level properties named 'prop'
|
|
84
|
-
* - `'prop.nested'` - Exact nested property paths like `obj.prop.nested`
|
|
85
|
-
* - `'*prop'` - Any property named exactly 'prop' at any level (root or nested)
|
|
86
|
-
* - `'*.prop'` - Any nested property named 'prop' (excludes root-level matches)
|
|
87
|
-
*
|
|
88
116
|
* **Examples:**
|
|
89
117
|
* ```typescript
|
|
90
118
|
* // Include only root-level 'user'
|