@hackylabs/deep-redact 2.2.0 → 3.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/LICENSE +1 -1
- package/README.md +36 -56
- package/dist/cjs/index.js +10 -131
- package/dist/cjs/utils/index.js +429 -0
- package/dist/cjs/utils/standardTransformers/bigint.js +10 -0
- package/dist/cjs/utils/standardTransformers/date.js +9 -0
- package/dist/cjs/utils/standardTransformers/error.js +16 -0
- package/dist/cjs/utils/standardTransformers/index.js +19 -0
- package/dist/cjs/utils/standardTransformers/map.js +9 -0
- package/dist/cjs/utils/standardTransformers/regex.js +15 -0
- package/dist/cjs/utils/standardTransformers/set.js +9 -0
- package/dist/cjs/utils/standardTransformers/url.js +9 -0
- package/dist/esm/index.mjs +9 -128
- package/dist/esm/utils/index.mjs +423 -0
- package/dist/esm/utils/standardTransformers/bigint.js +6 -0
- package/dist/esm/utils/standardTransformers/date.js +5 -0
- package/dist/esm/utils/standardTransformers/error.js +12 -0
- package/dist/esm/utils/standardTransformers/index.js +16 -0
- package/dist/esm/utils/standardTransformers/map.js +5 -0
- package/dist/esm/utils/standardTransformers/regex.js +11 -0
- package/dist/esm/utils/standardTransformers/set.js +5 -0
- package/dist/esm/utils/standardTransformers/url.js +5 -0
- package/dist/types/index.d.ts +3 -38
- package/dist/types/types.d.ts +48 -17
- package/dist/types/utils/index.d.ts +130 -0
- package/dist/types/utils/standardTransformers/bigint.d.ts +2 -0
- package/dist/types/utils/standardTransformers/date.d.ts +2 -0
- package/dist/types/utils/standardTransformers/error.d.ts +2 -0
- package/dist/types/utils/standardTransformers/index.d.ts +2 -0
- package/dist/types/utils/standardTransformers/map.d.ts +2 -0
- package/dist/types/utils/standardTransformers/regex.d.ts +2 -0
- package/dist/types/utils/standardTransformers/set.d.ts +2 -0
- package/dist/types/utils/standardTransformers/url.d.ts +2 -0
- package/package.json +66 -13
- package/dist/cjs/utils/redactorUtils.js +0 -263
- package/dist/esm/utils/redactorUtils.mjs +0 -264
- package/dist/types/utils/redactorUtils.d.ts +0 -91
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const standardTransformers_1 = require("./standardTransformers");
|
|
4
|
+
const defaultConfig = {
|
|
5
|
+
stringTests: [],
|
|
6
|
+
blacklistedKeys: [],
|
|
7
|
+
fuzzyKeyMatch: false,
|
|
8
|
+
caseSensitiveKeyMatch: true,
|
|
9
|
+
retainStructure: false,
|
|
10
|
+
remove: false,
|
|
11
|
+
replaceStringByLength: false,
|
|
12
|
+
replacement: '[REDACTED]',
|
|
13
|
+
types: ['string'],
|
|
14
|
+
transformers: standardTransformers_1.standardTransformers,
|
|
15
|
+
};
|
|
16
|
+
class RedactorUtils {
|
|
17
|
+
constructor(customConfig) {
|
|
18
|
+
var _a, _b;
|
|
19
|
+
/**
|
|
20
|
+
* The configuration for the redaction.
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
this.config = defaultConfig;
|
|
24
|
+
/**
|
|
25
|
+
* The computed regex pattern generated from sanitised blacklist keys of flat strings
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
this.computedRegex = null;
|
|
29
|
+
/**
|
|
30
|
+
* Regex to sanitise strings for the computed regex
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
this.sanitiseRegex = /[^a-zA-Z0-9_\-\$]/g;
|
|
34
|
+
/**
|
|
35
|
+
* The transformed blacklist keys of flat regex patterns and complex config objects
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
this.blacklistedKeysTransformed = [];
|
|
39
|
+
this.createTransformedBlacklistedKey = (key, customConfig) => {
|
|
40
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
41
|
+
if (key instanceof RegExp) {
|
|
42
|
+
return {
|
|
43
|
+
key,
|
|
44
|
+
fuzzyKeyMatch: (_a = customConfig.fuzzyKeyMatch) !== null && _a !== void 0 ? _a : defaultConfig.fuzzyKeyMatch,
|
|
45
|
+
caseSensitiveKeyMatch: (_b = customConfig.caseSensitiveKeyMatch) !== null && _b !== void 0 ? _b : defaultConfig.caseSensitiveKeyMatch,
|
|
46
|
+
retainStructure: (_c = customConfig.retainStructure) !== null && _c !== void 0 ? _c : defaultConfig.retainStructure,
|
|
47
|
+
replacement: (_d = customConfig.replacement) !== null && _d !== void 0 ? _d : defaultConfig.replacement,
|
|
48
|
+
replaceStringByLength: (_e = customConfig.replaceStringByLength) !== null && _e !== void 0 ? _e : defaultConfig.replaceStringByLength,
|
|
49
|
+
remove: (_f = customConfig.remove) !== null && _f !== void 0 ? _f : defaultConfig.remove,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
fuzzyKeyMatch: (_h = (_g = key.fuzzyKeyMatch) !== null && _g !== void 0 ? _g : customConfig.fuzzyKeyMatch) !== null && _h !== void 0 ? _h : defaultConfig.fuzzyKeyMatch,
|
|
54
|
+
caseSensitiveKeyMatch: (_k = (_j = key.caseSensitiveKeyMatch) !== null && _j !== void 0 ? _j : customConfig.caseSensitiveKeyMatch) !== null && _k !== void 0 ? _k : defaultConfig.caseSensitiveKeyMatch,
|
|
55
|
+
retainStructure: (_m = (_l = key.retainStructure) !== null && _l !== void 0 ? _l : customConfig.retainStructure) !== null && _m !== void 0 ? _m : defaultConfig.retainStructure,
|
|
56
|
+
replacement: (_p = (_o = key.replacement) !== null && _o !== void 0 ? _o : customConfig.replacement) !== null && _p !== void 0 ? _p : defaultConfig.replacement,
|
|
57
|
+
replaceStringByLength: (_r = (_q = key.replaceStringByLength) !== null && _q !== void 0 ? _q : customConfig.replaceStringByLength) !== null && _r !== void 0 ? _r : defaultConfig.replaceStringByLength,
|
|
58
|
+
remove: (_t = (_s = key.remove) !== null && _s !== void 0 ? _s : customConfig.remove) !== null && _t !== void 0 ? _t : defaultConfig.remove,
|
|
59
|
+
key: key.key,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Applies transformers to a value
|
|
64
|
+
* @param value - The value to transform
|
|
65
|
+
* @param key - The key to check
|
|
66
|
+
* @returns The transformed value
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
this.applyTransformers = (value, key, referenceMap) => {
|
|
70
|
+
if (typeof value === 'string')
|
|
71
|
+
return value;
|
|
72
|
+
let transformed = value;
|
|
73
|
+
for (const transformer of this.config.transformers) {
|
|
74
|
+
transformed = transformer(transformed, key, referenceMap);
|
|
75
|
+
if (transformed !== value)
|
|
76
|
+
return transformed;
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Sanitises a string for the computed regex
|
|
82
|
+
* @param key - The string to sanitise
|
|
83
|
+
* @returns The sanitised string
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
this.sanitiseStringForRegex = (key) => key.replace(this.sanitiseRegex, '');
|
|
87
|
+
/**
|
|
88
|
+
* Checks if a key should be redacted
|
|
89
|
+
* @param key - The key to check
|
|
90
|
+
* @returns Whether the key should be redacted
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
this.shouldRedactKey = (key) => {
|
|
94
|
+
var _a;
|
|
95
|
+
if ((_a = this.computedRegex) === null || _a === void 0 ? void 0 : _a.test(this.sanitiseStringForRegex(key)))
|
|
96
|
+
return true;
|
|
97
|
+
return this.blacklistedKeysTransformed.some(config => {
|
|
98
|
+
const pattern = config.key;
|
|
99
|
+
if (pattern instanceof RegExp)
|
|
100
|
+
return pattern.test(key);
|
|
101
|
+
if (!config.fuzzyKeyMatch && !config.caseSensitiveKeyMatch)
|
|
102
|
+
return key.toLowerCase() === pattern.toLowerCase();
|
|
103
|
+
if (config.fuzzyKeyMatch && !config.caseSensitiveKeyMatch)
|
|
104
|
+
return key.toLowerCase().includes(pattern.toLowerCase());
|
|
105
|
+
if (config.fuzzyKeyMatch && config.caseSensitiveKeyMatch)
|
|
106
|
+
return key.includes(pattern);
|
|
107
|
+
if (!config.fuzzyKeyMatch && config.caseSensitiveKeyMatch)
|
|
108
|
+
return key === pattern;
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Checks if a value should be redacted
|
|
113
|
+
* @param value - The value to check
|
|
114
|
+
* @param key - The key to check
|
|
115
|
+
* @returns Whether the value should be redacted
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
this.shouldRedactValue = (value, valueKey) => {
|
|
119
|
+
if (!this.config.types.includes(typeof value))
|
|
120
|
+
return false;
|
|
121
|
+
return this.shouldRedactKey(valueKey);
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Redacts a value based on the key-specific config
|
|
125
|
+
* @param value - The value to redact
|
|
126
|
+
* @param key - The key to check
|
|
127
|
+
* @param redactingParent - Whether the parent is being redacted
|
|
128
|
+
* @returns The redacted value
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
this.redactValue = (value, redactingParent, keyConfig) => {
|
|
132
|
+
var _a, _b, _c, _d;
|
|
133
|
+
if (!this.config.types.includes(typeof value))
|
|
134
|
+
return { transformed: value, redactingParent };
|
|
135
|
+
const remove = (_a = keyConfig === null || keyConfig === void 0 ? void 0 : keyConfig.remove) !== null && _a !== void 0 ? _a : this.config.remove;
|
|
136
|
+
const replacement = (_b = keyConfig === null || keyConfig === void 0 ? void 0 : keyConfig.replacement) !== null && _b !== void 0 ? _b : this.config.replacement;
|
|
137
|
+
const replaceStringByLength = (_c = keyConfig === null || keyConfig === void 0 ? void 0 : keyConfig.replaceStringByLength) !== null && _c !== void 0 ? _c : this.config.replaceStringByLength;
|
|
138
|
+
const retainStructure = (_d = keyConfig === null || keyConfig === void 0 ? void 0 : keyConfig.retainStructure) !== null && _d !== void 0 ? _d : this.config.retainStructure;
|
|
139
|
+
if (retainStructure && typeof value === 'object' && value !== null)
|
|
140
|
+
return { transformed: value, redactingParent: true };
|
|
141
|
+
if (remove)
|
|
142
|
+
return { transformed: undefined, redactingParent };
|
|
143
|
+
if (typeof replacement === 'function')
|
|
144
|
+
return { transformed: replacement(value), redactingParent };
|
|
145
|
+
return {
|
|
146
|
+
redactingParent,
|
|
147
|
+
transformed: (typeof value === 'string' && replaceStringByLength)
|
|
148
|
+
? replacement.toString().repeat(value.length)
|
|
149
|
+
: replacement,
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Traverses the raw value
|
|
154
|
+
* @param raw - The raw value to traverse
|
|
155
|
+
* @returns The transformed value
|
|
156
|
+
*/
|
|
157
|
+
this.traverse = (raw) => {
|
|
158
|
+
if (typeof raw === 'string') {
|
|
159
|
+
const { transformed } = this.applyStringTransformations(raw, false);
|
|
160
|
+
return transformed;
|
|
161
|
+
}
|
|
162
|
+
if (typeof raw !== 'object' || raw === null)
|
|
163
|
+
return raw;
|
|
164
|
+
const referenceMap = new WeakMap();
|
|
165
|
+
const cleanedInput = this.replaceCircularReferences(raw);
|
|
166
|
+
const { output, stack } = this.initialiseTraversal(cleanedInput);
|
|
167
|
+
if (typeof cleanedInput === 'object' && cleanedInput !== null)
|
|
168
|
+
referenceMap.set(cleanedInput, '');
|
|
169
|
+
while (stack.length > 0) {
|
|
170
|
+
const { parent, key, value, path, redactingParent: amRedactingParent, keyConfig } = stack.pop();
|
|
171
|
+
let transformed = this.applyTransformers(value, key, referenceMap);
|
|
172
|
+
let redactingParent = amRedactingParent;
|
|
173
|
+
if (typeof transformed !== 'object' || transformed === null) {
|
|
174
|
+
const primitiveResult = this.handlePrimitiveValue(transformed, key, amRedactingParent, keyConfig);
|
|
175
|
+
redactingParent = primitiveResult.redactingParent;
|
|
176
|
+
transformed = primitiveResult.transformed;
|
|
177
|
+
if (typeof transformed === 'undefined')
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const objectResult = this.handleObjectValue(transformed, key, path, redactingParent, referenceMap, keyConfig);
|
|
182
|
+
transformed = objectResult.transformed;
|
|
183
|
+
stack.push(...objectResult.stack);
|
|
184
|
+
}
|
|
185
|
+
if (parent !== null && key !== null)
|
|
186
|
+
parent[key] = transformed;
|
|
187
|
+
}
|
|
188
|
+
return output;
|
|
189
|
+
};
|
|
190
|
+
this.config = Object.assign(Object.assign({}, defaultConfig), customConfig);
|
|
191
|
+
this.blacklistedKeysTransformed = ((_a = customConfig.blacklistedKeys) !== null && _a !== void 0 ? _a : []).filter(key => typeof key !== 'string').map((key) => this.createTransformedBlacklistedKey(key, customConfig));
|
|
192
|
+
const stringKeys = ((_b = customConfig.blacklistedKeys) !== null && _b !== void 0 ? _b : []).filter(key => typeof key === 'string');
|
|
193
|
+
if (stringKeys.length > 0)
|
|
194
|
+
this.computedRegex = new RegExp(stringKeys.map(this.sanitiseStringForRegex).filter(Boolean).join('|'));
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Applies string transformations
|
|
198
|
+
* @param value - The value to transform
|
|
199
|
+
* @param key - The key to check
|
|
200
|
+
* @returns The transformed value
|
|
201
|
+
* @private
|
|
202
|
+
*/
|
|
203
|
+
applyStringTransformations(value, amRedactingParent, keyConfig) {
|
|
204
|
+
var _a;
|
|
205
|
+
if (((_a = this.config.stringTests) !== null && _a !== void 0 ? _a : []).length === 0)
|
|
206
|
+
return { transformed: value, redactingParent: amRedactingParent };
|
|
207
|
+
for (const test of this.config.stringTests) {
|
|
208
|
+
if (test instanceof RegExp) {
|
|
209
|
+
if (test.test(value)) {
|
|
210
|
+
const { transformed, redactingParent } = this.redactValue(value, amRedactingParent, keyConfig);
|
|
211
|
+
return { transformed: transformed, redactingParent };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
if (test.pattern.test(value)) {
|
|
216
|
+
const transformed = test.replacer(value, test.pattern);
|
|
217
|
+
return { transformed, redactingParent: amRedactingParent };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return { transformed: value, redactingParent: amRedactingParent };
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Handles primitive values
|
|
225
|
+
* @param value - The value to handle
|
|
226
|
+
* @param key - The key to check
|
|
227
|
+
* @param redactingParent - Whether the parent is being redacted
|
|
228
|
+
* @param keyConfig - The key config
|
|
229
|
+
* @returns The transformed value
|
|
230
|
+
* @private
|
|
231
|
+
*/
|
|
232
|
+
handlePrimitiveValue(value, valueKey, redactingParent, keyConfig) {
|
|
233
|
+
let transformed = value;
|
|
234
|
+
if (redactingParent) {
|
|
235
|
+
if (valueKey === '_transformer' || !this.config.types.includes(typeof value)) {
|
|
236
|
+
return { transformed: value, redactingParent };
|
|
237
|
+
}
|
|
238
|
+
const { transformed: transformedValue } = this.redactValue(value, redactingParent, keyConfig);
|
|
239
|
+
return { transformed: transformedValue, redactingParent };
|
|
240
|
+
}
|
|
241
|
+
if (keyConfig || this.shouldRedactValue(value, valueKey)) {
|
|
242
|
+
return this.redactValue(value, redactingParent, keyConfig);
|
|
243
|
+
}
|
|
244
|
+
if (typeof value === 'string') {
|
|
245
|
+
return this.applyStringTransformations(value, redactingParent, keyConfig);
|
|
246
|
+
}
|
|
247
|
+
return { transformed, redactingParent };
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Handles object values
|
|
251
|
+
* @param value - The value to handle
|
|
252
|
+
* @param key - The key to check
|
|
253
|
+
* @param path - The path to the value
|
|
254
|
+
* @param redactingParent - Whether the parent is being redacted
|
|
255
|
+
* @param referenceMap - The reference map
|
|
256
|
+
* @returns The transformed value and stack
|
|
257
|
+
* @private
|
|
258
|
+
*/
|
|
259
|
+
handleObjectValue(value, key, path, amRedactingParent, referenceMap, keyConfig) {
|
|
260
|
+
var _a;
|
|
261
|
+
const fullPath = path.join('.');
|
|
262
|
+
const shouldRedact = amRedactingParent || Boolean(keyConfig) || this.shouldRedactValue(value, key);
|
|
263
|
+
referenceMap.set(value, fullPath);
|
|
264
|
+
if (shouldRedact && !((_a = keyConfig === null || keyConfig === void 0 ? void 0 : keyConfig.retainStructure) !== null && _a !== void 0 ? _a : this.config.retainStructure)) {
|
|
265
|
+
const { transformed, redactingParent } = this.redactValue(value, amRedactingParent, keyConfig);
|
|
266
|
+
return { transformed, redactingParent, stack: [] };
|
|
267
|
+
}
|
|
268
|
+
return this.handleRetainStructure(value, path, shouldRedact);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Handles object values
|
|
272
|
+
* @param value - The value to handle
|
|
273
|
+
* @param path - The path to the value
|
|
274
|
+
* @param redactingParent - Whether the parent is being redacted
|
|
275
|
+
* @returns The transformed value and stack
|
|
276
|
+
* @private
|
|
277
|
+
*/
|
|
278
|
+
handleRetainStructure(value, path, redactingParent) {
|
|
279
|
+
const newValue = Array.isArray(value) ? [] : {};
|
|
280
|
+
const stack = [];
|
|
281
|
+
if (Array.isArray(value)) {
|
|
282
|
+
for (let i = value.length - 1; i >= 0; i--) {
|
|
283
|
+
stack.push({
|
|
284
|
+
parent: newValue,
|
|
285
|
+
key: i.toString(),
|
|
286
|
+
value: value[i],
|
|
287
|
+
path: [...path, i],
|
|
288
|
+
redactingParent,
|
|
289
|
+
keyConfig: this.findMatchingKeyConfig(i.toString()),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
for (const [propKey, propValue] of Object.entries(value).reverse()) {
|
|
295
|
+
stack.push({
|
|
296
|
+
parent: newValue,
|
|
297
|
+
key: propKey,
|
|
298
|
+
value: propValue,
|
|
299
|
+
path: [...path, propKey],
|
|
300
|
+
redactingParent,
|
|
301
|
+
keyConfig: this.findMatchingKeyConfig(propKey),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return { transformed: newValue, redactingParent, stack };
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Finds the matching key config
|
|
309
|
+
* @param key - The key to find
|
|
310
|
+
* @returns The matching key config
|
|
311
|
+
* @private
|
|
312
|
+
*/
|
|
313
|
+
findMatchingKeyConfig(key) {
|
|
314
|
+
var _a;
|
|
315
|
+
if ((_a = this.computedRegex) === null || _a === void 0 ? void 0 : _a.test(key)) {
|
|
316
|
+
return {
|
|
317
|
+
key,
|
|
318
|
+
fuzzyKeyMatch: this.config.fuzzyKeyMatch,
|
|
319
|
+
caseSensitiveKeyMatch: this.config.caseSensitiveKeyMatch,
|
|
320
|
+
replaceStringByLength: this.config.replaceStringByLength,
|
|
321
|
+
replacement: this.config.replacement,
|
|
322
|
+
retainStructure: this.config.retainStructure,
|
|
323
|
+
remove: this.config.remove,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
return this.blacklistedKeysTransformed.find(config => {
|
|
327
|
+
const pattern = config.key;
|
|
328
|
+
if (pattern instanceof RegExp)
|
|
329
|
+
return pattern.test(key);
|
|
330
|
+
if (config.fuzzyKeyMatch) {
|
|
331
|
+
const compareKey = config.caseSensitiveKeyMatch ? key : key.toLowerCase();
|
|
332
|
+
const comparePattern = config.caseSensitiveKeyMatch ? pattern : pattern.toLowerCase();
|
|
333
|
+
return compareKey.includes(comparePattern);
|
|
334
|
+
}
|
|
335
|
+
return config.caseSensitiveKeyMatch ? key === pattern : key.toLowerCase() === pattern.toLowerCase();
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Initialises the traversal
|
|
340
|
+
* @param raw - The raw value to traverse
|
|
341
|
+
* @returns The output and stack
|
|
342
|
+
* @private
|
|
343
|
+
*/
|
|
344
|
+
initialiseTraversal(raw) {
|
|
345
|
+
const output = Array.isArray(raw) ? [] : {};
|
|
346
|
+
const stack = [];
|
|
347
|
+
if (typeof raw === 'object' && raw !== null) {
|
|
348
|
+
if (Array.isArray(raw)) {
|
|
349
|
+
for (let i = raw.length - 1; i >= 0; i--) {
|
|
350
|
+
stack.push({
|
|
351
|
+
parent: output,
|
|
352
|
+
key: i.toString(),
|
|
353
|
+
value: raw[i],
|
|
354
|
+
path: [i],
|
|
355
|
+
redactingParent: false,
|
|
356
|
+
keyConfig: this.findMatchingKeyConfig(i.toString()),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
for (const [propKey, propValue] of Object.entries(raw).reverse()) {
|
|
362
|
+
stack.push({
|
|
363
|
+
parent: output,
|
|
364
|
+
key: propKey,
|
|
365
|
+
value: propValue,
|
|
366
|
+
path: [propKey],
|
|
367
|
+
redactingParent: false,
|
|
368
|
+
keyConfig: this.findMatchingKeyConfig(propKey),
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return { output, stack };
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Pre-processes the input to replace circular references with transformer objects
|
|
377
|
+
* @param raw - The raw value to process
|
|
378
|
+
* @returns The processed value with circular references replaced
|
|
379
|
+
* @private
|
|
380
|
+
*/
|
|
381
|
+
replaceCircularReferences(raw) {
|
|
382
|
+
if (typeof raw !== 'object' || raw === null)
|
|
383
|
+
return raw;
|
|
384
|
+
const visiting = new WeakSet();
|
|
385
|
+
const pathMap = new WeakMap();
|
|
386
|
+
const processValue = (value, path) => {
|
|
387
|
+
if (typeof value !== 'object' || value === null)
|
|
388
|
+
return value;
|
|
389
|
+
if (visiting.has(value)) {
|
|
390
|
+
const originalPath = pathMap.get(value) || '';
|
|
391
|
+
return {
|
|
392
|
+
_transformer: 'circular',
|
|
393
|
+
value: originalPath,
|
|
394
|
+
path: path
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
visiting.add(value);
|
|
398
|
+
pathMap.set(value, path);
|
|
399
|
+
let result;
|
|
400
|
+
if (Array.isArray(value)) {
|
|
401
|
+
let hasCircular = false;
|
|
402
|
+
const newArray = value.map((item, index) => {
|
|
403
|
+
const itemPath = path ? `${path}.${index}` : index.toString();
|
|
404
|
+
const processed = processValue(item, itemPath);
|
|
405
|
+
if (processed !== item)
|
|
406
|
+
hasCircular = true;
|
|
407
|
+
return processed;
|
|
408
|
+
});
|
|
409
|
+
result = hasCircular ? newArray : value;
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
let hasCircular = false;
|
|
413
|
+
const newObj = {};
|
|
414
|
+
for (const [key, val] of Object.entries(value)) {
|
|
415
|
+
const valuePath = path ? `${path}.${key}` : key;
|
|
416
|
+
const processed = processValue(val, valuePath);
|
|
417
|
+
newObj[key] = processed;
|
|
418
|
+
if (processed !== val)
|
|
419
|
+
hasCircular = true;
|
|
420
|
+
}
|
|
421
|
+
result = hasCircular ? newObj : value;
|
|
422
|
+
}
|
|
423
|
+
visiting.delete(value);
|
|
424
|
+
return result;
|
|
425
|
+
};
|
|
426
|
+
return processValue(raw, '');
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
exports.default = RedactorUtils;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._bigint = void 0;
|
|
4
|
+
const _bigint = (value) => {
|
|
5
|
+
if (typeof value !== 'bigint')
|
|
6
|
+
return value;
|
|
7
|
+
const radix = 10;
|
|
8
|
+
return { value: { radix, number: value.toString(radix) }, _transformer: 'bigint' };
|
|
9
|
+
};
|
|
10
|
+
exports._bigint = _bigint;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._date = void 0;
|
|
4
|
+
const _date = (value) => {
|
|
5
|
+
if (value instanceof Date)
|
|
6
|
+
return { datetime: value.toISOString(), _transformer: 'date' };
|
|
7
|
+
return value;
|
|
8
|
+
};
|
|
9
|
+
exports._date = _date;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._error = void 0;
|
|
4
|
+
const _error = (value) => {
|
|
5
|
+
if (!(value instanceof Error))
|
|
6
|
+
return value;
|
|
7
|
+
return {
|
|
8
|
+
_transformer: 'error',
|
|
9
|
+
value: {
|
|
10
|
+
type: value.constructor.name,
|
|
11
|
+
message: value.message,
|
|
12
|
+
stack: value.stack,
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
exports._error = _error;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.standardTransformers = void 0;
|
|
4
|
+
const bigint_1 = require("./bigint");
|
|
5
|
+
const date_1 = require("./date");
|
|
6
|
+
const error_1 = require("./error");
|
|
7
|
+
const map_1 = require("./map");
|
|
8
|
+
const regex_1 = require("./regex");
|
|
9
|
+
const set_1 = require("./set");
|
|
10
|
+
const url_1 = require("./url");
|
|
11
|
+
exports.standardTransformers = [
|
|
12
|
+
bigint_1._bigint,
|
|
13
|
+
url_1._url,
|
|
14
|
+
date_1._date,
|
|
15
|
+
error_1._error,
|
|
16
|
+
map_1._map,
|
|
17
|
+
set_1._set,
|
|
18
|
+
regex_1._regex,
|
|
19
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._map = void 0;
|
|
4
|
+
const _map = (value) => {
|
|
5
|
+
if (value instanceof Map)
|
|
6
|
+
return { value: Object.fromEntries(value.entries()), _transformer: 'map' };
|
|
7
|
+
return value;
|
|
8
|
+
};
|
|
9
|
+
exports._map = _map;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._regex = void 0;
|
|
4
|
+
const _regex = (value) => {
|
|
5
|
+
if (!(value instanceof RegExp))
|
|
6
|
+
return value;
|
|
7
|
+
return {
|
|
8
|
+
_transformer: 'regex',
|
|
9
|
+
value: {
|
|
10
|
+
source: value.source,
|
|
11
|
+
flags: value.flags,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
exports._regex = _regex;
|