-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutError.js
108 lines (104 loc) · 4.3 KB
/
utError.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
const typeRegex = /^[a-z]\w*(\.!?\w+)*$/;
const paramsRegex = /\{([^}]*)\}/g;
const interpolate = (regExp => (msg, params = {}) => {
return msg.replace(regExp, (placeholder, label) => {
return typeof params[label] === 'undefined' ? `?${label}?` : params[label];
});
})(paramsRegex);
const getWarnHandler = ({logFactory, logLevel}) => {
if (logFactory) {
const log = logFactory.createLog(logLevel, {name: 'utError', context: 'utError'});
if (log.warn) {
return (msg, context) => {
const e = new Error();
log.warn(msg, {
$meta: {
mtid: 'deprecation',
method: context.method
},
args: context.args,
error: {
type: 'utError.deprecation',
stack: e.stack.split('\n').splice(3).join('\n')
}
});
};
}
}
return () => {};
};
module.exports = ({logFactory, logLevel, errorPrint}) => {
const warn = getWarnHandler({logFactory, logLevel});
const errors = {};
const api = {
get(type) {
return type ? errors[type] : errors;
},
fetch(type) {
const result = {};
Object.keys(errors).forEach(key => {
if (key.startsWith(type)) {
result[key] = errors[key];
}
});
return result;
},
define(id, superType, message) {
const type = [
superType
? typeof superType === 'string'
? superType
: superType.type
: null,
id
].filter(x => x).join('.');
return api.register({[type]: message})[type];
},
register(errorsMap) {
const result = {};
Object.entries(errorsMap).forEach(([type, message]) => {
if (!typeRegex.test(type)) {
warn(`Invalid error type format: '${type}'!`, {
args: {type, expectedFormat: typeRegex.toString()},
method: 'utError.register'
});
}
const props = typeof message === 'string'
? {message}
: Array.isArray(message)
? {message: message[0], print: message[1]}
: message;
if (!props.message) throw new Error(`Missing message for error '${type}'`);
if (errors[type]) {
if (errors[type].message !== props.message) {
throw new Error(`Error '${type}' is already defined with different message!`);
}
result[type] = errors[type];
return;
}
if (!props.print && errorPrint) props.print = typeof errorPrint === 'string' ? errorPrint : props.message;
const handler = (params = {}, $meta) => {
const error = new Error();
if (params instanceof Error) {
error.cause = params;
} else {
Object.assign(error, params);
}
Object.assign(error, props);
Object.defineProperty(error, 'name', {value: type, configurable: true, enumerable: false});
error.type = type;
if (props.print) error.print = props.print;
error.message = interpolate(props.message, params.params);
return $meta ? [error] : error; // to do - fix once bus.register allows to configure unpack
};
handler.type = type;
handler.message = props.message;
if (props.print) handler.print = props.print;
handler.params = handler.message.match(paramsRegex)?.map(param => param.replace('{', '').replace('}', ''));
result[type] = errors[type] = handler;
});
return result;
}
};
return api;
};