pw-sanitizer 0.1.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 +415 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +30 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +173 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +432 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validator.d.ts +34 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +95 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +190 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +82 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +122 -0
- package/dist/logger.js.map +1 -0
- package/dist/processors/html-report.d.ts +27 -0
- package/dist/processors/html-report.d.ts.map +1 -0
- package/dist/processors/html-report.js +220 -0
- package/dist/processors/html-report.js.map +1 -0
- package/dist/processors/screenshot.d.ts +37 -0
- package/dist/processors/screenshot.d.ts.map +1 -0
- package/dist/processors/screenshot.js +52 -0
- package/dist/processors/screenshot.js.map +1 -0
- package/dist/processors/trace-file.d.ts +29 -0
- package/dist/processors/trace-file.d.ts.map +1 -0
- package/dist/processors/trace-file.js +250 -0
- package/dist/processors/trace-file.js.map +1 -0
- package/dist/redact/json-walker.d.ts +28 -0
- package/dist/redact/json-walker.d.ts.map +1 -0
- package/dist/redact/json-walker.js +164 -0
- package/dist/redact/json-walker.js.map +1 -0
- package/dist/redact/matcher.d.ts +25 -0
- package/dist/redact/matcher.d.ts.map +1 -0
- package/dist/redact/matcher.js +130 -0
- package/dist/redact/matcher.js.map +1 -0
- package/dist/redact/pattern-loader.d.ts +25 -0
- package/dist/redact/pattern-loader.d.ts.map +1 -0
- package/dist/redact/pattern-loader.js +111 -0
- package/dist/redact/pattern-loader.js.map +1 -0
- package/dist/redact/pattern-registry.d.ts +17 -0
- package/dist/redact/pattern-registry.d.ts.map +1 -0
- package/dist/redact/pattern-registry.js +58 -0
- package/dist/redact/pattern-registry.js.map +1 -0
- package/dist/remove/detector.d.ts +22 -0
- package/dist/remove/detector.d.ts.map +1 -0
- package/dist/remove/detector.js +152 -0
- package/dist/remove/detector.js.map +1 -0
- package/dist/remove/remover.d.ts +18 -0
- package/dist/remove/remover.d.ts.map +1 -0
- package/dist/remove/remover.js +72 -0
- package/dist/remove/remover.js.map +1 -0
- package/dist/remove/rule-loader.d.ts +25 -0
- package/dist/remove/rule-loader.d.ts.map +1 -0
- package/dist/remove/rule-loader.js +110 -0
- package/dist/remove/rule-loader.js.map +1 -0
- package/dist/remove/rule-registry.d.ts +17 -0
- package/dist/remove/rule-registry.d.ts.map +1 -0
- package/dist/remove/rule-registry.js +58 -0
- package/dist/remove/rule-registry.js.map +1 -0
- package/dist/remove/timestamp-repair.d.ts +28 -0
- package/dist/remove/timestamp-repair.d.ts.map +1 -0
- package/dist/remove/timestamp-repair.js +157 -0
- package/dist/remove/timestamp-repair.js.map +1 -0
- package/dist/reporter.d.ts +44 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +180 -0
- package/dist/reporter.js.map +1 -0
- package/dist/teardown.d.ts +27 -0
- package/dist/teardown.d.ts.map +1 -0
- package/dist/teardown.js +42 -0
- package/dist/teardown.js.map +1 -0
- package/dist/utils.d.ts +36 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +112 -0
- package/dist/utils.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findStepsToRemove = findStepsToRemove;
|
|
4
|
+
const logger_js_1 = require("../logger.js");
|
|
5
|
+
/**
|
|
6
|
+
* Tests whether an event field value satisfies a rule matcher.
|
|
7
|
+
*
|
|
8
|
+
* - `string` matcher → case-sensitive substring match (compatible with JSON-sourced rules).
|
|
9
|
+
* - `RegExp` matcher → tested against the value string.
|
|
10
|
+
* - Either argument being `undefined` → returns `false` immediately.
|
|
11
|
+
*
|
|
12
|
+
* @param value - The event field value to test (may be `undefined` if the field is absent).
|
|
13
|
+
* @param matcher - The rule matcher from a {@link RemoveRule} field (may be `undefined` if not set).
|
|
14
|
+
* @returns `true` if the matcher is defined, the value is defined, and the value satisfies the matcher.
|
|
15
|
+
*/
|
|
16
|
+
function matchesField(value, matcher) {
|
|
17
|
+
if (matcher === undefined || value === undefined)
|
|
18
|
+
return false;
|
|
19
|
+
if (typeof matcher === 'string') {
|
|
20
|
+
// Substring match for compatibility with JSON rule files
|
|
21
|
+
return value.includes(matcher);
|
|
22
|
+
}
|
|
23
|
+
return matcher.test(value);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Tests whether a single {@link TraceEvent} satisfies a {@link RemoveRule}.
|
|
27
|
+
*
|
|
28
|
+
* Each matcher field on the rule (`stepName`, `selector`, `url`, `actionType`)
|
|
29
|
+
* is compared against the corresponding event field(s). Only matchers that are
|
|
30
|
+
* explicitly set on the rule are evaluated — unset matchers are ignored.
|
|
31
|
+
* **All active matchers must match** (AND logic); a rule with no matchers never matches.
|
|
32
|
+
*
|
|
33
|
+
* Field mapping:
|
|
34
|
+
* - `rule.stepName` → `event.title ?? event.action ?? event.method`
|
|
35
|
+
* - `rule.selector` → `event.selector`
|
|
36
|
+
* - `rule.url` → `event.url`
|
|
37
|
+
* - `rule.actionType` → `event.actionType ?? event.type`
|
|
38
|
+
*
|
|
39
|
+
* @param event - The trace event to test.
|
|
40
|
+
* @param rule - The removal rule to test against.
|
|
41
|
+
* @returns `true` if all active matchers on the rule match the event.
|
|
42
|
+
*/
|
|
43
|
+
function eventMatchesRule(event, rule) {
|
|
44
|
+
const matchers = [
|
|
45
|
+
{ eventValue: event.title ?? event.action ?? event.method, ruleValue: rule.stepName },
|
|
46
|
+
{ eventValue: event.selector, ruleValue: rule.selector },
|
|
47
|
+
{ eventValue: event.url, ruleValue: rule.url },
|
|
48
|
+
{ eventValue: event.actionType ?? event.type, ruleValue: rule.actionType },
|
|
49
|
+
];
|
|
50
|
+
// Only consider matchers that are defined on the rule
|
|
51
|
+
const activeMatchers = matchers.filter((m) => m.ruleValue !== undefined);
|
|
52
|
+
if (activeMatchers.length === 0)
|
|
53
|
+
return false;
|
|
54
|
+
// ALL active matchers must match (AND logic)
|
|
55
|
+
return activeMatchers.every((m) => matchesField(m.eventValue, m.ruleValue));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Partitions the event list into contiguous runs where every event matches the rule.
|
|
59
|
+
*
|
|
60
|
+
* A "run" is a maximal sequence of consecutive indices where each event satisfies
|
|
61
|
+
* `eventMatchesRule`. Runs are separated by at least one non-matching event.
|
|
62
|
+
* Used to enforce {@link RemoveRule.minConsecutiveOccurrences}.
|
|
63
|
+
*
|
|
64
|
+
* @param events - The flat ordered list of trace events.
|
|
65
|
+
* @param rule - The rule to match against each event.
|
|
66
|
+
* @returns An array of runs; each run is an array of matching event indices.
|
|
67
|
+
*/
|
|
68
|
+
function findConsecutiveRuns(events, rule) {
|
|
69
|
+
const runs = [];
|
|
70
|
+
let currentRun = [];
|
|
71
|
+
for (let i = 0; i < events.length; i++) {
|
|
72
|
+
const event = events[i];
|
|
73
|
+
if (eventMatchesRule(event, rule)) {
|
|
74
|
+
currentRun.push(i);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
if (currentRun.length > 0) {
|
|
78
|
+
runs.push(currentRun);
|
|
79
|
+
currentRun = [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Don't forget the last run
|
|
84
|
+
if (currentRun.length > 0) {
|
|
85
|
+
runs.push(currentRun);
|
|
86
|
+
}
|
|
87
|
+
return runs;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Identifies all trace events that should be removed based on user-declared rules.
|
|
91
|
+
*
|
|
92
|
+
* Matching semantics:
|
|
93
|
+
* - **Within a rule**: all provided matchers must match (AND logic).
|
|
94
|
+
* - **Across rules**: any matching rule makes an event a removal candidate (OR logic).
|
|
95
|
+
* - **No automatic detection**: zero built-in heuristics; only explicitly declared rules apply.
|
|
96
|
+
*
|
|
97
|
+
* `minConsecutiveOccurrences` safety guard:
|
|
98
|
+
* If a rule declares this threshold, each consecutive run of matching events is
|
|
99
|
+
* evaluated against it. Runs that are *shorter* than the threshold are **skipped**
|
|
100
|
+
* (not removed) and a warning is emitted. This prevents accidentally deleting
|
|
101
|
+
* one-off occurrences of a step that also appears in noisy repeating sequences.
|
|
102
|
+
*
|
|
103
|
+
* @param events - The flat ordered list of trace events to scan.
|
|
104
|
+
* @param rules - The user-declared removal rules to apply.
|
|
105
|
+
* @returns A {@link RemovalSet} containing the indices and match details of every
|
|
106
|
+
* event selected for removal.
|
|
107
|
+
*/
|
|
108
|
+
function findStepsToRemove(events, rules) {
|
|
109
|
+
const indices = new Set();
|
|
110
|
+
const matches = [];
|
|
111
|
+
for (const rule of rules) {
|
|
112
|
+
if (rule.minConsecutiveOccurrences !== undefined) {
|
|
113
|
+
// Use consecutive-run logic
|
|
114
|
+
const runs = findConsecutiveRuns(events, rule);
|
|
115
|
+
for (const run of runs) {
|
|
116
|
+
if (run.length >= rule.minConsecutiveOccurrences) {
|
|
117
|
+
// Threshold met — remove all events in this run
|
|
118
|
+
for (const idx of run) {
|
|
119
|
+
indices.add(idx);
|
|
120
|
+
matches.push({
|
|
121
|
+
index: idx,
|
|
122
|
+
ruleLabel: rule.label,
|
|
123
|
+
event: events[idx],
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Threshold NOT met — warn and skip this entire run
|
|
129
|
+
logger_js_1.logger.warn(`Rule "${rule.label}" matched ${run.length} consecutive occurrences ` +
|
|
130
|
+
`but minConsecutiveOccurrences is ${rule.minConsecutiveOccurrences}. ` +
|
|
131
|
+
`Skipping removal. Review your rule.`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// No consecutive guard — remove every single match
|
|
137
|
+
for (let i = 0; i < events.length; i++) {
|
|
138
|
+
const event = events[i];
|
|
139
|
+
if (eventMatchesRule(event, rule)) {
|
|
140
|
+
indices.add(i);
|
|
141
|
+
matches.push({
|
|
142
|
+
index: i,
|
|
143
|
+
ruleLabel: rule.label,
|
|
144
|
+
event,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { indices, matches };
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/remove/detector.ts"],"names":[],"mappings":";;AAuHA,8CAiDC;AAvKD,4CAAsC;AAEtC;;;;;;;;;;GAUG;AACH,SAAS,YAAY,CACnB,KAAyB,EACzB,OAAoC;IAEpC,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAE/D,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,yDAAyD;QACzD,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAS,gBAAgB,CAAC,KAAiB,EAAE,IAAgB;IAC3D,MAAM,QAAQ,GAAsF;QAClG,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE;QACrF,EAAE,UAAU,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE;QACxD,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QAC9C,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE;KAC3E,CAAC;IAEF,sDAAsD;IACtD,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;IAEzE,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAE9C,6CAA6C;IAC7C,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,mBAAmB,CAC1B,MAAoB,EACpB,IAAgB;IAEhB,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,IAAI,UAAU,GAAa,EAAE,CAAC;IAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACzB,IAAI,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YAClC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACtB,UAAU,GAAG,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,iBAAiB,CAC/B,MAAoB,EACpB,KAAmB;IAEnB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,OAAO,GAAgB,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,yBAAyB,KAAK,SAAS,EAAE,CAAC;YACjD,4BAA4B;YAC5B,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAE/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,yBAAyB,EAAE,CAAC;oBACjD,gDAAgD;oBAChD,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;wBACtB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;wBACjB,OAAO,CAAC,IAAI,CAAC;4BACX,KAAK,EAAE,GAAG;4BACV,SAAS,EAAE,IAAI,CAAC,KAAK;4BACrB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAE;yBACpB,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oDAAoD;oBACpD,kBAAM,CAAC,IAAI,CACT,SAAS,IAAI,CAAC,KAAK,aAAa,GAAG,CAAC,MAAM,2BAA2B;wBACrE,oCAAoC,IAAI,CAAC,yBAAyB,IAAI;wBACtE,qCAAqC,CACtC,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;gBACzB,IAAI,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;oBAClC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC;wBACX,KAAK,EAAE,CAAC;wBACR,SAAS,EAAE,IAAI,CAAC,KAAK;wBACrB,KAAK;qBACN,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TraceEvent, RemovalSet } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Removes the matched steps — and all their descendants — from the events array.
|
|
4
|
+
*
|
|
5
|
+
* Algorithm:
|
|
6
|
+
* 1. Expands the removal set to include all descendant events (via {@link collectChildIndices}).
|
|
7
|
+
* 2. Sorts the combined indices in **descending** order so earlier indices remain
|
|
8
|
+
* stable as elements are spliced out.
|
|
9
|
+
* 3. Splices each index from a shallow copy of the events array.
|
|
10
|
+
*
|
|
11
|
+
* The input array is **never mutated** — a new array is returned.
|
|
12
|
+
*
|
|
13
|
+
* @param events - The ordered list of trace events.
|
|
14
|
+
* @param removalSet - The set of matched step indices (from {@link findStepsToRemove}).
|
|
15
|
+
* @returns A new array with all matched steps (and their descendants) removed.
|
|
16
|
+
*/
|
|
17
|
+
export declare function removeSteps(events: TraceEvent[], removalSet: RemovalSet): TraceEvent[];
|
|
18
|
+
//# sourceMappingURL=remover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remover.d.ts","sourceRoot":"","sources":["../../src/remove/remover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAyCjE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAAE,EACpB,UAAU,EAAE,UAAU,GACrB,UAAU,EAAE,CAwBd"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.removeSteps = removeSteps;
|
|
4
|
+
/**
|
|
5
|
+
* Recursively collects the indices of all descendant events for a given parent.
|
|
6
|
+
*
|
|
7
|
+
* Traverses the `callId` → `parentId` relationship: an event is considered a
|
|
8
|
+
* child of `parentIndex` if its `parentId` equals the parent's `callId`.
|
|
9
|
+
* Children of children are collected transitively.
|
|
10
|
+
*
|
|
11
|
+
* @param events - The flat event array being searched (current working copy).
|
|
12
|
+
* @param parentIndex - Zero-based index of the parent event in `allEvents`.
|
|
13
|
+
* @param allEvents - The original full event array used to look up the parent's `callId`.
|
|
14
|
+
* @returns A `Set` of all descendant indices (does **not** include `parentIndex` itself).
|
|
15
|
+
*/
|
|
16
|
+
function collectChildIndices(events, parentIndex, allEvents) {
|
|
17
|
+
const children = new Set();
|
|
18
|
+
const parentEvent = allEvents[parentIndex];
|
|
19
|
+
if (!parentEvent)
|
|
20
|
+
return children;
|
|
21
|
+
const parentCallId = parentEvent.callId;
|
|
22
|
+
if (!parentCallId)
|
|
23
|
+
return children;
|
|
24
|
+
for (let i = 0; i < events.length; i++) {
|
|
25
|
+
const event = events[i];
|
|
26
|
+
if (event && event.parentId === parentCallId && i !== parentIndex) {
|
|
27
|
+
children.add(i);
|
|
28
|
+
// Recursively collect children of children
|
|
29
|
+
const grandChildren = collectChildIndices(events, i, allEvents);
|
|
30
|
+
for (const gc of grandChildren) {
|
|
31
|
+
children.add(gc);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return children;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Removes the matched steps — and all their descendants — from the events array.
|
|
39
|
+
*
|
|
40
|
+
* Algorithm:
|
|
41
|
+
* 1. Expands the removal set to include all descendant events (via {@link collectChildIndices}).
|
|
42
|
+
* 2. Sorts the combined indices in **descending** order so earlier indices remain
|
|
43
|
+
* stable as elements are spliced out.
|
|
44
|
+
* 3. Splices each index from a shallow copy of the events array.
|
|
45
|
+
*
|
|
46
|
+
* The input array is **never mutated** — a new array is returned.
|
|
47
|
+
*
|
|
48
|
+
* @param events - The ordered list of trace events.
|
|
49
|
+
* @param removalSet - The set of matched step indices (from {@link findStepsToRemove}).
|
|
50
|
+
* @returns A new array with all matched steps (and their descendants) removed.
|
|
51
|
+
*/
|
|
52
|
+
function removeSteps(events, removalSet) {
|
|
53
|
+
// Expand removal set to include child indices
|
|
54
|
+
const expandedIndices = new Set(removalSet.indices);
|
|
55
|
+
for (const idx of removalSet.indices) {
|
|
56
|
+
const children = collectChildIndices(events, idx, events);
|
|
57
|
+
for (const childIdx of children) {
|
|
58
|
+
expandedIndices.add(childIdx);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Sort indices in reverse order for safe removal
|
|
62
|
+
const sortedIndices = Array.from(expandedIndices).sort((a, b) => b - a);
|
|
63
|
+
// Create a new array (immutability)
|
|
64
|
+
const result = [...events];
|
|
65
|
+
for (const idx of sortedIndices) {
|
|
66
|
+
if (idx >= 0 && idx < result.length) {
|
|
67
|
+
result.splice(idx, 1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=remover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remover.js","sourceRoot":"","sources":["../../src/remove/remover.ts"],"names":[],"mappings":";;AAwDA,kCA2BC;AAjFD;;;;;;;;;;;GAWG;AACH,SAAS,mBAAmB,CAC1B,MAAoB,EACpB,WAAmB,EACnB,SAAuB;IAEvB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,CAAC,WAAW;QAAE,OAAO,QAAQ,CAAC;IAElC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC;IACxC,IAAI,CAAC,YAAY;QAAE,OAAO,QAAQ,CAAC;IAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,YAAY,IAAI,CAAC,KAAK,WAAW,EAAE,CAAC;YAClE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChB,2CAA2C;YAC3C,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;YAChE,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;gBAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,WAAW,CACzB,MAAoB,EACpB,UAAsB;IAEtB,8CAA8C;IAC9C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAS,UAAU,CAAC,OAAO,CAAC,CAAC;IAE5D,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1D,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAChC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAExE,oCAAoC;IACpC,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RemoveRule } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a rule file path listed in `remove.ruleFiles` cannot be
|
|
4
|
+
* resolved or loaded.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RuleFileNotFoundError extends Error {
|
|
7
|
+
constructor(filePath: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Loads an array of {@link RemoveRule}s from an external file.
|
|
11
|
+
*
|
|
12
|
+
* Supported formats:
|
|
13
|
+
* - **`.json`** — parsed with `JSON.parse`; RegExp values are not supported.
|
|
14
|
+
* String matchers are evaluated as case-sensitive substring matches.
|
|
15
|
+
* - **`.ts` / `.js`** — loaded via dynamic `import()`; the file must export a
|
|
16
|
+
* default array of {@link RemoveRule} objects (supports `RegExp` fields).
|
|
17
|
+
* If a `.ts` file fails to import (e.g. no `tsx` / `ts-node` available),
|
|
18
|
+
* a compiled `.js` sibling at the same path is tried automatically.
|
|
19
|
+
*
|
|
20
|
+
* @param filePath - Absolute or relative path to the rule file.
|
|
21
|
+
* @returns Array of {@link RemoveRule}s defined in the file.
|
|
22
|
+
* @throws {@link RuleFileNotFoundError} if the file does not exist or cannot be loaded.
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadRuleFile(filePath: string): Promise<RemoveRule[]>;
|
|
25
|
+
//# sourceMappingURL=rule-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-loader.d.ts","sourceRoot":"","sources":["../../src/remove/rule-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,QAAQ,EAAE,MAAM;CAI7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAiD1E"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.RuleFileNotFoundError = void 0;
|
|
37
|
+
exports.loadRuleFile = loadRuleFile;
|
|
38
|
+
const fs = __importStar(require("node:fs"));
|
|
39
|
+
const path = __importStar(require("node:path"));
|
|
40
|
+
const logger_js_1 = require("../logger.js");
|
|
41
|
+
/**
|
|
42
|
+
* Thrown when a rule file path listed in `remove.ruleFiles` cannot be
|
|
43
|
+
* resolved or loaded.
|
|
44
|
+
*/
|
|
45
|
+
class RuleFileNotFoundError extends Error {
|
|
46
|
+
constructor(filePath) {
|
|
47
|
+
super(`remove.ruleFiles: file not found: ${filePath}`);
|
|
48
|
+
this.name = 'RuleFileNotFoundError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.RuleFileNotFoundError = RuleFileNotFoundError;
|
|
52
|
+
/**
|
|
53
|
+
* Loads an array of {@link RemoveRule}s from an external file.
|
|
54
|
+
*
|
|
55
|
+
* Supported formats:
|
|
56
|
+
* - **`.json`** — parsed with `JSON.parse`; RegExp values are not supported.
|
|
57
|
+
* String matchers are evaluated as case-sensitive substring matches.
|
|
58
|
+
* - **`.ts` / `.js`** — loaded via dynamic `import()`; the file must export a
|
|
59
|
+
* default array of {@link RemoveRule} objects (supports `RegExp` fields).
|
|
60
|
+
* If a `.ts` file fails to import (e.g. no `tsx` / `ts-node` available),
|
|
61
|
+
* a compiled `.js` sibling at the same path is tried automatically.
|
|
62
|
+
*
|
|
63
|
+
* @param filePath - Absolute or relative path to the rule file.
|
|
64
|
+
* @returns Array of {@link RemoveRule}s defined in the file.
|
|
65
|
+
* @throws {@link RuleFileNotFoundError} if the file does not exist or cannot be loaded.
|
|
66
|
+
*/
|
|
67
|
+
async function loadRuleFile(filePath) {
|
|
68
|
+
const absolutePath = path.resolve(filePath);
|
|
69
|
+
if (!fs.existsSync(absolutePath)) {
|
|
70
|
+
throw new RuleFileNotFoundError(filePath);
|
|
71
|
+
}
|
|
72
|
+
const ext = path.extname(absolutePath).toLowerCase();
|
|
73
|
+
if (ext === '.json') {
|
|
74
|
+
const content = fs.readFileSync(absolutePath, 'utf-8');
|
|
75
|
+
const parsed = JSON.parse(content);
|
|
76
|
+
if (!Array.isArray(parsed)) {
|
|
77
|
+
logger_js_1.logger.fatal(`Rule file ${filePath} must export an array of RemoveRule objects.`);
|
|
78
|
+
}
|
|
79
|
+
return parsed;
|
|
80
|
+
}
|
|
81
|
+
// .ts or .js — dynamic import
|
|
82
|
+
try {
|
|
83
|
+
const module = await import(absolutePath);
|
|
84
|
+
const rules = module.default ?? module;
|
|
85
|
+
if (!Array.isArray(rules)) {
|
|
86
|
+
logger_js_1.logger.fatal(`Rule file ${filePath} must export a default array of RemoveRule objects.`);
|
|
87
|
+
}
|
|
88
|
+
return rules;
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
if (ext === '.ts') {
|
|
92
|
+
const jsSibling = absolutePath.replace(/\.ts$/, '.js');
|
|
93
|
+
if (fs.existsSync(jsSibling)) {
|
|
94
|
+
try {
|
|
95
|
+
const module = await import(jsSibling);
|
|
96
|
+
const rules = module.default ?? module;
|
|
97
|
+
if (!Array.isArray(rules)) {
|
|
98
|
+
logger_js_1.logger.fatal(`Rule file ${jsSibling} must export a default array of RemoveRule objects.`);
|
|
99
|
+
}
|
|
100
|
+
return rules;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
throw new RuleFileNotFoundError(`Failed to load rule file from both ${filePath} and ${jsSibling}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
throw new RuleFileNotFoundError(`Failed to load rule file ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=rule-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-loader.js","sourceRoot":"","sources":["../../src/remove/rule-loader.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,oCAiDC;AAhFD,4CAA8B;AAC9B,gDAAkC;AAElC,4CAAsC;AAEtC;;;GAGG;AACH,MAAa,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,QAAgB;QAC1B,KAAK,CAAC,qCAAqC,QAAQ,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AALD,sDAKC;AAED;;;;;;;;;;;;;;GAcG;AACI,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE5C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAC;IAErD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;QACnD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,kBAAM,CAAC,KAAK,CAAC,aAAa,QAAQ,8CAA8C,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,8BAA8B;IAC9B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,kBAAM,CAAC,KAAK,CAAC,aAAa,QAAQ,qDAAqD,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,KAAqB,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAClB,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACvD,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;oBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC;oBACvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBAC1B,kBAAM,CAAC,KAAK,CAAC,aAAa,SAAS,qDAAqD,CAAC,CAAC;oBAC5F,CAAC;oBACD,OAAO,KAAqB,CAAC;gBAC/B,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,IAAI,qBAAqB,CAC7B,sCAAsC,QAAQ,QAAQ,SAAS,EAAE,CAClE,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,IAAI,qBAAqB,CAC7B,4BAA4B,QAAQ,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC5F,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RemoveConfig, RemoveRule } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Builds the complete, deduplicated list of {@link RemoveRule}s for a run.
|
|
4
|
+
*
|
|
5
|
+
* Merge order:
|
|
6
|
+
* 1. All rules loaded from `config.ruleFiles` (in declaration order)
|
|
7
|
+
* 2. Inline rules from `config.rules`
|
|
8
|
+
*
|
|
9
|
+
* No built-in rules are ever injected — only what the user explicitly declared.
|
|
10
|
+
* If the same `label` appears more than once, a warning is emitted and the **last**
|
|
11
|
+
* definition wins (last-write-wins semantics).
|
|
12
|
+
*
|
|
13
|
+
* @param config - The `remove` section of the sanitizer config.
|
|
14
|
+
* @returns Deduplicated array of validated {@link RemoveRule}s, ready for use.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildRuleRegistry(config: RemoveConfig): Promise<RemoveRule[]>;
|
|
17
|
+
//# sourceMappingURL=rule-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-registry.d.ts","sourceRoot":"","sources":["../../src/remove/rule-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKnE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,UAAU,EAAE,CAAC,CA6CvB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildRuleRegistry = buildRuleRegistry;
|
|
4
|
+
const rule_loader_js_1 = require("./rule-loader.js");
|
|
5
|
+
const validator_js_1 = require("../config/validator.js");
|
|
6
|
+
const logger_js_1 = require("../logger.js");
|
|
7
|
+
/**
|
|
8
|
+
* Builds the complete, deduplicated list of {@link RemoveRule}s for a run.
|
|
9
|
+
*
|
|
10
|
+
* Merge order:
|
|
11
|
+
* 1. All rules loaded from `config.ruleFiles` (in declaration order)
|
|
12
|
+
* 2. Inline rules from `config.rules`
|
|
13
|
+
*
|
|
14
|
+
* No built-in rules are ever injected — only what the user explicitly declared.
|
|
15
|
+
* If the same `label` appears more than once, a warning is emitted and the **last**
|
|
16
|
+
* definition wins (last-write-wins semantics).
|
|
17
|
+
*
|
|
18
|
+
* @param config - The `remove` section of the sanitizer config.
|
|
19
|
+
* @returns Deduplicated array of validated {@link RemoveRule}s, ready for use.
|
|
20
|
+
*/
|
|
21
|
+
async function buildRuleRegistry(config) {
|
|
22
|
+
const allRules = [];
|
|
23
|
+
// Load from rule files first
|
|
24
|
+
if (config.ruleFiles) {
|
|
25
|
+
const files = Array.isArray(config.ruleFiles)
|
|
26
|
+
? config.ruleFiles
|
|
27
|
+
: [config.ruleFiles];
|
|
28
|
+
for (const filePath of files) {
|
|
29
|
+
const rules = await (0, rule_loader_js_1.loadRuleFile)(filePath);
|
|
30
|
+
allRules.push(...rules);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Then inline rules
|
|
34
|
+
if (config.rules) {
|
|
35
|
+
allRules.push(...config.rules);
|
|
36
|
+
}
|
|
37
|
+
// Validate each rule
|
|
38
|
+
for (const rule of allRules) {
|
|
39
|
+
(0, validator_js_1.validateRule)(rule);
|
|
40
|
+
}
|
|
41
|
+
// Check for duplicate labels and warn
|
|
42
|
+
const seenLabels = new Map();
|
|
43
|
+
for (let i = 0; i < allRules.length; i++) {
|
|
44
|
+
const rule = allRules[i];
|
|
45
|
+
const previousIndex = seenLabels.get(rule.label);
|
|
46
|
+
if (previousIndex !== undefined) {
|
|
47
|
+
logger_js_1.logger.warn(`Duplicate rule label "${rule.label}" — last definition wins (index ${i} replaces ${previousIndex}).`);
|
|
48
|
+
}
|
|
49
|
+
seenLabels.set(rule.label, i);
|
|
50
|
+
}
|
|
51
|
+
// Deduplicate: last-write-wins
|
|
52
|
+
const deduped = new Map();
|
|
53
|
+
for (const rule of allRules) {
|
|
54
|
+
deduped.set(rule.label, rule);
|
|
55
|
+
}
|
|
56
|
+
return Array.from(deduped.values());
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=rule-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-registry.js","sourceRoot":"","sources":["../../src/remove/rule-registry.ts"],"names":[],"mappings":";;AAmBA,8CA+CC;AAjED,qDAAgD;AAChD,yDAAsD;AACtD,4CAAsC;AAEtC;;;;;;;;;;;;;GAaG;AACI,KAAK,UAAU,iBAAiB,CACrC,MAAoB;IAEpB,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAElC,6BAA6B;IAC7B,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;YAC3C,CAAC,CAAC,MAAM,CAAC,SAAS;YAClB,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEvB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,MAAM,IAAA,6BAAY,EAAC,QAAQ,CAAC,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,qBAAqB;IACrB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAA,2BAAY,EAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAED,sCAAsC;IACtC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC1B,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,kBAAM,CAAC,IAAI,CACT,yBAAyB,IAAI,CAAC,KAAK,mCAAmC,CAAC,aAAa,aAAa,IAAI,CACtG,CAAC;QACJ,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,+BAA+B;IAC/B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TraceEvent, TimestampStrategy } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Repairs the event timeline after steps have been removed, so that the total
|
|
4
|
+
* duration reported in the Playwright UI remains coherent.
|
|
5
|
+
*
|
|
6
|
+
* For each removed event, the duration (`endTime - startTime`) that it occupied
|
|
7
|
+
* is redistributed to an adjacent event according to the chosen strategy:
|
|
8
|
+
*
|
|
9
|
+
* - **`'absorb-into-prev'`** *(default)*: the preceding event's `endTime` is
|
|
10
|
+
* extended by the removed duration. Falls back to shifting the following
|
|
11
|
+
* event's `startTime` if no preceding event exists.
|
|
12
|
+
* - **`'absorb-into-next'`**: the following event's `startTime` is shifted
|
|
13
|
+
* back by the removed duration. Falls back to extending the preceding
|
|
14
|
+
* event if no following event exists.
|
|
15
|
+
* - **`'gap'`**: no adjustment — a visible gap will appear in the timeline.
|
|
16
|
+
*
|
|
17
|
+
* After redistribution, events where `startTime > endTime` are detected and
|
|
18
|
+
* corrected (a warning is emitted for each such case).
|
|
19
|
+
*
|
|
20
|
+
* The input arrays are **never mutated** — a new events array is returned.
|
|
21
|
+
*
|
|
22
|
+
* @param events - The events array **after** step removal (output of {@link removeSteps}).
|
|
23
|
+
* @param removedEvents - The events that were removed (needed to determine their durations).
|
|
24
|
+
* @param strategy - The {@link TimestampStrategy} to apply.
|
|
25
|
+
* @returns A new array of events with adjusted timestamps.
|
|
26
|
+
*/
|
|
27
|
+
export declare function repairTimestamps(events: TraceEvent[], removedEvents: TraceEvent[], strategy: TimestampStrategy): TraceEvent[];
|
|
28
|
+
//# sourceMappingURL=timestamp-repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestamp-repair.d.ts","sourceRoot":"","sources":["../../src/remove/timestamp-repair.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAGxE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAAE,EACpB,aAAa,EAAE,UAAU,EAAE,EAC3B,QAAQ,EAAE,iBAAiB,GAC1B,UAAU,EAAE,CA+Bd"}
|