@aikotools/datafilter 1.0.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/README.md +396 -0
- package/dist/aikotools-datafilter.mjs +591 -0
- package/dist/src/core/index.d.ts +5 -0
- package/dist/src/core/index.d.ts.map +1 -0
- package/dist/src/core/types.d.ts +321 -0
- package/dist/src/core/types.d.ts.map +1 -0
- package/dist/src/engine/FilterEngine.d.ts +84 -0
- package/dist/src/engine/FilterEngine.d.ts.map +1 -0
- package/dist/src/engine/index.d.ts +5 -0
- package/dist/src/engine/index.d.ts.map +1 -0
- package/dist/src/index.d.ts +48 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/matcher/Matcher.d.ts +64 -0
- package/dist/src/matcher/Matcher.d.ts.map +1 -0
- package/dist/src/matcher/index.d.ts +5 -0
- package/dist/src/matcher/index.d.ts.map +1 -0
- package/dist/src/utils/ObjectAccess.d.ts +72 -0
- package/dist/src/utils/ObjectAccess.d.ts.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/license +9 -0
- package/package.json +52 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
import { DateTime as E } from "luxon";
|
|
2
|
+
function R(i) {
|
|
3
|
+
return "matchAny" in i;
|
|
4
|
+
}
|
|
5
|
+
function S(i) {
|
|
6
|
+
return "match" in i && "expected" in i;
|
|
7
|
+
}
|
|
8
|
+
function k(i, s) {
|
|
9
|
+
const t = [];
|
|
10
|
+
if (s.length === 0)
|
|
11
|
+
return {
|
|
12
|
+
value: i,
|
|
13
|
+
found: !0,
|
|
14
|
+
validPath: []
|
|
15
|
+
};
|
|
16
|
+
let e = i;
|
|
17
|
+
for (let n = 0; n < s.length; n++) {
|
|
18
|
+
const r = s[n];
|
|
19
|
+
if (e == null)
|
|
20
|
+
return {
|
|
21
|
+
value: void 0,
|
|
22
|
+
found: !1,
|
|
23
|
+
error: `Cannot read property '${r}' of ${e}`,
|
|
24
|
+
validPath: t
|
|
25
|
+
};
|
|
26
|
+
if (Array.isArray(e)) {
|
|
27
|
+
const a = typeof r == "number" ? r : parseInt(String(r), 10);
|
|
28
|
+
if (isNaN(a))
|
|
29
|
+
return {
|
|
30
|
+
value: void 0,
|
|
31
|
+
found: !1,
|
|
32
|
+
error: `Array index must be a number, got '${r}'`,
|
|
33
|
+
validPath: t
|
|
34
|
+
};
|
|
35
|
+
if (a < 0 || a >= e.length)
|
|
36
|
+
return {
|
|
37
|
+
value: void 0,
|
|
38
|
+
found: !1,
|
|
39
|
+
error: `Array index ${a} out of bounds (length: ${e.length})`,
|
|
40
|
+
validPath: t
|
|
41
|
+
};
|
|
42
|
+
t.push(a), e = e[a];
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (typeof e == "object") {
|
|
46
|
+
const a = String(r);
|
|
47
|
+
if (!(a in e))
|
|
48
|
+
return {
|
|
49
|
+
value: void 0,
|
|
50
|
+
found: !1,
|
|
51
|
+
error: `Property '${a}' does not exist`,
|
|
52
|
+
validPath: t
|
|
53
|
+
};
|
|
54
|
+
t.push(a), e = e[a];
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
value: void 0,
|
|
59
|
+
found: !1,
|
|
60
|
+
error: `Cannot access property '${r}' of primitive type ${typeof e}`,
|
|
61
|
+
validPath: t
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
value: e,
|
|
66
|
+
found: !0,
|
|
67
|
+
validPath: t
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function N(i, s) {
|
|
71
|
+
const t = k(i, s);
|
|
72
|
+
return t.found && t.value !== void 0;
|
|
73
|
+
}
|
|
74
|
+
function z(i, s, t) {
|
|
75
|
+
const e = k(i, s);
|
|
76
|
+
return e.found && e.value !== void 0 ? e.value : t;
|
|
77
|
+
}
|
|
78
|
+
class M {
|
|
79
|
+
constructor(s) {
|
|
80
|
+
this.context = s;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Evaluates a single filter criterion against a data object.
|
|
84
|
+
*
|
|
85
|
+
* @param data - The data object to check
|
|
86
|
+
* @param criterion - The filter criterion to evaluate
|
|
87
|
+
* @returns FilterCheckResult indicating success or failure
|
|
88
|
+
*/
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
|
+
evaluateCriterion(s, t) {
|
|
91
|
+
const e = t.check;
|
|
92
|
+
return "value" in e ? this.checkValue(s, t.path, e) : "exists" in e ? this.checkExists(s, t.path, e) : "itemExists" in e && "item" in e ? this.checkArrayElement(s, t.path, e) : "type" in e && "size" in e ? this.checkArraySize(s, t.path, e) : "min" in e && "max" in e ? typeof e.min == "number" && typeof e.max == "number" ? this.checkNumericRange(s, t.path, e) : this.checkTimeRange(s, t.path, e) : {
|
|
93
|
+
status: !1,
|
|
94
|
+
checkType: "unknown",
|
|
95
|
+
reason: `Unknown check type: ${JSON.stringify(e)}`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Checks if a value matches an expected value using deep equality.
|
|
100
|
+
*
|
|
101
|
+
* @param data - The data object
|
|
102
|
+
* @param path - Path to the value
|
|
103
|
+
* @param check - The value check specification
|
|
104
|
+
* @returns FilterCheckResult
|
|
105
|
+
*/
|
|
106
|
+
checkValue(s, t, e) {
|
|
107
|
+
const n = k(s, t);
|
|
108
|
+
if (!n.found)
|
|
109
|
+
return {
|
|
110
|
+
status: !1,
|
|
111
|
+
checkType: "checkValue",
|
|
112
|
+
reason: {
|
|
113
|
+
message: n.error || "Path not found",
|
|
114
|
+
path: t
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const r = n.value, a = e.value;
|
|
118
|
+
return this.deepEqual(r, a) ? {
|
|
119
|
+
status: !0,
|
|
120
|
+
checkType: "checkValue"
|
|
121
|
+
} : {
|
|
122
|
+
status: !1,
|
|
123
|
+
checkType: "checkValue",
|
|
124
|
+
reason: {
|
|
125
|
+
message: "Value mismatch",
|
|
126
|
+
path: t,
|
|
127
|
+
expected: a,
|
|
128
|
+
actual: r
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Checks if a path exists in the data object.
|
|
134
|
+
*
|
|
135
|
+
* @param data - The data object
|
|
136
|
+
* @param path - Path to check
|
|
137
|
+
* @param check - The exists check specification
|
|
138
|
+
* @returns FilterCheckResult
|
|
139
|
+
*/
|
|
140
|
+
checkExists(s, t, e) {
|
|
141
|
+
const n = k(s, t), r = n.found && n.value !== void 0;
|
|
142
|
+
return e.exists === r ? {
|
|
143
|
+
status: !0,
|
|
144
|
+
checkType: "checkExists"
|
|
145
|
+
} : {
|
|
146
|
+
status: !1,
|
|
147
|
+
checkType: "checkExists",
|
|
148
|
+
reason: {
|
|
149
|
+
message: e.exists ? `Path should exist but doesn't: ${n.error}` : "Path should not exist but does",
|
|
150
|
+
path: t
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Checks if an array contains (or doesn't contain) a specific element.
|
|
156
|
+
*
|
|
157
|
+
* @param data - The data object
|
|
158
|
+
* @param path - Path to the array
|
|
159
|
+
* @param check - The array element check specification
|
|
160
|
+
* @returns FilterCheckResult
|
|
161
|
+
*/
|
|
162
|
+
checkArrayElement(s, t, e) {
|
|
163
|
+
const n = k(s, t);
|
|
164
|
+
if (!n.found)
|
|
165
|
+
return {
|
|
166
|
+
status: !1,
|
|
167
|
+
checkType: "checkArrayElement",
|
|
168
|
+
reason: {
|
|
169
|
+
message: n.error || "Path not found",
|
|
170
|
+
path: t
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const r = n.value;
|
|
174
|
+
if (!Array.isArray(r))
|
|
175
|
+
return {
|
|
176
|
+
status: !1,
|
|
177
|
+
checkType: "checkArrayElement",
|
|
178
|
+
reason: {
|
|
179
|
+
message: "Value is not an array",
|
|
180
|
+
path: t,
|
|
181
|
+
actualType: typeof r
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const a = r.some((u) => this.deepEqual(u, e.item));
|
|
185
|
+
return e.itemExists === a ? {
|
|
186
|
+
status: !0,
|
|
187
|
+
checkType: "checkArrayElement"
|
|
188
|
+
} : {
|
|
189
|
+
status: !1,
|
|
190
|
+
checkType: "checkArrayElement",
|
|
191
|
+
reason: {
|
|
192
|
+
message: e.itemExists ? "Item should exist in array but doesn't" : "Item should not exist in array but does",
|
|
193
|
+
path: t,
|
|
194
|
+
item: e.item
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Checks if an array has the expected size.
|
|
200
|
+
*
|
|
201
|
+
* @param data - The data object
|
|
202
|
+
* @param path - Path to the array
|
|
203
|
+
* @param check - The array size check specification
|
|
204
|
+
* @returns FilterCheckResult
|
|
205
|
+
*/
|
|
206
|
+
checkArraySize(s, t, e) {
|
|
207
|
+
const n = k(s, t);
|
|
208
|
+
if (!n.found)
|
|
209
|
+
return {
|
|
210
|
+
status: !1,
|
|
211
|
+
checkType: "checkArraySize",
|
|
212
|
+
reason: {
|
|
213
|
+
message: n.error || "Path not found",
|
|
214
|
+
path: t
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
const r = n.value;
|
|
218
|
+
if (!Array.isArray(r))
|
|
219
|
+
return {
|
|
220
|
+
status: !1,
|
|
221
|
+
checkType: "checkArraySize",
|
|
222
|
+
reason: {
|
|
223
|
+
message: "Value is not an array",
|
|
224
|
+
path: t,
|
|
225
|
+
actualType: typeof r
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const a = r.length, u = e.size;
|
|
229
|
+
let c = !1, f = "";
|
|
230
|
+
switch (e.type) {
|
|
231
|
+
case "equal":
|
|
232
|
+
c = a === u, f = `Array length should be ${u} but is ${a}`;
|
|
233
|
+
break;
|
|
234
|
+
case "lessThan":
|
|
235
|
+
c = a < u, f = `Array length should be less than ${u} but is ${a}`;
|
|
236
|
+
break;
|
|
237
|
+
case "greaterThan":
|
|
238
|
+
c = a > u, f = `Array length should be greater than ${u} but is ${a}`;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
return c ? {
|
|
242
|
+
status: !0,
|
|
243
|
+
checkType: "checkArraySize"
|
|
244
|
+
} : {
|
|
245
|
+
status: !1,
|
|
246
|
+
checkType: "checkArraySize",
|
|
247
|
+
reason: {
|
|
248
|
+
message: f,
|
|
249
|
+
path: t,
|
|
250
|
+
expected: u,
|
|
251
|
+
actual: a
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Checks if a timestamp is within the expected time range.
|
|
257
|
+
*
|
|
258
|
+
* @param data - The data object
|
|
259
|
+
* @param path - Path to the timestamp
|
|
260
|
+
* @param check - The time range check specification
|
|
261
|
+
* @returns FilterCheckResult
|
|
262
|
+
*/
|
|
263
|
+
checkTimeRange(s, t, e) {
|
|
264
|
+
const n = k(s, t);
|
|
265
|
+
if (!n.found)
|
|
266
|
+
return {
|
|
267
|
+
status: !1,
|
|
268
|
+
checkType: "checkTimeRange",
|
|
269
|
+
reason: {
|
|
270
|
+
message: n.error || "Path not found",
|
|
271
|
+
path: t
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
const r = n.value;
|
|
275
|
+
if (typeof r == "number") {
|
|
276
|
+
const a = parseInt(e.min), u = parseInt(e.max);
|
|
277
|
+
return isNaN(a) || isNaN(u) ? {
|
|
278
|
+
status: !1,
|
|
279
|
+
checkType: "checkTimeRange",
|
|
280
|
+
reason: {
|
|
281
|
+
message: "Min or max is not a valid number",
|
|
282
|
+
min: e.min,
|
|
283
|
+
max: e.max
|
|
284
|
+
}
|
|
285
|
+
} : r >= a && r <= u ? {
|
|
286
|
+
status: !0,
|
|
287
|
+
checkType: "checkTimeRange"
|
|
288
|
+
} : {
|
|
289
|
+
status: !1,
|
|
290
|
+
checkType: "checkTimeRange",
|
|
291
|
+
reason: {
|
|
292
|
+
message: `Timestamp ${r} is outside range [${a}, ${u}]`,
|
|
293
|
+
path: t,
|
|
294
|
+
actual: r,
|
|
295
|
+
min: a,
|
|
296
|
+
max: u
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
if (typeof r == "string") {
|
|
301
|
+
const a = E.fromISO(r), u = E.fromISO(e.min), c = E.fromISO(e.max);
|
|
302
|
+
return a.isValid ? !u.isValid || !c.isValid ? {
|
|
303
|
+
status: !1,
|
|
304
|
+
checkType: "checkTimeRange",
|
|
305
|
+
reason: {
|
|
306
|
+
message: "Invalid min or max time",
|
|
307
|
+
min: e.min,
|
|
308
|
+
max: e.max
|
|
309
|
+
}
|
|
310
|
+
} : a >= u && a <= c ? {
|
|
311
|
+
status: !0,
|
|
312
|
+
checkType: "checkTimeRange"
|
|
313
|
+
} : {
|
|
314
|
+
status: !1,
|
|
315
|
+
checkType: "checkTimeRange",
|
|
316
|
+
reason: {
|
|
317
|
+
message: `Timestamp ${r} is outside range [${e.min}, ${e.max}]`,
|
|
318
|
+
path: t,
|
|
319
|
+
actual: r,
|
|
320
|
+
min: e.min,
|
|
321
|
+
max: e.max
|
|
322
|
+
}
|
|
323
|
+
} : {
|
|
324
|
+
status: !1,
|
|
325
|
+
checkType: "checkTimeRange",
|
|
326
|
+
reason: {
|
|
327
|
+
message: `Invalid timestamp: ${r}`,
|
|
328
|
+
path: t
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
status: !1,
|
|
334
|
+
checkType: "checkTimeRange",
|
|
335
|
+
reason: {
|
|
336
|
+
message: `Timestamp must be a string or number, got ${typeof r}`,
|
|
337
|
+
path: t
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Checks if a numeric value is within the expected range.
|
|
343
|
+
*
|
|
344
|
+
* @param data - The data object
|
|
345
|
+
* @param path - Path to the numeric value
|
|
346
|
+
* @param check - The numeric range check specification
|
|
347
|
+
* @returns FilterCheckResult
|
|
348
|
+
*/
|
|
349
|
+
checkNumericRange(s, t, e) {
|
|
350
|
+
const n = k(s, t);
|
|
351
|
+
if (!n.found)
|
|
352
|
+
return {
|
|
353
|
+
status: !1,
|
|
354
|
+
checkType: "checkNumericRange",
|
|
355
|
+
reason: {
|
|
356
|
+
message: n.error || "Path not found",
|
|
357
|
+
path: t
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
const r = n.value;
|
|
361
|
+
return typeof r != "number" ? {
|
|
362
|
+
status: !1,
|
|
363
|
+
checkType: "checkNumericRange",
|
|
364
|
+
reason: {
|
|
365
|
+
message: `Value must be a number, got ${typeof r}`,
|
|
366
|
+
path: t,
|
|
367
|
+
actual: r
|
|
368
|
+
}
|
|
369
|
+
} : r >= e.min && r <= e.max ? {
|
|
370
|
+
status: !0,
|
|
371
|
+
checkType: "checkNumericRange"
|
|
372
|
+
} : {
|
|
373
|
+
status: !1,
|
|
374
|
+
checkType: "checkNumericRange",
|
|
375
|
+
reason: {
|
|
376
|
+
message: `Value ${r} is outside range [${e.min}, ${e.max}]`,
|
|
377
|
+
path: t,
|
|
378
|
+
actual: r,
|
|
379
|
+
min: e.min,
|
|
380
|
+
max: e.max
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Deep equality comparison.
|
|
386
|
+
* Compares two values recursively for equality.
|
|
387
|
+
*/
|
|
388
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
389
|
+
deepEqual(s, t) {
|
|
390
|
+
if (s === t) return !0;
|
|
391
|
+
if (s === null || t === null || s === void 0 || t === void 0) return s === t;
|
|
392
|
+
if (typeof s != typeof t) return !1;
|
|
393
|
+
if (s instanceof Date && t instanceof Date)
|
|
394
|
+
return s.getTime() === t.getTime();
|
|
395
|
+
if (Array.isArray(s) && Array.isArray(t))
|
|
396
|
+
return s.length !== t.length ? !1 : s.every((e, n) => this.deepEqual(e, t[n]));
|
|
397
|
+
if (typeof s == "object" && typeof t == "object") {
|
|
398
|
+
const e = Object.keys(s), n = Object.keys(t);
|
|
399
|
+
return e.length !== n.length ? !1 : e.every((r) => this.deepEqual(s[r], t[r]));
|
|
400
|
+
}
|
|
401
|
+
return s === t;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
class P {
|
|
405
|
+
constructor(s) {
|
|
406
|
+
this.engine = new M(s);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Matches a single file against a rule.
|
|
410
|
+
*
|
|
411
|
+
* @param file - The file to match
|
|
412
|
+
* @param rule - The rule to match against
|
|
413
|
+
* @returns MatchResult indicating if all criteria matched
|
|
414
|
+
*/
|
|
415
|
+
matchFile(s, t) {
|
|
416
|
+
const n = (R(t) ? t.matchAny : t.match).map((a) => this.engine.evaluateCriterion(s.data, a));
|
|
417
|
+
return {
|
|
418
|
+
matched: n.every((a) => a.status),
|
|
419
|
+
checks: n,
|
|
420
|
+
rule: t
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Applies pre-filter criteria to files, returning only files that match all criteria.
|
|
425
|
+
*
|
|
426
|
+
* @param files - Files to filter
|
|
427
|
+
* @param preFilter - Filter criteria that all files must match
|
|
428
|
+
* @returns Filtered files that match all preFilter criteria
|
|
429
|
+
*/
|
|
430
|
+
applyPreFilter(s, t) {
|
|
431
|
+
return s.filter((e) => t.map((r) => this.engine.evaluateCriterion(e.data, r)).every((r) => r.status));
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Main filtering function that processes files according to rules.
|
|
435
|
+
*
|
|
436
|
+
* @param files - Files to filter
|
|
437
|
+
* @param rules - Matching rules (can include arrays for flexible ordering)
|
|
438
|
+
* @param sortFn - Optional sort function for file ordering
|
|
439
|
+
* @param preFilter - Optional pre-filter criteria (files not matching are excluded)
|
|
440
|
+
* @returns FilterResult with mapped, wildcardMatched, and unmapped files
|
|
441
|
+
*/
|
|
442
|
+
filterFiles(s, t, e, n) {
|
|
443
|
+
var T, y;
|
|
444
|
+
const r = n ? this.applyPreFilter(s, n) : s, a = e ? [...r].sort(e) : [...r], u = [], c = [], f = [], p = /* @__PURE__ */ new Set(), x = /* @__PURE__ */ new Map();
|
|
445
|
+
let o = 0, l = 0;
|
|
446
|
+
for (; o < a.length; ) {
|
|
447
|
+
const g = a[o];
|
|
448
|
+
if (l >= t.length) {
|
|
449
|
+
p.has(o) || f.push({
|
|
450
|
+
file: g,
|
|
451
|
+
attemptedRules: []
|
|
452
|
+
}), o++;
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
const d = t[l], F = [];
|
|
456
|
+
let b = !1;
|
|
457
|
+
if (Array.isArray(d)) {
|
|
458
|
+
for (let m = 0; m < d.length; m++) {
|
|
459
|
+
if ((T = x.get(l)) == null ? void 0 : T.has(m))
|
|
460
|
+
continue;
|
|
461
|
+
const v = d[m], $ = this.matchFile(g, v);
|
|
462
|
+
if (F.push($), $.matched && S(v)) {
|
|
463
|
+
x.has(l) || x.set(l, /* @__PURE__ */ new Set());
|
|
464
|
+
const w = x.get(l);
|
|
465
|
+
w && w.add(m), u.push({
|
|
466
|
+
expected: v.expected,
|
|
467
|
+
file: g,
|
|
468
|
+
matchResult: $,
|
|
469
|
+
optional: v.optional || !1,
|
|
470
|
+
info: v.info
|
|
471
|
+
}), p.add(o), b = !0;
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
((y = x.get(l)) == null ? void 0 : y.size) === d.length && l++, o++;
|
|
476
|
+
} else {
|
|
477
|
+
const h = d, m = this.matchFile(g, h);
|
|
478
|
+
F.push(m), m.matched ? S(h) ? (u.push({
|
|
479
|
+
expected: h.expected,
|
|
480
|
+
file: g,
|
|
481
|
+
matchResult: m,
|
|
482
|
+
optional: h.optional || !1,
|
|
483
|
+
info: h.info
|
|
484
|
+
}), p.add(o), l++, o++) : R(h) && (c.push({
|
|
485
|
+
file: g,
|
|
486
|
+
matchResult: m,
|
|
487
|
+
info: h.info
|
|
488
|
+
}), p.add(o), h.greedy || l++, o++) : h.optional || R(h) ? l++ : (f.push({
|
|
489
|
+
file: g,
|
|
490
|
+
attemptedRules: F
|
|
491
|
+
}), o++);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const A = {
|
|
495
|
+
totalFiles: s.length,
|
|
496
|
+
mappedFiles: u.length,
|
|
497
|
+
wildcardMatchedFiles: c.length,
|
|
498
|
+
unmappedFiles: f.length,
|
|
499
|
+
totalRules: this.countRules(t),
|
|
500
|
+
mandatoryRules: this.countMandatoryRules(t),
|
|
501
|
+
optionalRules: this.countOptionalRules(t)
|
|
502
|
+
};
|
|
503
|
+
return {
|
|
504
|
+
mapped: u,
|
|
505
|
+
wildcardMatched: c,
|
|
506
|
+
unmapped: f,
|
|
507
|
+
stats: A
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Counts total number of rules (flattening arrays)
|
|
512
|
+
*/
|
|
513
|
+
countRules(s) {
|
|
514
|
+
return s.reduce((t, e) => Array.isArray(e) ? t + e.length : t + 1, 0);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Counts mandatory rules
|
|
518
|
+
*/
|
|
519
|
+
countMandatoryRules(s) {
|
|
520
|
+
return s.reduce((t, e) => Array.isArray(e) ? t + e.filter((n) => !n.optional && !R(n)).length : t + (e.optional || R(e) ? 0 : 1), 0);
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Counts optional rules
|
|
524
|
+
*/
|
|
525
|
+
countOptionalRules(s) {
|
|
526
|
+
return s.reduce((t, e) => Array.isArray(e) ? t + e.filter((n) => n.optional || R(n)).length : t + (e.optional || R(e) ? 1 : 0), 0);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Filtering function for grouped rules with common filter criteria.
|
|
530
|
+
* Files are first filtered by preFilter (if provided), then matched against
|
|
531
|
+
* group filters, and finally processed by the group's rules.
|
|
532
|
+
*
|
|
533
|
+
* @param files - Files to filter
|
|
534
|
+
* @param groups - Filter groups with common criteria and rules
|
|
535
|
+
* @param sortFn - Optional sort function for file ordering
|
|
536
|
+
* @param preFilter - Optional pre-filter criteria (files not matching are excluded)
|
|
537
|
+
* @returns FilterResult with mapped, wildcardMatched, and unmapped files
|
|
538
|
+
*/
|
|
539
|
+
filterFilesWithGroups(s, t, e, n) {
|
|
540
|
+
const r = n ? this.applyPreFilter(s, n) : s, a = e ? [...r].sort(e) : [...r], u = [], c = [], f = [];
|
|
541
|
+
for (const o of t) {
|
|
542
|
+
const l = a.filter((y) => o.groupFilter.map((d) => this.engine.evaluateCriterion(y.data, d)).every((d) => d.status));
|
|
543
|
+
if (l.length === 0)
|
|
544
|
+
continue;
|
|
545
|
+
const A = o.rules.map((y) => (Array.isArray(y), y)), T = this.filterFiles(l, A);
|
|
546
|
+
u.push(...T.mapped), c.push(...T.wildcardMatched), f.push(...T.unmapped);
|
|
547
|
+
}
|
|
548
|
+
const p = t.flatMap((o) => o.rules), x = {
|
|
549
|
+
totalFiles: s.length,
|
|
550
|
+
mappedFiles: u.length,
|
|
551
|
+
wildcardMatchedFiles: c.length,
|
|
552
|
+
unmappedFiles: f.length,
|
|
553
|
+
totalRules: this.countRules(p),
|
|
554
|
+
mandatoryRules: this.countMandatoryRules(p),
|
|
555
|
+
optionalRules: this.countOptionalRules(p)
|
|
556
|
+
};
|
|
557
|
+
return {
|
|
558
|
+
mapped: u,
|
|
559
|
+
wildcardMatched: c,
|
|
560
|
+
unmapped: f,
|
|
561
|
+
stats: x
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function O(i) {
|
|
566
|
+
const s = new P(i.context);
|
|
567
|
+
if (i.rules && i.groups)
|
|
568
|
+
throw new Error('FilterRequest: Provide either "rules" or "groups", not both');
|
|
569
|
+
if (!i.rules && !i.groups)
|
|
570
|
+
throw new Error('FilterRequest: Must provide either "rules" or "groups"');
|
|
571
|
+
if (i.groups)
|
|
572
|
+
return s.filterFilesWithGroups(
|
|
573
|
+
i.files,
|
|
574
|
+
i.groups,
|
|
575
|
+
i.sortFn,
|
|
576
|
+
i.preFilter
|
|
577
|
+
);
|
|
578
|
+
if (!i.rules)
|
|
579
|
+
throw new Error("FilterRequest: Rules are required");
|
|
580
|
+
return s.filterFiles(i.files, i.rules, i.sortFn, i.preFilter);
|
|
581
|
+
}
|
|
582
|
+
export {
|
|
583
|
+
M as FilterEngine,
|
|
584
|
+
P as Matcher,
|
|
585
|
+
O as filterFiles,
|
|
586
|
+
k as getValueFromPath,
|
|
587
|
+
z as getValueOr,
|
|
588
|
+
S as isSingleMatchRule,
|
|
589
|
+
R as isWildcardRule,
|
|
590
|
+
N as pathExists
|
|
591
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,SAAS,CAAA"}
|