topkat-utils 1.0.60 → 1.1.2

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.
Files changed (102) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.d.ts +34 -0
  3. package/dist/index.js +56 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/src/array-utils.d.ts +56 -0
  6. package/dist/src/array-utils.js +138 -0
  7. package/dist/src/array-utils.js.map +1 -0
  8. package/dist/src/date-utils.d.ts +100 -0
  9. package/dist/src/date-utils.js +357 -0
  10. package/dist/src/date-utils.js.map +1 -0
  11. package/dist/src/env-utils.d.ts +8 -0
  12. package/dist/src/env-utils.js +38 -0
  13. package/dist/src/env-utils.js.map +1 -0
  14. package/dist/src/error-utils.d.ts +8 -0
  15. package/dist/src/error-utils.js +99 -0
  16. package/dist/src/error-utils.js.map +1 -0
  17. package/dist/src/is-empty.d.ts +1 -0
  18. package/dist/src/is-empty.js +13 -0
  19. package/dist/src/is-empty.js.map +1 -0
  20. package/dist/src/is-object.d.ts +2 -0
  21. package/dist/src/is-object.js +7 -0
  22. package/dist/src/is-object.js.map +1 -0
  23. package/dist/src/isset.d.ts +1 -0
  24. package/dist/src/isset.js +8 -0
  25. package/dist/src/isset.js.map +1 -0
  26. package/dist/src/logger-utils.d.ts +76 -0
  27. package/dist/src/logger-utils.js +355 -0
  28. package/dist/src/logger-utils.js.map +1 -0
  29. package/dist/src/loop-utils.d.ts +37 -0
  30. package/dist/src/loop-utils.js +105 -0
  31. package/dist/src/loop-utils.js.map +1 -0
  32. package/dist/src/math-utils.d.ts +23 -0
  33. package/dist/src/math-utils.js +43 -0
  34. package/dist/src/math-utils.js.map +1 -0
  35. package/dist/src/mongo-utils.d.ts +11 -0
  36. package/dist/src/mongo-utils.js +49 -0
  37. package/dist/src/mongo-utils.js.map +1 -0
  38. package/dist/src/object-utils.d.ts +96 -0
  39. package/dist/src/object-utils.js +369 -0
  40. package/dist/src/object-utils.js.map +1 -0
  41. package/dist/src/private/config.d.ts +44 -0
  42. package/dist/src/private/config.js +55 -0
  43. package/dist/src/private/config.js.map +1 -0
  44. package/dist/src/private/error-handler.d.ts +10 -0
  45. package/dist/src/private/error-handler.js +18 -0
  46. package/dist/src/private/error-handler.js.map +1 -0
  47. package/dist/src/private/types.d.ts +4 -0
  48. package/dist/src/private/types.js +3 -0
  49. package/dist/src/private/types.js.map +1 -0
  50. package/dist/src/regexp-utils.d.ts +12 -0
  51. package/dist/src/regexp-utils.js +44 -0
  52. package/dist/src/regexp-utils.js.map +1 -0
  53. package/dist/src/remove-circular-json-stringify.d.ts +1 -0
  54. package/dist/src/remove-circular-json-stringify.js +20 -0
  55. package/dist/src/remove-circular-json-stringify.js.map +1 -0
  56. package/dist/src/string-utils.d.ts +77 -0
  57. package/dist/src/string-utils.js +209 -0
  58. package/dist/src/string-utils.js.map +1 -0
  59. package/dist/src/tests-utils.js +77 -0
  60. package/dist/src/tests-utils.js.map +1 -0
  61. package/dist/src/timer-utils.d.ts +16 -0
  62. package/dist/src/timer-utils.js +79 -0
  63. package/dist/src/timer-utils.js.map +1 -0
  64. package/dist/src/transaction-utils.d.ts +14 -0
  65. package/dist/src/transaction-utils.js +87 -0
  66. package/dist/src/transaction-utils.js.map +1 -0
  67. package/dist/src/validation-utils.d.ts +89 -0
  68. package/dist/src/validation-utils.js +192 -0
  69. package/dist/src/validation-utils.js.map +1 -0
  70. package/dist/src/wtf-utils.d.ts +7 -0
  71. package/dist/src/wtf-utils.js +83 -0
  72. package/dist/src/wtf-utils.js.map +1 -0
  73. package/index.ts +38 -0
  74. package/package.json +2 -2
  75. package/src/array-utils.ts +128 -0
  76. package/src/date-utils.ts +377 -0
  77. package/src/env-utils.ts +29 -0
  78. package/src/error-utils.ts +77 -0
  79. package/src/is-empty.ts +5 -0
  80. package/src/is-object.ts +3 -0
  81. package/src/isset.ts +3 -0
  82. package/src/logger-utils.ts +349 -0
  83. package/src/loop-utils.ts +101 -0
  84. package/src/math-utils.ts +38 -0
  85. package/src/mongo-utils.ts +38 -0
  86. package/src/object-utils.ts +356 -0
  87. package/src/private/config.ts +85 -0
  88. package/src/private/error-handler.ts +21 -0
  89. package/src/private/types.ts +6 -0
  90. package/src/regexp-utils.ts +37 -0
  91. package/src/remove-circular-json-stringify.ts +17 -0
  92. package/src/string-utils.ts +212 -0
  93. package/src/tests-utils.ts +70 -0
  94. package/src/timer-utils.ts +58 -0
  95. package/src/transaction-utils.ts +63 -0
  96. package/src/validation-utils.ts +253 -0
  97. package/src/wtf-utils.ts +88 -0
  98. package/tsconfig.json +11 -4
  99. package/utils.d.ts +0 -694
  100. package/utils.js +0 -2227
  101. package/utils.js.map +0 -1
  102. package/utils.ts +0 -2304
@@ -0,0 +1,356 @@
1
+ //----------------------------------------
2
+ // OBJECT UTILS
3
+ //----------------------------------------
4
+ import { ObjectGeneric } from "./private/types"
5
+ import { err500IfNotSet } from "./error-utils"
6
+ import { recursiveGenericFunctionSync } from "./loop-utils"
7
+ import { isset } from "./isset"
8
+ import { isObject } from "./is-object"
9
+ import { dataValidationUtilErrorHandler } from "./private/error-handler"
10
+
11
+ /**
12
+ *
13
+ * @param {Object} object main object
14
+ * @param {String[]} maskedOrSelectedFields array of fields
15
+ * @param {Boolean} isMask default: true; determine the behavior of the function. If is mask, selected fields will not appear in the resulting object. If it's a select, only selected fields will appear.
16
+ * @param {Boolean} deleteKeysInsteadOfReturningAnewObject default:false; modify the existing object instead of creating a new instance
17
+ */
18
+ export function simpleObjectMaskOrSelect(object: ObjectGeneric, maskedOrSelectedFields: string[], isMask = true, deleteKeysInsteadOfReturningAnewObject = false) {
19
+ const allKeys = Object.keys(object)
20
+ const keysToMask = allKeys.filter(keyName => {
21
+ if (isMask) return maskedOrSelectedFields.includes(keyName)
22
+ else return !maskedOrSelectedFields.includes(keyName)
23
+ })
24
+ if (deleteKeysInsteadOfReturningAnewObject) {
25
+ keysToMask.forEach(keyNameToDelete => delete object[keyNameToDelete])
26
+ return object
27
+ } else {
28
+ return allKeys.reduce((newObject, key) => {
29
+ if (!keysToMask.includes(key)) newObject[key] = object[key]
30
+ return newObject
31
+ }, {})
32
+ }
33
+ }
34
+
35
+ /**
36
+ * check if **object OR array** has property Safely (avoid cannot read property x of null and such)
37
+ * @param {Object} obj object to test against
38
+ * @param {string} addr `a.b.c.0.1` will test if myObject has props a that has prop b. Work wit arrays as well (like `arr.0`)
39
+ */
40
+ export function has(obj: ObjectGeneric, addr: string) {
41
+ if (!isset(obj) || typeof obj !== 'object') return
42
+ let propsArr = addr.replace(/\.?\[(\d+)\]/g, '.$1').split('.') // replace a[3] => a.3;
43
+ let objChain = obj
44
+ return propsArr.every(prop => {
45
+ objChain = objChain[prop]
46
+ return isset(objChain)
47
+ })
48
+ }
49
+
50
+ /** Find address in an object "a.b.c" IN { a : { b : {c : 'blah' }}} RETURNS 'blah'
51
+ * @param obj
52
+ * @param addr accept syntax like "obj.subItem.[0].sub2" OR "obj.subItem.0.sub2" OR "obj.subItem[0].sub2"
53
+ * @returns the last item of the chain OR undefined if not found
54
+ */
55
+ export function findByAddress(obj: ObjectGeneric, addr: string): any | undefined {
56
+ if (addr === '') return obj
57
+ if (!isset(obj) || typeof obj !== 'object') return console.warn('Main object in `findByAddress` function is undefined or has the wrong type')
58
+ const propsArr = addr.replace(/\.?\[(\d+)\]/g, '.$1').split('.') // replace .[4] AND [4] TO .4
59
+ const objRef = propsArr.reduce((objChain, prop) => {
60
+ if (!isset(objChain) || typeof objChain !== 'object' || !isset(objChain[prop])) return
61
+ else return objChain[prop]
62
+ }, obj)
63
+ return objRef
64
+ }
65
+
66
+
67
+ /** Will return all objects matching that path. Eg: user.*.myVar */
68
+ export function findByAddressAll(obj, addr, returnAddresses?: true): Array<[string, any]>
69
+ export function findByAddressAll(obj, addr, returnAddresses?: false): Array<any>
70
+ export function findByAddressAll(obj, addr, returnAddresses = false) {
71
+ err500IfNotSet({ obj, addr })
72
+ if (addr === '') return obj
73
+ const addrRegexp = new RegExp('^' + addr
74
+ .replace(/\.?\[(\d+)\]/g, '.$1') // replace .[4] AND [4] TO .4
75
+ .replace(/\./g, '\\.')
76
+ .replace(/\.\*/g, '.[^.]+') // replace * by [^. (all but a point)]
77
+ + '$')
78
+
79
+ const matchingItems = []
80
+
81
+ recursiveGenericFunctionSync(obj, (item, address) => {
82
+ if (addrRegexp.test(address)) matchingItems.push(returnAddresses ? [address, item] : item)
83
+ })
84
+ return matchingItems
85
+ }
86
+
87
+ /** Enforce writing subItems. Eg: user.name.blah will ensure all are set until the writing of the last item
88
+ * NOTE: doesn't work with arrays
89
+ */
90
+ export function objForceWrite(obj: ObjectGeneric, addr: string, item) {
91
+ const chunks = addr.replace(/\.?\[(\d+)\]/g, '.[$1').split('.')
92
+ let lastItem = obj
93
+ chunks.forEach((chunkRaw, i) => {
94
+ const chunk = chunkRaw.replace(/^\[/, '')
95
+ if (i === chunks.length - 1) lastItem[chunk] = item
96
+ else if (!isset(lastItem[chunk])) {
97
+ const nextChunk = chunks[i + 1]
98
+ if (isset(nextChunk) && nextChunk.startsWith('[')) lastItem[chunk] = []
99
+ else lastItem[chunk] = {}
100
+ } else if (typeof lastItem[chunk] !== 'object') throw new dataValidationUtilErrorHandler(`itemNotTypeObjectOrArrayInAddrChainForObjForceWrite`, 500, { origin: 'Validator', chunks, actualValueOfItem: lastItem[chunk], actualChunk: chunk })
101
+ lastItem = lastItem[chunk]
102
+ })
103
+ }
104
+
105
+ /** Enforce writing subItems, only if obj.addr is empty.
106
+ * Eg: user.name.blah will ensure all are set until the writing of the last item
107
+ * if user.name.blah has a value it will not change it.
108
+ * NOTE: doesn't work with arrays
109
+ */
110
+ export function objForceWriteIfNotSet(obj: ObjectGeneric, addr: string, item) {
111
+ if (!isset(findByAddress(obj, addr))) return objForceWrite(obj, addr, item)
112
+ }
113
+
114
+ /** Merge mixins into class. Use it in the constructor like: mergeMixins(this, {myMixin: true}) */
115
+ export function mergeMixins(that, ...mixins) {
116
+ mixins.forEach(mixin => {
117
+ for (const method in mixin) {
118
+ that[method] = mixin[method]
119
+ }
120
+ })
121
+ }
122
+
123
+ export function cloneObject(o) {
124
+ return JSON.parse(JSON.stringify(o))
125
+ }
126
+
127
+ /** Deep clone. WILL REMOVE circular references */
128
+ export function deepClone<T>(obj: T, cache = []): T {
129
+
130
+ let copy
131
+ // usefull to not modify 1st level objet by lower levels
132
+ // this is required for the same object to be referenced not in a redundant way
133
+ const newCache = [...cache]
134
+ if (obj instanceof Date) return new Date(obj) as any
135
+
136
+ // Handle Array
137
+ if (Array.isArray(obj)) {
138
+ if (newCache.includes(obj)) return [] as any
139
+ newCache.push(obj)
140
+ copy = []
141
+ for (var i = 0, len = obj.length; i < len; i++) {
142
+ copy[i] = deepClone(obj[i], newCache)
143
+ }
144
+ return copy
145
+ }
146
+
147
+ if (typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === Object.prototype) {
148
+ if (newCache.includes(obj)) return {} as any
149
+ newCache.push(obj)
150
+ copy = {}
151
+ for (var key in obj) {
152
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
153
+ copy[key] = deepClone(obj[key], newCache)
154
+ }
155
+ }
156
+ return copy
157
+ }
158
+
159
+ return obj // number, string...
160
+ }
161
+
162
+
163
+ /**
164
+ * @param {Object} obj the object on which we want to filter the keys
165
+ * @param {function} filterFunc function that returns true if the key match the wanted criteria
166
+ */
167
+ export function filterKeys(obj: object, filter) {
168
+ const clone = cloneObject(obj)
169
+ recursiveGenericFunctionSync(obj, (item, addr, lastElementKey) => {
170
+ if (!filter(lastElementKey)) deleteByAddress(clone, addr.split('.'))
171
+ })
172
+ return clone
173
+ }
174
+ /**
175
+ * @param {Object} obj the object on which we want to delete a property
176
+ * @param {Array} addr addressArray on which to delete the property
177
+ */
178
+ export function deleteByAddress(obj: object, addr: string[]) {
179
+ let current = obj
180
+ for (let i = 0; i < addr.length - 2; i++) current = current[addr[i]]
181
+ delete current[addr[addr.length - 1]]
182
+ }
183
+
184
+
185
+
186
+ /** Remove all key/values pair if value is undefined */
187
+ export function objFilterUndefined(o) {
188
+ Object.keys(o).forEach(k => !isset(o[k]) && delete o[k])
189
+ return o
190
+ }
191
+
192
+ /** Lock all 1st level props of an object to read only */
193
+ export function readOnly(o) {
194
+ const throwErr = () => { throw new dataValidationUtilErrorHandler('Cannot modify object that is read only', 500) }
195
+ return new Proxy(o, {
196
+ set: throwErr,
197
+ defineProperty: throwErr,
198
+ deleteProperty: throwErr,
199
+ })
200
+ }
201
+
202
+ /** Fields of the object can be created BUT NOT reassignated */
203
+ export function reassignForbidden(o) {
204
+ return new Proxy(o, {
205
+ defineProperty: function (that, key, value) {
206
+ if (key in that) throw new dataValidationUtilErrorHandler(`Cannot reassign the property ${key.toString()} of this object`, 500)
207
+ else {
208
+ that[key] = value
209
+ return true
210
+ }
211
+ },
212
+ deleteProperty: function (_, key) {
213
+ throw new dataValidationUtilErrorHandler(`Cannot delete the property ${key.toString()} of this object`, 500)
214
+ }
215
+ })
216
+ }
217
+
218
+ /** All fileds and subFields of the object will become readOnly */
219
+ export function readOnlyForAll(object) {
220
+ recursiveGenericFunctionSync(object, (item, _, lastElementKey, parent) => {
221
+ if (typeof item === 'object') parent[lastElementKey] = readOnly(item)
222
+ })
223
+ return object
224
+ }
225
+
226
+ export function objFilterUndefinedRecursive(obj) {
227
+ if (obj) {
228
+ const flattenedObj = flattenObject(obj)
229
+ Object.keys(flattenedObj).forEach(key => {
230
+ if (!isset(flattenedObj[key])) {
231
+ delete flattenedObj[key]
232
+ }
233
+ })
234
+ return unflattenObject(flattenedObj)
235
+ } else return obj
236
+ }
237
+
238
+ export function sortObjKeyAccordingToValue(unorderedObj, ascending = true) {
239
+ const orderedObj = {}
240
+ const sortingConst = ascending ? 1 : -1
241
+ Object.keys(unorderedObj)
242
+ .sort((keyA, keyB) => unorderedObj[keyA] < unorderedObj[keyB] ? sortingConst : -sortingConst)
243
+ .forEach(key => { orderedObj[key] = unorderedObj[key] })
244
+ return orderedObj
245
+ }
246
+
247
+ /**
248
+ * Make default value if object key do not exist
249
+ * @param {object} obj
250
+ * @param {string} addr
251
+ * @param {any} defaultValue
252
+ * @param {function} callback (obj[addr]) => processValue. Eg: myObjAddr => myObjAddr.push('bikou')
253
+ * @return obj[addr] eventually processed by the callback
254
+ */
255
+ export function ensureObjectProp(obj: object, addr: string, defaultValue, callback = o => o) {
256
+ err500IfNotSet({ obj, addr, defaultValue, callback })
257
+ if (!isset(obj[addr])) obj[addr] = defaultValue
258
+ callback(obj[addr])
259
+ return obj[addr]
260
+ }
261
+
262
+
263
+ /** object and array merge
264
+ * @warn /!\ Array will be merged and duplicate values will be deleted /!\
265
+ * @return {Object} new object result from merge
266
+ * NOTE: objects in params will NOT be modified*/
267
+ export function mergeDeep(...objects) {
268
+ return mergeDeepConfigurable(
269
+ (previousVal, currentVal) => [...previousVal, ...currentVal].filter((elm, i, arr) => arr.indexOf(elm) === i),
270
+ (previousVal, currentVal) => mergeDeep(previousVal, currentVal),
271
+ undefined,
272
+ ...objects
273
+ )
274
+ }
275
+
276
+ /** object and array merge
277
+ * @warn /!\ Array will be replaced by the latest object /!\
278
+ * @return {Object} new object result from merge
279
+ * NOTE: objects in params will NOT be modified */
280
+ export function mergeDeepOverrideArrays(...objects) {
281
+ return mergeDeepConfigurable(
282
+ undefined,
283
+ (previousVal, currentVal) => mergeDeepOverrideArrays(previousVal, currentVal),
284
+ undefined,
285
+ ...objects
286
+ )
287
+ }
288
+
289
+ /** object and array merge
290
+ * @param {Function} replacerForArrays item[key] = (prevValue, currentVal) => () When 2 values are arrays,
291
+ * @param {Function} replacerForObjects item[key] = (prevValue, currentVal) => () When 2 values are objects,
292
+ * @param {Function} replacerDefault item[key] = (prevValue, currentVal) => () For all other values
293
+ * @param {...Object} objects
294
+ * @return {Object} new object result from merge
295
+ * NOTE: objects in params will NOT be modified
296
+ */
297
+ export function mergeDeepConfigurable(replacerForArrays = (prev, curr) => curr, replacerForObjects, replacerDefault = (prev, curr) => curr, ...objects) {
298
+ return objects.reduce((actuallyMerged, obj) => {
299
+ Object.keys(obj).forEach(key => {
300
+ const previousVal = actuallyMerged[key]
301
+ const currentVal = obj[key]
302
+
303
+ if (Array.isArray(previousVal) && Array.isArray(currentVal)) {
304
+ actuallyMerged[key] = replacerForArrays(previousVal, currentVal)
305
+ } else if (isObject(previousVal) && isObject(currentVal)) {
306
+ actuallyMerged[key] = replacerForObjects(previousVal, currentVal)
307
+ } else {
308
+ actuallyMerged[key] = replacerDefault(previousVal, currentVal)
309
+ }
310
+ })
311
+
312
+ return actuallyMerged
313
+ }, {})
314
+ }
315
+
316
+ /** { a: {b:2}} => {'a.b':2} useful for translations
317
+ * NOTE: will remove circular references
318
+ */
319
+ export function flattenObject(data, config: { withoutArraySyntax?: boolean, withArraySyntaxMinified?: boolean } = {}) {
320
+ const { withoutArraySyntax = false, withArraySyntaxMinified = false } = config
321
+ const result = {}
322
+ const seenObjects = [] // avoidCircular reference to infinite loop
323
+ const recurse = (cur, prop) => {
324
+ if (Array.isArray(cur)) {
325
+ let l = cur.length
326
+ let i = 0
327
+ if (withoutArraySyntax) recurse(cur[0], prop)
328
+ else {
329
+ for (; i < l; i++) recurse(cur[i], prop + (withArraySyntaxMinified ? `.${i}` : `[${i}]`))
330
+ if (l == 0) result[prop] = []
331
+ }
332
+ } else if (isObject(cur)) { // is object
333
+ try {
334
+ if (seenObjects.includes(cur)) cur = deepClone(cur) // avoid circular ref but allow duplicate objects
335
+ else seenObjects.push(cur)
336
+
337
+ const isEmpty = Object.keys(cur).length === 0
338
+
339
+ for (const p in cur) recurse(cur[p], (prop ? prop + '.' : '') + p.replace(/\./g, '%')) // allow prop to contain special chars like points);
340
+
341
+ if (isEmpty && prop) result[prop] = {}
342
+ } catch (error) {
343
+ console.warn('Circular reference in flattenObject, impossible to parse')
344
+ }
345
+ } else result[prop] = cur
346
+ }
347
+ recurse(data, '')
348
+ return result
349
+ }
350
+
351
+ /** {'a.b':2} => { a: {b:2}} */
352
+ export function unflattenObject(data) {
353
+ const newO = {}
354
+ for (const [addr, value] of Object.entries(data)) objForceWrite(newO, addr, value)
355
+ return newO
356
+ }
@@ -0,0 +1,85 @@
1
+ import { Color } from './types'
2
+ import { isset } from '../isset'
3
+
4
+ export type Config = {
5
+ env: string
6
+ isProd: boolean
7
+ nbOfLogsToKeep: number
8
+ customTypes: object,
9
+ preprocessLog?: Function,
10
+ terminal: {
11
+ noColor: boolean
12
+ theme: {
13
+ primary: Color, // blue theme
14
+ shade1: Color,
15
+ shade2: Color,
16
+ bgColor?: Color
17
+ paddingX: number
18
+ paddingY: number
19
+ fontColor?: Color
20
+ pageWidth: number
21
+ debugModeColor: Color,
22
+ }
23
+ },
24
+ }
25
+
26
+ let config: Config = {
27
+ env: 'development',
28
+ isProd: false,
29
+ nbOfLogsToKeep: 25,
30
+ customTypes: {},
31
+ terminal: {
32
+ noColor: false,
33
+ theme: {
34
+ primary: [0, 149, 250], // blue theme
35
+ shade1: [0, 90, 250],
36
+ shade2: [0, 208, 245],
37
+ paddingX: 2,
38
+ paddingY: 2,
39
+ pageWidth: 53,
40
+ debugModeColor: [201, 27, 169],
41
+ }
42
+ },
43
+ }
44
+
45
+ /** Allow dynamic changing of config */
46
+ export function configFn() { return config }
47
+
48
+
49
+ /** Register custom config
50
+ * @param {object} customConfig { 'email': email => /.+@.+/.test(email), type2 : myTestFunction() }
51
+ * * env: 'development',
52
+ * * customTypes: {},
53
+ * * terminal: {
54
+ * * noColor: false, // disable colored escape sequences like /mOO35...etc
55
+ * * theme: {
56
+ * * primary: [61, 167, 32], // main color (title font)
57
+ * * shade1: [127, 192, 39], // gradient shade 1
58
+ * * shade2: [194, 218, 47], // gradient shade 2
59
+ * * bgColor: false, // background color
60
+ * * paddingX: 2, // nb spaces added before an outputted str
61
+ * * paddingY: 2, //
62
+ * * fontColor: false, // default font color
63
+ * * pageWidth: 53, // page size in character
64
+ * * debugModeColor: [147, 212, 6], // usually orange
65
+ * * }
66
+ * * },
67
+ */
68
+ export function registerConfig(customConfig) {
69
+ if (!isset(customConfig.terminal)) customConfig.terminal = {}
70
+ const newconfig = {
71
+ ...config,
72
+ ...customConfig
73
+ }
74
+ newconfig.terminal = {
75
+ ...config.terminal,
76
+ ...customConfig.terminal
77
+ }
78
+ newconfig.terminal.theme = {
79
+ ...config.terminal.theme,
80
+ ...(customConfig.terminal.theme || {})
81
+ }
82
+ config = newconfig
83
+
84
+ config.isProd = config.env.includes('prod')
85
+ }
@@ -0,0 +1,21 @@
1
+ export class dataValidationUtilErrorHandler extends Error {
2
+ fromDataValidation: boolean
3
+ code: number
4
+ extraInfos: object
5
+ msg: string
6
+ errorDescription: { [k: string]: any }
7
+ constructor(msg, code, extraInfos?) {
8
+ super(msg)
9
+ this.message = msg
10
+ this.msg = msg
11
+ this.name = `${code} ${msg}`
12
+ this.fromDataValidation = true // will be catched by express error handler
13
+ this.code = code
14
+ this.extraInfos = extraInfos
15
+ this.errorDescription = {
16
+ msg,
17
+ code,
18
+ ...extraInfos,
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,6 @@
1
+
2
+ export type ObjectGeneric = { [k: string]: any }
3
+
4
+ export type Color = [number, number, number]
5
+
6
+ export type Override<T1, T2> = Omit<T1, keyof T2> & T2
@@ -0,0 +1,37 @@
1
+ //----------------------------------------
2
+ // REGEXP UTILS
3
+ //----------------------------------------
4
+ import { C } from "./logger-utils"
5
+
6
+ export function escapeRegexp(str: string, config: { parseStarChar?: boolean } = {}): string {
7
+ const { parseStarChar = false } = config
8
+ if (parseStarChar) return str.replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&').replace(/\*/g, '.*')
9
+ else return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
10
+ }
11
+
12
+ /** Get first match of the first capturing group of regexp
13
+ * Eg: const basePath = firstMatch(apiFile, /basePath = '(.*?)'/); will get what is inside quotes
14
+ */
15
+ export function firstMatch(str: string, regExp: RegExp): string | undefined { return (str.match(regExp) || [])[1] }
16
+
17
+ /** Get all matches from regexp with g flag
18
+ * Eg: [ [full, match1, m2], [f, m1, m2]... ]
19
+ * NOTE: the G flag will be appended to regexp
20
+ */
21
+ export function allMatches(str: string, reg: RegExp): string[] {
22
+ let i = 0
23
+ let matches
24
+ const arr = []
25
+ if (typeof str !== 'string') C.error('Not a string provided as first argument for allMatches()')
26
+ else {
27
+ reg = new RegExp(reg, 'g')
28
+ while ((matches = reg.exec(str))) {
29
+ arr.push(matches)
30
+ if (i++ > 99) {
31
+ C.error('error', 'Please provide the G flag in regexp for allMatches')
32
+ break
33
+ }
34
+ }
35
+ }
36
+ return arr
37
+ }
@@ -0,0 +1,17 @@
1
+
2
+ export function removeCircularJSONstringify(object, indent = 2) {
3
+ const getCircularReplacer = () => {
4
+ const seen = new WeakSet()
5
+ return (key, value) => {
6
+ if (typeof value === 'object' && value !== null) {
7
+ if (seen.has(value)) {
8
+ return
9
+ }
10
+ seen.add(value)
11
+ }
12
+ return value
13
+ }
14
+ }
15
+
16
+ return JSON.stringify(object, getCircularReplacer(), indent)
17
+ }