axe 12.2.3 → 12.2.5
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/dist/axe.js +33 -27
- package/dist/axe.min.js +1 -1
- package/lib/index.d.ts +247 -0
- package/lib/index.js +11 -7
- package/package.json +23 -20
- package/src/index.d.ts +247 -0
- package/src/index.js +634 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-unassigned-import
|
|
2
|
+
require('console-polyfill');
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line unicorn/prefer-node-protocol
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const format = require('@ladjs/format-util');
|
|
7
|
+
const formatSpecifiers = require('format-specifiers');
|
|
8
|
+
const get = require('@strikeentco/get');
|
|
9
|
+
const isError = require('iserror');
|
|
10
|
+
const isSymbol = require('is-symbol');
|
|
11
|
+
const mergeOptions = require('merge-options');
|
|
12
|
+
const pMapSeries = require('p-map-series');
|
|
13
|
+
const parseAppInfo = require('parse-app-info');
|
|
14
|
+
const parseErr = require('parse-err');
|
|
15
|
+
const pickDeep = require('pick-deep');
|
|
16
|
+
const set = require('@strikeentco/set');
|
|
17
|
+
const unset = require('unset-value');
|
|
18
|
+
const { boolean } = require('boolean');
|
|
19
|
+
const pkg = require('../package.json');
|
|
20
|
+
|
|
21
|
+
const silentSymbol = Symbol.for('axe.silent');
|
|
22
|
+
const omittedLoggerKeys = new Set(['config', 'log']);
|
|
23
|
+
const levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
|
|
24
|
+
const aliases = { warning: 'warn', err: 'error' };
|
|
25
|
+
const levelError = `\`level\` invalid, must be: ${levels.join(', ')}`;
|
|
26
|
+
const name =
|
|
27
|
+
process.env.NODE_ENV === 'development'
|
|
28
|
+
? false
|
|
29
|
+
: process.env.HOSTNAME || os.hostname();
|
|
30
|
+
|
|
31
|
+
// <https://github.com/sindresorhus/is-plain-obj/blob/main/index.js>
|
|
32
|
+
function isPlainObject(value) {
|
|
33
|
+
if (typeof value !== 'object' || value === null) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const prototype = Object.getPrototypeOf(value);
|
|
38
|
+
return (
|
|
39
|
+
(prototype === null ||
|
|
40
|
+
prototype === Object.prototype ||
|
|
41
|
+
Object.getPrototypeOf(prototype) === null) &&
|
|
42
|
+
!(Symbol.toStringTag in value) &&
|
|
43
|
+
!(Symbol.iterator in value) &&
|
|
44
|
+
!isSymbol(value)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// <https://github.com/GeenenTijd/dotify/blob/master/dotify.js>
|
|
49
|
+
function dotifyToArray(obj) {
|
|
50
|
+
const res = [];
|
|
51
|
+
function recurse(obj, current) {
|
|
52
|
+
for (const key of Reflect.ownKeys(obj)) {
|
|
53
|
+
const value = obj[key];
|
|
54
|
+
const convertedKey = isSymbol(key)
|
|
55
|
+
? Symbol.keyFor(key) || key.description
|
|
56
|
+
: key;
|
|
57
|
+
const newKey = current ? current + '.' + convertedKey : convertedKey; // joined key with dot
|
|
58
|
+
// if (value && typeof value === 'object' && !(value instanceof Date) && !ObjectID.isValid(value)) {
|
|
59
|
+
if (isPlainObject(value) && res.indexOf(convertedKey) === -1) {
|
|
60
|
+
res.push(convertedKey);
|
|
61
|
+
recurse(value, newKey); // it's a nested object, so do it again
|
|
62
|
+
} else if (res.indexOf(newKey) === -1) {
|
|
63
|
+
res.push(newKey);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
recurse(obj);
|
|
69
|
+
return res;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// <https://stackoverflow.com/a/43233163>
|
|
73
|
+
function isEmpty(value) {
|
|
74
|
+
return (
|
|
75
|
+
value === undefined ||
|
|
76
|
+
value === null ||
|
|
77
|
+
(typeof value === 'object' && Reflect.ownKeys(value).length === 0) ||
|
|
78
|
+
(typeof value === 'string' && value.trim().length === 0)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isNull(value) {
|
|
83
|
+
return value === null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function isUndefined(value) {
|
|
87
|
+
return value === undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isObject(value) {
|
|
91
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isString(value) {
|
|
95
|
+
return typeof value === 'string';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function isFunction(value) {
|
|
99
|
+
return typeof value === 'function';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getFunction(value) {
|
|
103
|
+
return isFunction(value) ? value : null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class Axe {
|
|
107
|
+
// eslint-disable-next-line complexity
|
|
108
|
+
constructor(config = {}) {
|
|
109
|
+
const remappedFields = {};
|
|
110
|
+
if (process.env.AXE_REMAPPED_META_FIELDS) {
|
|
111
|
+
const fields = process.env.AXE_REMAPPED_META_FIELDS;
|
|
112
|
+
const arr = fields.split(',').map((v) => v.split(':'));
|
|
113
|
+
for (const [prop, value] of arr) {
|
|
114
|
+
remappedFields[prop] = value;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// envify does not support conditionals well enough so we declare vars outside
|
|
119
|
+
let omittedFields = process.env.AXE_OMIT_META_FIELDS;
|
|
120
|
+
if (typeof omittedFields === 'string')
|
|
121
|
+
omittedFields = omittedFields.split(',').map((s) => s.trim());
|
|
122
|
+
if (!Array.isArray(omittedFields)) omittedFields = [];
|
|
123
|
+
|
|
124
|
+
let pickedFields = process.env.AXE_PICK_META_FIELDS;
|
|
125
|
+
if (typeof pickedFields === 'string')
|
|
126
|
+
pickedFields = pickedFields.split(',').map((s) => s.trim());
|
|
127
|
+
if (!Array.isArray(pickedFields)) pickedFields = [];
|
|
128
|
+
|
|
129
|
+
this.config = mergeOptions(
|
|
130
|
+
{
|
|
131
|
+
showStack: process.env.AXE_SHOW_STACK
|
|
132
|
+
? boolean(process.env.AXE_SHOW_STACK)
|
|
133
|
+
: true,
|
|
134
|
+
meta: Object.assign(
|
|
135
|
+
{
|
|
136
|
+
show: process.env.AXE_SHOW_META
|
|
137
|
+
? boolean(process.env.AXE_SHOW_META)
|
|
138
|
+
: true,
|
|
139
|
+
remappedFields,
|
|
140
|
+
omittedFields,
|
|
141
|
+
pickedFields,
|
|
142
|
+
cleanupRemapping: true,
|
|
143
|
+
hideHTTP: 'is_http',
|
|
144
|
+
// implemented mainly for @ladjs/graceful to
|
|
145
|
+
// suppress unnecessary meta output to console
|
|
146
|
+
hideMeta: 'hide_meta'
|
|
147
|
+
},
|
|
148
|
+
typeof config.meta === 'object' ? config.meta : {}
|
|
149
|
+
),
|
|
150
|
+
version: pkg.version,
|
|
151
|
+
silent: false,
|
|
152
|
+
logger: console,
|
|
153
|
+
name,
|
|
154
|
+
level: 'info',
|
|
155
|
+
levels: ['info', 'warn', 'error', 'fatal'],
|
|
156
|
+
appInfo: process.env.AXE_APP_INFO
|
|
157
|
+
? boolean(process.env.AXE_APP_INFO)
|
|
158
|
+
: true,
|
|
159
|
+
hooks: Object.assign(
|
|
160
|
+
{
|
|
161
|
+
pre: [],
|
|
162
|
+
post: []
|
|
163
|
+
},
|
|
164
|
+
typeof config.hooks === 'object' ? config.hooks : {}
|
|
165
|
+
)
|
|
166
|
+
},
|
|
167
|
+
config
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
this.appInfo = this.config.appInfo
|
|
171
|
+
? isFunction(parseAppInfo)
|
|
172
|
+
? parseAppInfo()
|
|
173
|
+
: false
|
|
174
|
+
: false;
|
|
175
|
+
|
|
176
|
+
this.log = this.log.bind(this);
|
|
177
|
+
|
|
178
|
+
// Inherit methods from parent logger
|
|
179
|
+
const methods = Object.keys(this.config.logger).filter(
|
|
180
|
+
(key) => !omittedLoggerKeys.has(key)
|
|
181
|
+
);
|
|
182
|
+
for (const element of methods) {
|
|
183
|
+
this[element] = this.config.logger[element];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Bind helper functions for each log level
|
|
187
|
+
for (const element of levels) {
|
|
188
|
+
// Ensure function exists in logger passed
|
|
189
|
+
if (element === 'fatal') {
|
|
190
|
+
this.config.logger.fatal =
|
|
191
|
+
getFunction(this.config.logger[element]) ||
|
|
192
|
+
getFunction(this.config.logger.error) ||
|
|
193
|
+
getFunction(this.config.logger.info) ||
|
|
194
|
+
getFunction(this.config.logger.log);
|
|
195
|
+
} else {
|
|
196
|
+
this.config.logger[element] =
|
|
197
|
+
getFunction(this.config.logger[element]) ||
|
|
198
|
+
getFunction(this.config.logger.info) ||
|
|
199
|
+
getFunction(this.config.logger.log);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!isFunction(this.config.logger[element])) {
|
|
203
|
+
throw new Error(`\`${element}\` must be a function on the logger.`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Bind log handler which normalizes args and populates meta
|
|
207
|
+
this[element] = (...args) =>
|
|
208
|
+
this.log(element, ...Array.prototype.slice.call(args));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.setLevel = this.setLevel.bind(this);
|
|
212
|
+
this.getNormalizedLevel = this.getNormalizedLevel.bind(this);
|
|
213
|
+
this.setName = this.setName.bind(this);
|
|
214
|
+
|
|
215
|
+
// Set the logger name
|
|
216
|
+
if (this.config.name) this.setName(this.config.name);
|
|
217
|
+
|
|
218
|
+
// Set the logger level
|
|
219
|
+
this.setLevel(this.config.level);
|
|
220
|
+
|
|
221
|
+
// Aliases
|
|
222
|
+
this.err = this.error;
|
|
223
|
+
this.warning = this.warn;
|
|
224
|
+
|
|
225
|
+
// Pre and Post Hooks
|
|
226
|
+
this.pre = function (level, fn) {
|
|
227
|
+
this.config.hooks.pre.push(function (_level, ...args) {
|
|
228
|
+
if (level !== _level) return [...args];
|
|
229
|
+
return fn(...args);
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
this.post = function (level, fn) {
|
|
234
|
+
this.config.hooks.post.push(function (_level, ...args) {
|
|
235
|
+
if (level !== _level) return [...args];
|
|
236
|
+
return fn(...args);
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
setLevel(level) {
|
|
242
|
+
if (!isString(level) || levels.indexOf(level) === -1)
|
|
243
|
+
throw new Error(levelError);
|
|
244
|
+
// Support signale logger and other loggers that use `logLevel`
|
|
245
|
+
if (isString(this.config.logger.logLevel))
|
|
246
|
+
this.config.logger.logLevel = level;
|
|
247
|
+
else this.config.logger.level = level;
|
|
248
|
+
// Adjusts `this.config.levels` array
|
|
249
|
+
// so that it has all proceeding (inclusive)
|
|
250
|
+
this.config.levels = levels.slice(levels.indexOf(level));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
getNormalizedLevel(level) {
|
|
254
|
+
if (!isString(level)) return 'info';
|
|
255
|
+
if (isString(aliases[level])) return aliases[level];
|
|
256
|
+
if (levels.indexOf(level) === -1) return 'info';
|
|
257
|
+
return level;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
setName(name) {
|
|
261
|
+
if (!isString(name)) throw new Error('`name` must be a String');
|
|
262
|
+
// Support signale logger and other loggers that use `scope`
|
|
263
|
+
if (isString(this.config.logger.scope)) this.config.logger.scope = name;
|
|
264
|
+
else this.config.logger.name = name;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// eslint-disable-next-line complexity
|
|
268
|
+
log(level, message, meta, ...args) {
|
|
269
|
+
const originalArgs = [];
|
|
270
|
+
const errors = [];
|
|
271
|
+
let hasMessage = false;
|
|
272
|
+
let hasLevel = true;
|
|
273
|
+
|
|
274
|
+
if (!isUndefined(level)) originalArgs.push(level);
|
|
275
|
+
if (!isUndefined(message)) originalArgs.push(message);
|
|
276
|
+
if (!isUndefined(meta)) originalArgs.push(meta);
|
|
277
|
+
for (const arg of Array.prototype.slice.call(args)) {
|
|
278
|
+
originalArgs.push(arg);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
let modifier = 0;
|
|
282
|
+
|
|
283
|
+
if (isString(level) && isString(aliases[level])) {
|
|
284
|
+
level = aliases[level];
|
|
285
|
+
} else if (isError(level)) {
|
|
286
|
+
hasLevel = false;
|
|
287
|
+
meta = message;
|
|
288
|
+
message = level;
|
|
289
|
+
level = 'error';
|
|
290
|
+
} else if (!isString(level) || levels.indexOf(level) === -1) {
|
|
291
|
+
hasLevel = false;
|
|
292
|
+
meta = message;
|
|
293
|
+
message = level;
|
|
294
|
+
level = this.getNormalizedLevel(level);
|
|
295
|
+
modifier = -1;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Return early if it is not a valid logging level
|
|
299
|
+
if (this.config.levels.indexOf(level) === -1) return;
|
|
300
|
+
|
|
301
|
+
// Bunyan support (meta, message, ...args)
|
|
302
|
+
let isBunyan = false;
|
|
303
|
+
if ((isObject(message) || Array.isArray(message)) && isString(meta)) {
|
|
304
|
+
isBunyan = true;
|
|
305
|
+
const _meta = meta;
|
|
306
|
+
meta = message;
|
|
307
|
+
message =
|
|
308
|
+
isString(_meta) && originalArgs.length >= 3 + modifier
|
|
309
|
+
? format(...originalArgs.slice(2 + modifier))
|
|
310
|
+
: _meta;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// If message was undefined then set it to level
|
|
314
|
+
if (isUndefined(message)) message = level;
|
|
315
|
+
|
|
316
|
+
// If only `message` was passed then if it was an Object
|
|
317
|
+
// preserve it as an Object by setting it as meta
|
|
318
|
+
if (
|
|
319
|
+
originalArgs.slice(1 + modifier).length === 1 &&
|
|
320
|
+
!isString(message) &&
|
|
321
|
+
!isError(message)
|
|
322
|
+
) {
|
|
323
|
+
meta = { message };
|
|
324
|
+
message = level;
|
|
325
|
+
} else if (!isBunyan && originalArgs.length >= 4 + modifier) {
|
|
326
|
+
message = undefined;
|
|
327
|
+
meta = {};
|
|
328
|
+
const messages = [];
|
|
329
|
+
for (const arg of originalArgs.slice(
|
|
330
|
+
hasLevel && modifier === 0 ? 1 : 0
|
|
331
|
+
)) {
|
|
332
|
+
if (isError(arg)) errors.push(arg);
|
|
333
|
+
// pushes number, object, string, etc for formatting
|
|
334
|
+
else messages.push(arg);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (messages.length > 0) {
|
|
338
|
+
message = format(...messages);
|
|
339
|
+
hasMessage = true;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (errors.length > 0 && level === 'log') level = 'error';
|
|
343
|
+
} else if (
|
|
344
|
+
!isBunyan &&
|
|
345
|
+
originalArgs.length === 3 + modifier &&
|
|
346
|
+
isString(message) &&
|
|
347
|
+
formatSpecifiers.some((t) => message.indexOf(t) !== -1)
|
|
348
|
+
) {
|
|
349
|
+
// Otherwise if there are three args and if the `message` contains
|
|
350
|
+
// a placeholder token (e.g. '%s' or '%d' - see above `formatSpecifiers` variable)
|
|
351
|
+
// then we can infer that the `meta` arg passed is used for formatting
|
|
352
|
+
message = format(message, meta);
|
|
353
|
+
meta = {};
|
|
354
|
+
} else if (!isError(message)) {
|
|
355
|
+
if (isError(meta)) {
|
|
356
|
+
errors.push(meta);
|
|
357
|
+
meta = {};
|
|
358
|
+
} else if (!isObject(meta) && !isUndefined(meta) && !isNull(meta)) {
|
|
359
|
+
// If the `meta` variable passed was not an Object then convert it
|
|
360
|
+
message = format(message, meta);
|
|
361
|
+
meta = {};
|
|
362
|
+
} else if (!isString(message)) {
|
|
363
|
+
// If the message is not a string then we should run `util.format` on it
|
|
364
|
+
// assuming we're formatting it like it was another argument
|
|
365
|
+
// (as opposed to using something like fast-json-stringify)
|
|
366
|
+
message = format(message);
|
|
367
|
+
}
|
|
368
|
+
} else if (isError(meta)) {
|
|
369
|
+
errors.push(meta);
|
|
370
|
+
// handle additional args
|
|
371
|
+
const messages = [];
|
|
372
|
+
if (isError(message)) {
|
|
373
|
+
errors.unshift(message);
|
|
374
|
+
message = undefined;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
for (const arg of originalArgs.slice(2 + modifier)) {
|
|
378
|
+
// should skip this better with slice and modifier adjustment
|
|
379
|
+
if (meta === arg) continue;
|
|
380
|
+
if (isError(arg)) errors.push(arg);
|
|
381
|
+
else messages.push(arg);
|
|
382
|
+
|
|
383
|
+
if (messages.length > 0) {
|
|
384
|
+
message = format(...messages);
|
|
385
|
+
hasMessage = true;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (level === 'log') level = 'error';
|
|
390
|
+
|
|
391
|
+
meta = {};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (!isUndefined(meta) && !isObject(meta)) meta = { original_meta: meta };
|
|
395
|
+
else if (!isObject(meta)) meta = {};
|
|
396
|
+
|
|
397
|
+
if (isError(message)) {
|
|
398
|
+
errors.unshift(message);
|
|
399
|
+
message = undefined;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
//
|
|
403
|
+
// rewrite `meta.err` to `meta.original_err` for consistency
|
|
404
|
+
// (in case someone has an object with `.err` property on it with an error)
|
|
405
|
+
//
|
|
406
|
+
if (isObject(meta.err)) {
|
|
407
|
+
if (isError(meta.err)) errors.push(meta.err);
|
|
408
|
+
meta.original_err = isError(meta.err) ? parseErr(meta.err) : meta.err;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
let err;
|
|
412
|
+
if (errors.length > 0) {
|
|
413
|
+
if (errors.length === 1) {
|
|
414
|
+
err = errors[0];
|
|
415
|
+
} else {
|
|
416
|
+
err = new Error(
|
|
417
|
+
[...new Set(errors.map((e) => e.message).filter(Boolean))].join('; ')
|
|
418
|
+
);
|
|
419
|
+
err.stack = [
|
|
420
|
+
...new Set(errors.map((e) => e.stack).filter(Boolean))
|
|
421
|
+
].join('\n\n');
|
|
422
|
+
err.errors = errors;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
meta.err = parseErr(err);
|
|
426
|
+
if (!isString(message)) message = err.message;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
//
|
|
430
|
+
// NOTE: this was removed in v10.2.2 due to circular reference issues
|
|
431
|
+
// (the workaround would involve safeStringify and then JSON.parse which would be perf bloat)
|
|
432
|
+
// (there still might be another workaround or perhaps we don't add all the args here except additional)
|
|
433
|
+
//
|
|
434
|
+
// Set `args` prop with original arguments passed
|
|
435
|
+
// meta.args = originalArgs;
|
|
436
|
+
|
|
437
|
+
// Set default level on meta
|
|
438
|
+
meta.level = level;
|
|
439
|
+
|
|
440
|
+
// Add `app` object to metadata
|
|
441
|
+
if (this.appInfo) meta.app = this.appInfo;
|
|
442
|
+
|
|
443
|
+
//
|
|
444
|
+
// determine log method to use
|
|
445
|
+
//
|
|
446
|
+
// if we didn't pass a level as a method
|
|
447
|
+
// (e.g. console.info), then we should still
|
|
448
|
+
// use the logger's `log` method to output
|
|
449
|
+
//
|
|
450
|
+
// and fatal should use error (e.g. in browser)
|
|
451
|
+
//
|
|
452
|
+
const method = modifier === -1 ? 'log' : level;
|
|
453
|
+
|
|
454
|
+
// pre-hooks
|
|
455
|
+
for (const hook of this.config.hooks.pre) {
|
|
456
|
+
[err, message, meta] = hook(method, err, message, meta);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
//
|
|
460
|
+
// NOTE: using lodash _.omit and _.pick would have been _very slow_
|
|
461
|
+
//
|
|
462
|
+
// const omittedAndPickedFields = {
|
|
463
|
+
// ..._.omit(meta, this.config.meta.omittedFields),
|
|
464
|
+
// ..._.pick(meta, this.config.meta.pickedFields)
|
|
465
|
+
// };
|
|
466
|
+
//
|
|
467
|
+
// also we don't want to mutate anything in `meta`
|
|
468
|
+
// and ideally we only want to pick exactly what we need
|
|
469
|
+
// (and not have two operations, one for omit, and one for pick)
|
|
470
|
+
//
|
|
471
|
+
|
|
472
|
+
// set a boolean flag if we had the silent symbol or not
|
|
473
|
+
const hadTrueSilentSymbol = boolean(meta[silentSymbol]);
|
|
474
|
+
|
|
475
|
+
if (!isEmpty(this.config.meta.remappedFields)) {
|
|
476
|
+
for (const key of Reflect.ownKeys(this.config.meta.remappedFields)) {
|
|
477
|
+
set(meta, this.config.meta.remappedFields[key], get(meta, key));
|
|
478
|
+
unset(meta, key);
|
|
479
|
+
// cleanup empty objects after remapping
|
|
480
|
+
if (this.config.meta.cleanupRemapping) {
|
|
481
|
+
const index = key.lastIndexOf('.');
|
|
482
|
+
if (index === -1) continue;
|
|
483
|
+
const parentKey = key.slice(0, index);
|
|
484
|
+
if (isEmpty(get(meta, parentKey))) unset(meta, parentKey);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (
|
|
490
|
+
!isEmpty(this.config.meta.omittedFields) ||
|
|
491
|
+
!isEmpty(this.config.meta.pickedFields)
|
|
492
|
+
) {
|
|
493
|
+
const dotified = dotifyToArray(meta);
|
|
494
|
+
// dotified = [
|
|
495
|
+
// 'err.name',
|
|
496
|
+
// 'err.message',
|
|
497
|
+
// 'err.stack',
|
|
498
|
+
// 'level',
|
|
499
|
+
// 'app.name',
|
|
500
|
+
// 'app.version',
|
|
501
|
+
// 'app.node',
|
|
502
|
+
// 'app.hash',
|
|
503
|
+
// // ...
|
|
504
|
+
// ]
|
|
505
|
+
|
|
506
|
+
if (!isEmpty(this.config.meta.omittedFields)) {
|
|
507
|
+
for (const prop of this.config.meta.omittedFields) {
|
|
508
|
+
// <https://stackoverflow.com/a/9882349>
|
|
509
|
+
let i = dotified.length;
|
|
510
|
+
while (i--) {
|
|
511
|
+
if (
|
|
512
|
+
dotified[i] === prop ||
|
|
513
|
+
(!isSymbol(dotified[i]) && dotified[i].indexOf(`${prop}.`) === 0)
|
|
514
|
+
)
|
|
515
|
+
dotified.splice(i, 1);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const pickedSymbols = [];
|
|
521
|
+
|
|
522
|
+
if (!isEmpty(this.config.meta.pickedFields)) {
|
|
523
|
+
for (const prop of this.config.meta.pickedFields) {
|
|
524
|
+
// response.headers.boop
|
|
525
|
+
// response.headers.beep
|
|
526
|
+
// response.body
|
|
527
|
+
// response.text
|
|
528
|
+
// response
|
|
529
|
+
//
|
|
530
|
+
// so we need to split by the first period and omit any keys from dotified starting with it
|
|
531
|
+
if (isSymbol(prop)) {
|
|
532
|
+
if (meta[prop]) pickedSymbols.push([prop, meta[prop]]);
|
|
533
|
+
} else {
|
|
534
|
+
const index = prop.indexOf('.');
|
|
535
|
+
const key = prop.slice(0, index + 1);
|
|
536
|
+
if (index !== -1) {
|
|
537
|
+
let i = dotified.length;
|
|
538
|
+
while (i--) {
|
|
539
|
+
if (dotified[i] === key.slice(0, -1)) dotified.splice(i, 1);
|
|
540
|
+
else if (dotified[i].indexOf(key) === 0) dotified.splice(i, 1);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// finally add it if it did not already exist
|
|
546
|
+
if (dotified.indexOf(prop) === -1) dotified.push(prop);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
//
|
|
551
|
+
// iterate over all dotified values to check for symbols
|
|
552
|
+
//
|
|
553
|
+
// NOTE: this does not take into account that they could already be in `pickedSymbols`
|
|
554
|
+
// (and it doesn't also do bigints yet)
|
|
555
|
+
//
|
|
556
|
+
for (const prop of dotified) {
|
|
557
|
+
if (isSymbol(prop)) {
|
|
558
|
+
if (meta[prop] !== undefined) pickedSymbols.push([prop, meta[prop]]);
|
|
559
|
+
} else if (meta[Symbol.for(prop)] !== undefined) {
|
|
560
|
+
pickedSymbols.push([Symbol.for(prop), meta[Symbol.for(prop)]]);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
//
|
|
565
|
+
// now we call pick-deep using the final array
|
|
566
|
+
//
|
|
567
|
+
// NOTE: this does not pick symbols, bigints, nor streams
|
|
568
|
+
// <https://github.com/strikeentco/pick-deep/issues/2>
|
|
569
|
+
// <https://github.com/strikeentco/pick-deep/issues/2>
|
|
570
|
+
//
|
|
571
|
+
// NOTE: this is wrapped in try/catch in case similar errors occur
|
|
572
|
+
// <https://github.com/stripe/stripe-node/issues/1796>
|
|
573
|
+
//
|
|
574
|
+
try {
|
|
575
|
+
meta = pickDeep(meta, dotified);
|
|
576
|
+
} catch (err) {
|
|
577
|
+
this.config.logger.error(err);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
//
|
|
581
|
+
// if there were any top-level symbols to be
|
|
582
|
+
// picked then we need to add them back here to the list
|
|
583
|
+
//
|
|
584
|
+
// NOTE: we'd probably want to do the same for bigints as symbols
|
|
585
|
+
//
|
|
586
|
+
if (pickedSymbols.length > 0) {
|
|
587
|
+
for (const [key, value] of pickedSymbols) {
|
|
588
|
+
meta[key] = value;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// only invoke logger methods if it was not silent
|
|
594
|
+
if (!this.config.silent && !hadTrueSilentSymbol) {
|
|
595
|
+
// Show stack trace if necessary (along with any metadata)
|
|
596
|
+
if (isError(err) && this.config.showStack) {
|
|
597
|
+
if (!this.config.meta.show || isEmpty(meta)) {
|
|
598
|
+
this.config.logger[method](...(hasMessage ? [message, err] : [err]));
|
|
599
|
+
} else if (
|
|
600
|
+
this.config.meta.hideMeta &&
|
|
601
|
+
meta[this.config.meta.hideMeta]
|
|
602
|
+
) {
|
|
603
|
+
this.config.logger[method](...(hasMessage ? [message, err] : [err]));
|
|
604
|
+
} else {
|
|
605
|
+
this.config.logger[method](
|
|
606
|
+
...(hasMessage ? [message, err, meta] : [err, meta])
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
} else if (!this.config.meta.show || isEmpty(meta)) {
|
|
610
|
+
this.config.logger[method](message);
|
|
611
|
+
} else if (
|
|
612
|
+
(this.config.meta.hideMeta && meta[this.config.meta.hideMeta]) ||
|
|
613
|
+
(this.config.meta.hideHTTP && meta[this.config.meta.hideHTTP])
|
|
614
|
+
) {
|
|
615
|
+
this.config.logger[method](message);
|
|
616
|
+
} else {
|
|
617
|
+
this.config.logger[method](message, meta);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// post-hooks
|
|
622
|
+
if (this.config.hooks.post.length === 0)
|
|
623
|
+
return { method, err, message, meta };
|
|
624
|
+
return pMapSeries(this.config.hooks.post, (hook) =>
|
|
625
|
+
hook(method, err, message, meta)
|
|
626
|
+
)
|
|
627
|
+
.then()
|
|
628
|
+
.catch((err) => {
|
|
629
|
+
this.config.logger.error(err);
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
module.exports = Axe;
|