@aikotools/datafilter 1.0.5 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -7
- package/dist/aikotools-datafilter.cjs +937 -1
- package/dist/aikotools-datafilter.cjs.map +1 -0
- package/dist/aikotools-datafilter.mjs +677 -354
- package/dist/aikotools-datafilter.mjs.map +1 -0
- package/dist/src/core/types.d.ts +46 -0
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/matcher/Matcher.d.ts +10 -4
- package/dist/src/matcher/Matcher.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ Advanced data filtering engine for JSON file matching in E2E testing.
|
|
|
13
13
|
|
|
14
14
|
- **Flexible Matching**: Match files using various filter criteria (value, exists, array checks, time ranges)
|
|
15
15
|
- **Order Handling**: Support for both strict and flexible ordering of expected files
|
|
16
|
+
- **🆕 Optional Mode**: Automatically treat unmatched files as optional without explicit rules
|
|
16
17
|
- **🆕 Wildcard Optionals**: Match arbitrary number of optional files without explicit specification
|
|
17
18
|
- **Greedy vs. Non-Greedy**: Control whether wildcards match once or multiple times
|
|
18
19
|
- **PreFilter Support**: Global file filtering before rule matching
|
|
@@ -180,6 +181,82 @@ Validate timestamps (ISO strings or numeric):
|
|
|
180
181
|
|
|
181
182
|
## Advanced Features
|
|
182
183
|
|
|
184
|
+
### 🆕 Optional Mode - Automatic Optional File Handling (NEW)
|
|
185
|
+
|
|
186
|
+
Optional mode allows you to focus on matching critical files while automatically treating unmatched files as optional. This eliminates the need to create explicit wildcard rules for every gap between expected files.
|
|
187
|
+
|
|
188
|
+
**Use Case:** Event streams, log files, or test executions where you want to validate specific checkpoints but allow arbitrary intermediate files.
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
#### Three Matching Modes
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Mode 1: 'strict' (default) - Current behavior
|
|
195
|
+
// Every file must match a rule, non-matching files → unmapped (error)
|
|
196
|
+
const result = filterFiles({
|
|
197
|
+
files,
|
|
198
|
+
rules,
|
|
199
|
+
mode: 'strict' // or omit for default
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Mode 2: 'optional' - Permissive mode
|
|
203
|
+
// Files between matches are automatically treated as optional
|
|
204
|
+
// Non-matched files → optionalFiles (not an error)
|
|
205
|
+
const result = filterFiles({
|
|
206
|
+
files: [
|
|
207
|
+
{ fileName: 'critical_A.json', data: { type: 'critical' } },
|
|
208
|
+
{ fileName: 'info_1.json', data: { type: 'info' } }, // ← automatically optional
|
|
209
|
+
{ fileName: 'debug_1.json', data: { type: 'debug' } }, // ← automatically optional
|
|
210
|
+
{ fileName: 'critical_B.json', data: { type: 'critical' } },
|
|
211
|
+
],
|
|
212
|
+
rules: [
|
|
213
|
+
{ match: [{ path: ['type'], check: { value: 'critical' } }], expected: 'A' },
|
|
214
|
+
{ match: [{ path: ['type'], check: { value: 'critical' } }], expected: 'B' },
|
|
215
|
+
],
|
|
216
|
+
mode: 'optional' // Enable permissive mode
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Result:
|
|
220
|
+
// - mapped: critical_A.json, critical_B.json
|
|
221
|
+
// - optionalFiles: info_1.json, debug_1.json (with position and context)
|
|
222
|
+
// - unmapped: [] (always empty in optional mode)
|
|
223
|
+
|
|
224
|
+
// Mode 3: 'strict-optional' - Balanced approach
|
|
225
|
+
// Similar to optional mode but respects optional flags on rules
|
|
226
|
+
const result = filterFiles({
|
|
227
|
+
files,
|
|
228
|
+
rules,
|
|
229
|
+
mode: 'strict-optional'
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### Optional File Information
|
|
234
|
+
|
|
235
|
+
When files are treated as optional, they include detailed context:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
result.optionalFiles = [
|
|
239
|
+
{
|
|
240
|
+
fileName: 'info_1.json',
|
|
241
|
+
position: 1,
|
|
242
|
+
between: {
|
|
243
|
+
afterRule: 'A', // After which matched rule
|
|
244
|
+
beforeRule: 'B' // Before which matched rule
|
|
245
|
+
},
|
|
246
|
+
failedMatches: [...] // Why this file didn't match any rule
|
|
247
|
+
},
|
|
248
|
+
// ...
|
|
249
|
+
]
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### Benefits
|
|
253
|
+
|
|
254
|
+
✅ **Simplicity**: No need for explicit wildcard matchers at every position
|
|
255
|
+
✅ **Flexibility**: Handle variable numbers of files between rules
|
|
256
|
+
✅ **Transparency**: Track which files were optional and why
|
|
257
|
+
✅ **Debugging**: `failedMatches` helps understand filter behavior
|
|
258
|
+
✅ **Clarity**: `unmapped` empty when optional mode active - clear intent
|
|
259
|
+
|
|
183
260
|
### PreFilter - Global File Exclusion
|
|
184
261
|
|
|
185
262
|
PreFilter allows you to exclude files globally **before** any rule matching occurs. Files not matching the preFilter criteria are collected in the `preFiltered` property of the result, separate from `unmapped` files.
|
|
@@ -378,14 +455,19 @@ Main filtering function.
|
|
|
378
455
|
- `rules: (MatchRule | MatchRule[])[]` - Matching rules
|
|
379
456
|
- `sortFn?: (a, b) => number` - Optional sort function
|
|
380
457
|
- `preFilter?: FilterCriterion[]` - Optional pre-filter criteria (files not matching are collected in `preFiltered`)
|
|
458
|
+
- `mode?: 'strict' | 'strict-optional' | 'optional'` - 🆕 Matching mode (default: 'strict')
|
|
459
|
+
- `'strict'`: All files must match a rule (unmapped = errors)
|
|
460
|
+
- `'optional'`: Unmatched files → optionalFiles (unmapped always empty)
|
|
461
|
+
- `'strict-optional'`: Similar to optional but respects optional flags
|
|
381
462
|
- `context?: { startTimeScript?, startTimeTest?, pathTime? }` - Optional context
|
|
382
463
|
|
|
383
464
|
**FilterResult:**
|
|
384
465
|
- `mapped: MappedFile[]` - Successfully mapped files
|
|
385
466
|
- `wildcardMatched: WildcardMappedFile[]` - Files matched by wildcards
|
|
386
|
-
- `
|
|
467
|
+
- `optionalFiles: OptionalFile[]` - 🆕 Files treated as optional (with position and context)
|
|
468
|
+
- `unmapped: UnmappedFile[]` - Files that passed preFilter but couldn't be matched to any rule (empty when mode is 'optional' or 'strict-optional')
|
|
387
469
|
- `preFiltered: PreFilteredFile[]` - Files excluded by preFilter criteria (with failed check details)
|
|
388
|
-
- `stats: { totalFiles, mappedFiles, wildcardMatchedFiles, unmappedFiles, preFilteredFiles, ... }`
|
|
470
|
+
- `stats: { totalFiles, mappedFiles, wildcardMatchedFiles, optionalFiles, unmappedFiles, preFilteredFiles, ... }`
|
|
389
471
|
|
|
390
472
|
### filterFilesWithGroups(request: FilterGroupRequest): FilterResult
|
|
391
473
|
|
|
@@ -396,6 +478,7 @@ Filtering with grouped rules for categorized file processing.
|
|
|
396
478
|
- `groups: FilterGroup[]` - Filter groups with common criteria and rules
|
|
397
479
|
- `sortFn?: (a, b) => number` - Optional sort function
|
|
398
480
|
- `preFilter?: FilterCriterion[]` - Optional pre-filter criteria (applied before group filtering)
|
|
481
|
+
- `mode?: 'strict' | 'strict-optional' | 'optional'` - 🆕 Matching mode (default: 'strict')
|
|
399
482
|
- `context?: { startTimeScript?, startTimeTest?, pathTime? }` - Optional context
|
|
400
483
|
|
|
401
484
|
**FilterGroup:**
|
|
@@ -413,11 +496,11 @@ import { Matcher } from '@aikotools/datafilter';
|
|
|
413
496
|
|
|
414
497
|
const matcher = new Matcher({ startTimeScript, startTimeTest });
|
|
415
498
|
|
|
416
|
-
// With preFilter
|
|
417
|
-
const result = matcher.filterFiles(files, rules, sortFn, preFilter);
|
|
499
|
+
// With preFilter and mode
|
|
500
|
+
const result = matcher.filterFiles(files, rules, sortFn, preFilter, mode);
|
|
418
501
|
|
|
419
|
-
// With groups
|
|
420
|
-
const groupResult = matcher.filterFilesWithGroups(files, groups, sortFn, preFilter);
|
|
502
|
+
// With groups and mode
|
|
503
|
+
const groupResult = matcher.filterFilesWithGroups(files, groups, sortFn, preFilter, mode);
|
|
421
504
|
```
|
|
422
505
|
|
|
423
506
|
### FilterEngine Class
|
|
@@ -488,12 +571,16 @@ const value = getValueOr(obj, ['data', 'missing'], 'default');
|
|
|
488
571
|
|
|
489
572
|
## Test Results
|
|
490
573
|
|
|
491
|
-
✅ **
|
|
574
|
+
✅ **194/194 tests passing** (97.93% coverage for Matcher module)
|
|
492
575
|
- ✅ Basic filtering with single matches
|
|
493
576
|
- ✅ Flexible ordering (array of rules)
|
|
494
577
|
- ✅ Optional rules
|
|
578
|
+
- ✅ 🆕 Optional mode (automatic optional file handling)
|
|
579
|
+
- ✅ 🆕 Strict-optional mode
|
|
495
580
|
- ✅ 🆕 Wildcard matches (greedy & non-greedy)
|
|
496
581
|
- ✅ All filter check types (value, exists, array, time)
|
|
582
|
+
- ✅ PreFilter support
|
|
583
|
+
- ✅ Group filtering
|
|
497
584
|
- ✅ Complex real-world scenarios
|
|
498
585
|
- ✅ Sort function integration
|
|
499
586
|
|