@beecode/msh-util 1.2.1 → 2.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.
Files changed (145) hide show
  1. package/dist/array-util.d.ts +23 -0
  2. package/dist/array-util.d.ts.map +1 -0
  3. package/dist/array-util.js +27 -0
  4. package/{src/class-factory-pattern.ts → dist/class-factory-pattern.d.ts} +5 -9
  5. package/dist/class-factory-pattern.d.ts.map +1 -0
  6. package/dist/class-factory-pattern.js +26 -0
  7. package/{src/express/error-handler.ts → dist/express/error-handler.d.ts} +2 -10
  8. package/dist/express/error-handler.d.ts.map +1 -0
  9. package/dist/express/error-handler.js +26 -0
  10. package/dist/index.d.ts +17 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +14 -0
  13. package/dist/joi-util.d.ts +47 -0
  14. package/dist/joi-util.d.ts.map +1 -0
  15. package/dist/joi-util.js +62 -0
  16. package/{src/memoize-factory.ts → dist/memoize-factory.d.ts} +3 -14
  17. package/dist/memoize-factory.d.ts.map +1 -0
  18. package/dist/memoize-factory.js +24 -0
  19. package/dist/object-util.d.ts +72 -0
  20. package/dist/object-util.d.ts.map +1 -0
  21. package/dist/object-util.js +115 -0
  22. package/dist/regex-util.d.ts +12 -0
  23. package/dist/regex-util.d.ts.map +1 -0
  24. package/dist/regex-util.js +12 -0
  25. package/dist/single-threshold-promise.d.ts +31 -0
  26. package/dist/single-threshold-promise.d.ts.map +1 -0
  27. package/dist/single-threshold-promise.js +46 -0
  28. package/dist/singleton/async.d.ts +50 -0
  29. package/dist/singleton/async.d.ts.map +1 -0
  30. package/dist/singleton/async.js +75 -0
  31. package/{src/singleton/pattern.ts → dist/singleton/pattern.d.ts} +3 -13
  32. package/dist/singleton/pattern.d.ts.map +1 -0
  33. package/dist/singleton/pattern.js +41 -0
  34. package/dist/string-util.d.ts +10 -0
  35. package/dist/string-util.d.ts.map +1 -0
  36. package/dist/string-util.js +18 -0
  37. package/dist/time-util.d.ts +74 -0
  38. package/dist/time-util.d.ts.map +1 -0
  39. package/dist/time-util.js +90 -0
  40. package/dist/time-zone.d.ts +467 -0
  41. package/dist/time-zone.d.ts.map +1 -0
  42. package/dist/time-zone.js +468 -0
  43. package/{src/timeout.ts → dist/timeout.d.ts} +2 -3
  44. package/dist/timeout.d.ts.map +1 -0
  45. package/dist/timeout.js +17 -0
  46. package/dist/type-util.d.ts +50 -0
  47. package/dist/type-util.d.ts.map +1 -0
  48. package/dist/type-util.js +54 -0
  49. package/lib/array-util.d.ts.map +1 -1
  50. package/lib/array-util.js +30 -28
  51. package/lib/class-factory-pattern.d.ts.map +1 -1
  52. package/lib/class-factory-pattern.js +17 -8
  53. package/lib/express/error-handler.d.ts.map +1 -1
  54. package/lib/express/error-handler.js +15 -11
  55. package/lib/index.d.ts +16 -13
  56. package/lib/index.d.ts.map +1 -1
  57. package/lib/index.js +107 -29
  58. package/lib/joi-util.d.ts.map +1 -1
  59. package/lib/joi-util.js +66 -22
  60. package/lib/memoize-factory.d.ts +1 -1
  61. package/lib/memoize-factory.d.ts.map +1 -1
  62. package/lib/memoize-factory.js +19 -13
  63. package/lib/object-util.d.ts.map +1 -1
  64. package/lib/object-util.js +110 -55
  65. package/lib/package.json +1 -0
  66. package/lib/regex-util.js +15 -13
  67. package/lib/single-threshold-promise.d.ts +1 -1
  68. package/lib/single-threshold-promise.d.ts.map +1 -1
  69. package/lib/single-threshold-promise.js +74 -28
  70. package/lib/singleton/async.d.ts +1 -1
  71. package/lib/singleton/async.d.ts.map +1 -1
  72. package/lib/singleton/async.js +105 -45
  73. package/lib/singleton/pattern.d.ts +1 -1
  74. package/lib/singleton/pattern.d.ts.map +1 -1
  75. package/lib/singleton/pattern.js +13 -12
  76. package/lib/string-util.js +21 -19
  77. package/lib/time-util.js +69 -39
  78. package/lib/time-zone.d.ts +467 -0
  79. package/lib/time-zone.d.ts.map +1 -0
  80. package/lib/time-zone.js +473 -0
  81. package/lib/timeout.js +9 -6
  82. package/lib/type-util.js +57 -55
  83. package/lib/types/global.d.js +5 -0
  84. package/lib/types/types.d.js +3 -0
  85. package/package.json +188 -134
  86. package/lib/array-util.js.map +0 -1
  87. package/lib/class-factory-pattern.js.map +0 -1
  88. package/lib/express/error-handler.js.map +0 -1
  89. package/lib/index.js.map +0 -1
  90. package/lib/joi-util.js.map +0 -1
  91. package/lib/memoize-factory.js.map +0 -1
  92. package/lib/object-util.js.map +0 -1
  93. package/lib/regex-util.js.map +0 -1
  94. package/lib/single-threshold-promise.js.map +0 -1
  95. package/lib/singleton/async.js.map +0 -1
  96. package/lib/singleton/pattern.js.map +0 -1
  97. package/lib/string-util.js.map +0 -1
  98. package/lib/time-util.js.map +0 -1
  99. package/lib/timeout.js.map +0 -1
  100. package/lib/type-util.js.map +0 -1
  101. package/lib/types/any-function/index.d.ts +0 -2
  102. package/lib/types/any-function/index.d.ts.map +0 -1
  103. package/lib/types/any-function/index.js +0 -3
  104. package/lib/types/any-function/index.js.map +0 -1
  105. package/lib/types/any-function/no-params.d.ts +0 -2
  106. package/lib/types/any-function/no-params.d.ts.map +0 -1
  107. package/lib/types/any-function/no-params.js +0 -3
  108. package/lib/types/any-function/no-params.js.map +0 -1
  109. package/lib/types/any-function/promise-no-params.d.ts +0 -2
  110. package/lib/types/any-function/promise-no-params.d.ts.map +0 -1
  111. package/lib/types/any-function/promise-no-params.js +0 -3
  112. package/lib/types/any-function/promise-no-params.js.map +0 -1
  113. package/lib/types/any-function/promise.d.ts +0 -2
  114. package/lib/types/any-function/promise.d.ts.map +0 -1
  115. package/lib/types/any-function/promise.js +0 -3
  116. package/lib/types/any-function/promise.js.map +0 -1
  117. package/src/array-util.test.ts +0 -50
  118. package/src/array-util.ts +0 -26
  119. package/src/class-factory-pattern.test.ts +0 -39
  120. package/src/express/error-handler.test.ts +0 -44
  121. package/src/index.ts +0 -25
  122. package/src/joi-util.test.ts +0 -192
  123. package/src/joi-util.ts +0 -65
  124. package/src/memoize-factory.test.ts +0 -40
  125. package/src/object-util.test.ts +0 -360
  126. package/src/object-util.ts +0 -127
  127. package/src/regex-util.test.ts +0 -25
  128. package/src/regex-util.ts +0 -11
  129. package/src/single-threshold-promise.test.ts +0 -91
  130. package/src/single-threshold-promise.ts +0 -56
  131. package/src/singleton/async.test.ts +0 -122
  132. package/src/singleton/async.ts +0 -90
  133. package/src/singleton/pattern.test.ts +0 -16
  134. package/src/string-util.test.ts +0 -18
  135. package/src/string-util.ts +0 -18
  136. package/src/time-util.test.ts +0 -89
  137. package/src/time-util.ts +0 -98
  138. package/src/timeout.test.ts +0 -65
  139. package/src/type-util.test.ts +0 -20
  140. package/src/type-util.ts +0 -54
  141. package/src/types/any-function/index.ts +0 -1
  142. package/src/types/any-function/no-params.ts +0 -1
  143. package/src/types/any-function/promise-no-params.ts +0 -1
  144. package/src/types/any-function/promise.ts +0 -1
  145. package/src/types/types.d.ts +0 -2
@@ -1,360 +0,0 @@
1
- import { ObjectUtil } from 'src/object-util'
2
-
3
- /* eslint-disable sort-keys-fix/sort-keys-fix */
4
- describe('objectUtil', () => {
5
- const objectUtil = new ObjectUtil()
6
-
7
- const everyType = {
8
- number: 1,
9
- decimal: 1.12345,
10
- string: 'string',
11
- undefined: undefined,
12
- notANumber: NaN,
13
- emptyObj: {},
14
- date: new Date('2020-01-01'),
15
- boolean: true,
16
- nestedObject: { obj: 'test' },
17
- }
18
-
19
- const everyTypeReversed = {
20
- nestedObject: { obj: 'test' },
21
- boolean: true,
22
- date: new Date('2020-01-01'),
23
- emptyObj: {},
24
- notANumber: NaN,
25
- undefined: undefined,
26
- string: 'string',
27
- decimal: 1.12345,
28
- number: 1,
29
- }
30
-
31
- describe('deepClone', () => {
32
- it.each([
33
- [{ test: 'string' }],
34
- [{ deep: { test: 'string' } }],
35
- [{ deeper: { deep: { test: 'string' } } }],
36
- [everyType],
37
- [{ deep: everyType }],
38
- [{ deeper: { deep: everyType } }],
39
- ])('%#. should clone %j', (obj) => {
40
- expect(objectUtil.deepClone(obj)).not.toBe(obj)
41
- })
42
- })
43
-
44
- describe('pickByList', () => {
45
- it.each([
46
- [['a', 'b'], { a: 1, b: '2', c: 3 }, { a: 1, b: '2' }],
47
- [['a', 'c'], { a: 1, b: '2', c: 3 }, { a: 1, c: 3 }],
48
- ])('%#. should pick only this properties [%s] from object %s and return object %s', (propList, obj, result) => {
49
- expect(objectUtil.pickByList(obj, propList)).toEqual(result)
50
- })
51
- })
52
-
53
- describe('pickByObjectKeys', () => {
54
- it.each([
55
- [
56
- { a: 1, b: '2', c: 3 },
57
- { a: '', b: '' },
58
- { a: 1, b: '2' },
59
- ],
60
- [
61
- { a: 1, b: '2', c: 3 },
62
- { a: '', c: '' },
63
- { a: 1, c: 3 },
64
- ],
65
- ])('%#. should pick form this %s using keys from %s and return %s', (obj, objWithPickKeys, result) => {
66
- expect(objectUtil.pickByObjectKeys(obj, objWithPickKeys)).toEqual(result)
67
- })
68
- })
69
-
70
- describe('deepStringify', () => {
71
- it.each([
72
- [{}, '{}'],
73
- [{ a: 1, b: 2 }, `{ a: 1, b: 2 }`],
74
- [
75
- everyType,
76
- `{ boolean: true, date: 2020-01-01T00:00:00.000Z, decimal: 1.12345, emptyObj: {}, nestedObject: { obj: 'test' }, notANumber: NaN, number: 1, string: 'string', undefined: undefined }`,
77
- ],
78
- [
79
- { deep: everyType },
80
- `{ deep: { boolean: true, date: 2020-01-01T00:00:00.000Z, decimal: 1.12345, emptyObj: {}, nestedObject: { obj: 'test' }, notANumber: NaN, number: 1, string: 'string', undefined: undefined } }`,
81
- ],
82
- [
83
- { deeper: { deep: everyType } },
84
- `{ deeper: { deep: { boolean: true, date: 2020-01-01T00:00:00.000Z, decimal: 1.12345, emptyObj: {}, nestedObject: { obj: 'test' }, notANumber: NaN, number: 1, string: 'string', undefined: undefined } } }`,
85
- ],
86
- ])('%#. should compare %j and sort with result %j', (value, expected) => {
87
- expect(objectUtil.deepStringify(value, { isSorted: true })).toEqual(expected)
88
- })
89
-
90
- it.each([
91
- [{ b: 2, a: 1 }, `{ a: 1, b: 2 }`],
92
- [
93
- everyType,
94
- `{ boolean: true, date: 2020-01-01T00:00:00.000Z, decimal: 1.12345, emptyObj: {}, nestedObject: { obj: 'test' }, notANumber: NaN, number: 1, string: 'string', undefined: undefined }`,
95
- ],
96
- [
97
- { deep: everyType },
98
- `{ deep: { boolean: true, date: 2020-01-01T00:00:00.000Z, decimal: 1.12345, emptyObj: {}, nestedObject: { obj: 'test' }, notANumber: NaN, number: 1, string: 'string', undefined: undefined } }`,
99
- ],
100
- [
101
- { deeper: { deep: everyType } },
102
- `{ deeper: { deep: { boolean: true, date: 2020-01-01T00:00:00.000Z, decimal: 1.12345, emptyObj: {}, nestedObject: { obj: 'test' }, notANumber: NaN, number: 1, string: 'string', undefined: undefined } } }`,
103
- ],
104
- ])('%#. should compare %j with result %j and not be equal because it is not sorted', (value, expected) => {
105
- expect(objectUtil.deepStringify(value, { isSorted: true })).toEqual(expected)
106
- expect(objectUtil.deepStringify(value)).not.toEqual(expected)
107
- })
108
-
109
- it.each([
110
- [null, 'null'],
111
- [undefined, 'undefined'],
112
- [123, '123'],
113
- [[123], `[ 123 ]`],
114
- ['test', "'test'"],
115
- (() => {
116
- const date = new Date()
117
-
118
- return [date, date.toISOString()]
119
- })(),
120
- ])('%#. should compare %j with result %j with compact enabled', (value, expected) => {
121
- expect(objectUtil.deepStringify(value)).toEqual(expected)
122
- })
123
-
124
- it.each([
125
- [['d', 'c', 'b', 'a'], `[ 'a', 'b', 'c', 'd' ]`, `[ 'd', 'c', 'b', 'a' ]`],
126
- [{ a: ['d', 'c', 'b', 'a'] }, `{ a: [ 'a', 'b', 'c', 'd' ]`, `{ a: [ 'd', 'c', 'b', 'a' ] }`],
127
- ])('%# should not sort arrays', (arr, expectSorted, expectUnsorted) => {
128
- expect(objectUtil.deepStringify(arr, { isSorted: true })).not.toEqual(expectSorted)
129
- expect(objectUtil.deepStringify(arr, { isSorted: true })).toEqual(expectUnsorted)
130
- })
131
-
132
- it.each([
133
- [
134
- 0,
135
- `{
136
- a: {
137
- a1: {
138
- a2: {
139
- a3: {
140
- a4: {
141
- a5: 'level 5'
142
- }
143
- }
144
- }
145
- }
146
- },
147
- b: {
148
- b1: {
149
- b2: {
150
- b3: {
151
- b4: 'level 4'
152
- }
153
- }
154
- }
155
- },
156
- c: [
157
- 'c0',
158
- [
159
- 'c1',
160
- [
161
- 'c2',
162
- [
163
- 'c3',
164
- [
165
- 'c4',
166
- [
167
- 'c5'
168
- ]
169
- ]
170
- ]
171
- ]
172
- ]
173
- ]
174
- }`,
175
- ],
176
- [
177
- 1,
178
- `{
179
- a: {
180
- a1: {
181
- a2: {
182
- a3: {
183
- a4: { a5: 'level 5' }
184
- }
185
- }
186
- }
187
- },
188
- b: {
189
- b1: {
190
- b2: {
191
- b3: { b4: 'level 4' }
192
- }
193
- }
194
- },
195
- c: [
196
- 'c0',
197
- [
198
- 'c1',
199
- [
200
- 'c2',
201
- [
202
- 'c3',
203
- [
204
- 'c4',
205
- [ 'c5' ]
206
- ]
207
- ]
208
- ]
209
- ]
210
- ]
211
- }`,
212
- ],
213
- [
214
- 2,
215
- `{
216
- a: {
217
- a1: {
218
- a2: {
219
- a3: { a4: { a5: 'level 5' } }
220
- }
221
- }
222
- },
223
- b: {
224
- b1: {
225
- b2: { b3: { b4: 'level 4' } }
226
- }
227
- },
228
- c: [
229
- 'c0',
230
- [
231
- 'c1',
232
- [
233
- 'c2',
234
- [
235
- 'c3',
236
- [ 'c4', [ 'c5' ] ]
237
- ]
238
- ]
239
- ]
240
- ]
241
- }`,
242
- ],
243
- [
244
- 3,
245
- `{
246
- a: {
247
- a1: {
248
- a2: { a3: { a4: { a5: 'level 5' } } }
249
- }
250
- },
251
- b: {
252
- b1: { b2: { b3: { b4: 'level 4' } } }
253
- },
254
- c: [
255
- 'c0',
256
- [
257
- 'c1',
258
- [
259
- 'c2',
260
- [ 'c3', [ 'c4', [ 'c5' ] ] ]
261
- ]
262
- ]
263
- ]
264
- }`,
265
- ],
266
- [
267
- 4,
268
- `{
269
- a: {
270
- a1: { a2: { a3: { a4: { a5: 'level 5' } } } }
271
- },
272
- b: { b1: { b2: { b3: { b4: 'level 4' } } } },
273
- c: [
274
- 'c0',
275
- [
276
- 'c1',
277
- [ 'c2', [ 'c3', [ 'c4', [ 'c5' ] ] ] ]
278
- ]
279
- ]
280
- }`,
281
- ],
282
- [
283
- 5,
284
- `{
285
- a: { a1: { a2: { a3: { a4: { a5: 'level 5' } } } } },
286
- b: { b1: { b2: { b3: { b4: 'level 4' } } } },
287
- c: [
288
- 'c0',
289
- [ 'c1', [ 'c2', [ 'c3', [ 'c4', [ 'c5' ] ] ] ] ]
290
- ]
291
- }`,
292
- ],
293
- [
294
- 6,
295
- `{
296
- a: { a1: { a2: { a3: { a4: { a5: 'level 5' } } } } },
297
- b: { b1: { b2: { b3: { b4: 'level 4' } } } },
298
- c: [ 'c0', [ 'c1', [ 'c2', [ 'c3', [ 'c4', [ 'c5' ] ] ] ] ] ]
299
- }`,
300
- ],
301
- ])('%# should take object with 5 levels and compact it to level $s', (level, expected) => {
302
- const obj = {
303
- a: { a1: { a2: { a3: { a4: { a5: 'level 5' } } } } },
304
- b: { b1: { b2: { b3: { b4: 'level 4' } } } },
305
- c: ['c0', ['c1', ['c2', ['c3', ['c4', ['c5']]]]]],
306
- }
307
- expect(objectUtil.deepStringify(obj, { isPrettyPrinted: true, prettyPrintCompactLevel: level })).toEqual(expected)
308
- })
309
- })
310
-
311
- describe('deepEqual', () => {
312
- it.each([
313
- [null, null],
314
- [undefined, undefined],
315
- [{}, {}],
316
- [everyType, everyType],
317
- [{ deep: everyType }, { deep: everyType }],
318
- [{ deeper: { deep: everyType } }, { deeper: { deep: everyType } }],
319
- ])('%#. should be deep equal compare %j with result %j', (value, result) => {
320
- expect(objectUtil.deepEqual(value, result)).toBeTruthy()
321
- })
322
-
323
- it.each([
324
- [{}, { a: 1 }],
325
- [everyType, { ...everyType, a: 1 }],
326
- [{ deep: everyType }, { a: 1, deep: everyType }],
327
- [{ deeper: { deep: everyType } }, { a: 1, deeper: { deep: everyType } }],
328
- ])('%#. should not deep equal compare %j with result %j', (value, result) => {
329
- expect(objectUtil.deepEqual(value, result)).toBeFalsy()
330
- })
331
-
332
- it.each([
333
- [
334
- { a: 1, b: 2 },
335
- { a: 1, b: 2 },
336
- ],
337
- [
338
- { a: { a: 1, b: 2 }, b: everyType },
339
- { a: { a: 1, b: 2 }, b: everyTypeReversed },
340
- ],
341
- ])('%#. should be deep equal even if in different order compare %j with result %j', (value, result) => {
342
- expect(objectUtil.deepEqual(value, result)).toBeTruthy()
343
- })
344
- })
345
-
346
- describe('deepNullToUndefined', () => {
347
- it.each([
348
- [{ test: undefined }, { test: undefined }],
349
- [{ test: null }, { test: undefined }],
350
- [{ deep: { test: null } }, { deep: { test: undefined } }],
351
- [{ deeper: { deep: { test: null } } }, { deeper: { deep: { test: undefined } } }],
352
- [everyType, everyType],
353
- [{ deep: everyType }, { deep: everyType }],
354
- [{ deeper: { deep: everyType } }, { deeper: { deep: everyType } }],
355
- ])('%#. should convert null to undefined for %j', (withNulls, withUndefined) => {
356
- expect(objectUtil.deepNullToUndefined(withNulls)).toEqual(withUndefined)
357
- })
358
- })
359
- })
360
- /* eslint-enable sort-keys-fix/sort-keys-fix */
@@ -1,127 +0,0 @@
1
- import cloneDeep from 'lodash.clonedeep'
2
- import util from 'util'
3
-
4
- export type ObjectType = Record<string, any>
5
-
6
- export class ObjectUtil {
7
- /**
8
- * Deep clone object. Returned object will have no references to the object passed through params
9
- * @template T
10
- * @param {T} objectToClone
11
- * @return {T}
12
- */
13
- deepClone<T extends ObjectType>(objectToClone: T): T {
14
- return cloneDeep(objectToClone)
15
- }
16
-
17
- /**
18
- * Pick only properties from the property list. It is only allowed to pick properties from the first level
19
- * @template T
20
- * @template L
21
- * @param {T} obj
22
- * @param {L[]} keyList
23
- * @return {Pick<T, L>}
24
- */
25
- pickByList<T extends object, L extends keyof T>(obj: T, keyList: (L | string)[]): Pick<T, L> {
26
- return keyList.reduce((pickedObj, key) => {
27
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
28
- pickedObj[key as L] = obj[key as L]
29
- }
30
-
31
- return pickedObj
32
- }, {} as Pick<T, L>) // eslint-disable-line @typescript-eslint/prefer-reduce-type-parameter
33
- }
34
-
35
- /**
36
- * Pick objects properties using keys from the second object.
37
- * @template T
38
- * @template L
39
- * @param {T} obj
40
- * @param {Partial<T>} objWithPickKeys
41
- * @return {Pick<T, L>}
42
- */
43
- pickByObjectKeys<T extends object, L extends keyof T>(obj: T, objWithPickKeys: Partial<T> | ObjectType): Pick<T, L> {
44
- const keys = Object.keys(objWithPickKeys) as L[]
45
-
46
- return this.pickByList<T, L>(obj, keys)
47
- }
48
-
49
- /**
50
- * This function will do stringify deeper that JSON.stringify.
51
- * @param {any} entity - entity thant needs to be stringify
52
- * @param {object} [options] - available options
53
- * @param {boolean} [options.isSortable=false] - if object property should be sorted
54
- * @param {boolean} [options.isPrettyPrinted=false] - if object and array properties should be printed in a new row
55
- * @param {number} [options.prettyPrintCompactLevel=0] - if pretty print is on define the level of deepest children that are not
56
- * going to be pretty. It doesn't matter if the siblings doesn't have the same depth.
57
- * @return {string} - strung result
58
- * @example
59
- * console.log(new ObjectUtil().deepStringify(null)) // 'null'
60
- * console.log(new ObjectUtil().deepStringify(undefined)) // 'undefined'
61
- * console.log(new ObjectUtil().deepStringify({ a: 1 })) // '{\n\ta: 1\n}'
62
- * // `{
63
- * // a:1
64
- * // }`
65
- * console.log(new ObjectUtil().deepStringify({ b: 1, a: 2 }, {isSorted:true, compact: true})) // { a: 2, b: 1 }
66
- */
67
- deepStringify(
68
- entity: any,
69
- options?: { isSorted?: boolean; isPrettyPrinted?: boolean; prettyPrintCompactLevel?: number }
70
- ): string {
71
- const { isSorted = false, isPrettyPrinted = false, prettyPrintCompactLevel = 0 } = options ?? {}
72
-
73
- const compact = this._deepStringifyCompact({ isPrettyPrinted, prettyPrintCompactLevel })
74
-
75
- return util.inspect(entity, {
76
- breakLength: Infinity,
77
- compact,
78
- depth: Infinity,
79
- maxArrayLength: Infinity,
80
- maxStringLength: Infinity,
81
- sorted: isSorted,
82
- })
83
- }
84
-
85
- protected _deepStringifyCompact(params: { isPrettyPrinted: boolean; prettyPrintCompactLevel: number }): number | boolean {
86
- const { isPrettyPrinted, prettyPrintCompactLevel } = params
87
-
88
- if (!isPrettyPrinted) {
89
- return true
90
- }
91
-
92
- return prettyPrintCompactLevel
93
- }
94
-
95
- /**
96
- * We are converting objects to string (or null or undefined) and comparing if the result is equal
97
- * @param a
98
- * @param b
99
- * @return {boolean}
100
- */
101
- deepEqual(a: any, b: any): boolean {
102
- return this.deepStringify(a, { isSorted: true }) === this.deepStringify(b, { isSorted: true })
103
- }
104
-
105
- /**
106
- * This function is going to convert any null to undefined in the object that is passed to it.
107
- * @template T
108
- * @param {T} objectWithNulls
109
- * @return {T}
110
- * @example
111
- * console.log(new ObjectUtil().deepNullToUndefined({ a: null, b: { c: null } })) // { a: undefined, b: { c: undefined } }
112
- */
113
- deepNullToUndefined<T extends ObjectType>(objectWithNulls: T): T {
114
- return Object.entries(objectWithNulls).reduce<any>((acc, cur) => {
115
- const [key, value] = cur
116
- if (value === null) {
117
- acc[key] = undefined
118
- } else if (typeof value === 'object' && !(value instanceof Date)) {
119
- acc[key] = this.deepNullToUndefined(value)
120
- } else {
121
- acc[key] = value
122
- }
123
-
124
- return acc
125
- }, {})
126
- }
127
- }
@@ -1,25 +0,0 @@
1
- import { regexUtil } from 'src/regex-util'
2
-
3
- describe('regexUtil', () => {
4
- it.each([
5
- ['00000000-0000-0000-0000-000000000000'],
6
- ['b40c3094-a238-4c21-a744-f19b9e476abf'],
7
- ['7d39e0a8-4ca2-41ff-9ded-312fb08f4dda'],
8
- ['f9ea83de-c69f-42ff-8764-a6e88d59d75d'],
9
- ['33f13db5-d427-4ea4-b028-6fc30a84d827'],
10
- ['f04ec90e-2ff5-4b88-beb3-23b348b8e33b'],
11
- ['83ad915b-645a-4132-b8c1-ab398701ba66'],
12
- ['3510e9f1-08f6-4c5a-86a9-66e91c6093b7'],
13
- ['02f243d8-3225-460b-9df7-30380d96971d'],
14
- ['f27571d4-8c4a-4c9a-8899-932d0fa7a68c'],
15
- ['b87a9f9c-c7c2-4aa2-85af-87221cebce9d'],
16
- ])('%#. should pass regex expression check %s', (uuidString) => {
17
- expect(new RegExp(regexUtil.uuid).test(uuidString)).toBeTruthy()
18
- })
19
- it.each([['a'], ['test'], [123], [{}], [{ uuid: '3510e9f1-08f6-4c5a-86a9-66e91c6093b7' }], [new Date()]])(
20
- '%#. should pass regex expression check %s',
21
- (uuidString) => {
22
- expect(new RegExp(regexUtil.uuid).test(uuidString.toString())).toBeFalsy()
23
- }
24
- )
25
- })
package/src/regex-util.ts DELETED
@@ -1,11 +0,0 @@
1
- export const regexUtil = {
2
- /**
3
- * This is a UUID regex expression. This is usually used in express router to constrict the values passed as a path parameter (if you are using UUID as your identifier).
4
- * @return {string}
5
- * @example
6
- * const { uuid } = regexUtil
7
- * router.route(`/users/:userId(${uuid})`).get(getUsersById)
8
- * //...
9
- */
10
- uuid: `\\b[0-9a-f]{8}\\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\\b[0-9a-f]{12}\\b` as const,
11
- }
@@ -1,91 +0,0 @@
1
- import { SingleThresholdPromise } from 'src/single-threshold-promise'
2
- import { timeout } from 'src/timeout'
3
-
4
- describe('SingleThresholdPromise', () => {
5
- describe('promise', () => {
6
- let callCounter = 0
7
- const fake_asyncFactoryFn = jest.fn()
8
- const fake_asyncRejectFactoryFn = jest.fn()
9
-
10
- beforeEach(() => {
11
- callCounter = 0
12
- jest.useFakeTimers()
13
- fake_asyncFactoryFn.mockImplementation(async (): Promise<{ callCount: number }> => {
14
- await timeout(1000)
15
-
16
- return { callCount: ++callCounter }
17
- })
18
- fake_asyncRejectFactoryFn.mockImplementation(async (): Promise<{ callCount: number }> => {
19
- await timeout(1000)
20
- throw new Error()
21
- })
22
- })
23
-
24
- afterEach(() => {
25
- jest.clearAllTimers()
26
- jest.useRealTimers()
27
- jest.resetAllMocks()
28
- })
29
-
30
- it('should return result of the factory function when promise called', async () => {
31
- const singleThresholdPromiseImplementation = new SingleThresholdPromise(fake_asyncFactoryFn)
32
- expect(fake_asyncFactoryFn).not.toHaveBeenCalled()
33
-
34
- const promise = singleThresholdPromiseImplementation.promise()
35
- expect(fake_asyncFactoryFn).toHaveBeenCalledTimes(1)
36
- jest.runAllTimers()
37
- expect(await promise).toEqual({ callCount: 1 })
38
- expect(fake_asyncFactoryFn).toHaveBeenCalledTimes(1)
39
- })
40
-
41
- it('should return the same promise result to multiple calls before the first promise is resolved ', async () => {
42
- const expected = { callCount: 1 }
43
-
44
- const singleThresholdPromiseImplementation = new SingleThresholdPromise(fake_asyncFactoryFn)
45
- const promise1 = singleThresholdPromiseImplementation.promise()
46
- const promise2 = singleThresholdPromiseImplementation.promise()
47
- const promise3 = singleThresholdPromiseImplementation.promise()
48
-
49
- expect(fake_asyncFactoryFn).toHaveBeenCalledTimes(1)
50
- jest.runAllTimers()
51
- expect(await promise1).toEqual(expected)
52
- expect(await promise2).toEqual(expected)
53
- expect(await promise3).toEqual(expected)
54
- expect(fake_asyncFactoryFn).toHaveBeenCalledTimes(1)
55
- })
56
-
57
- it('should return different promise result to multiple calls if they are called after the promise is resolved', async () => {
58
- const singleThresholdPromiseImplementation = new SingleThresholdPromise(fake_asyncFactoryFn)
59
-
60
- expect(fake_asyncFactoryFn).not.toHaveBeenCalled()
61
-
62
- const promise1 = singleThresholdPromiseImplementation.promise()
63
- expect(fake_asyncFactoryFn).toHaveBeenCalledTimes(1)
64
- jest.runAllTimers()
65
- expect(await promise1).toEqual({ callCount: 1 })
66
-
67
- const promise2 = singleThresholdPromiseImplementation.promise()
68
- expect(fake_asyncFactoryFn).toHaveBeenCalledTimes(2)
69
- jest.runAllTimers()
70
- expect(await promise2).toEqual({ callCount: 2 })
71
-
72
- const promise3 = singleThresholdPromiseImplementation.promise()
73
- expect(fake_asyncFactoryFn).toHaveBeenCalledTimes(3)
74
- jest.runAllTimers()
75
- expect(await promise3).toEqual({ callCount: 3 })
76
- })
77
-
78
- it('should reject all if promise is rejected', async () => {
79
- const singleThresholdPromiseImplementation = new SingleThresholdPromise(fake_asyncRejectFactoryFn)
80
- const promise1 = singleThresholdPromiseImplementation.promise()
81
- const promise2 = singleThresholdPromiseImplementation.promise()
82
- const promise3 = singleThresholdPromiseImplementation.promise()
83
- expect(fake_asyncRejectFactoryFn).toHaveBeenCalledTimes(1)
84
- jest.runAllTimers()
85
- await promise1.then(() => expect.fail('test failed')).catch(() => undefined)
86
- await promise2.then(() => expect.fail('test failed')).catch(() => undefined)
87
- await promise3.then(() => expect.fail('test failed')).catch(() => undefined)
88
- expect(fake_asyncRejectFactoryFn).toHaveBeenCalledTimes(1)
89
- })
90
- })
91
- })
@@ -1,56 +0,0 @@
1
- import { AnyFunctionPromiseNoParams } from 'src/types/any-function/promise-no-params'
2
-
3
- /**
4
- * SingleThresholdPromise returns a single promise, and subsequent calls made before the promise resolves will return the same promise.
5
- * @example
6
- * export const refreshTokenSingleThreshold = new SingleThresholdPromise(async () => {
7
- * const oldRefreshToken = await refreshTokenService.get()
8
- * const { accessToken, refreshToken } = await authService.refreshToken({
9
- * refreshToken: oldRefreshToken,
10
- * })
11
- * return { accessToken, refreshToken }
12
- * })
13
- *
14
- * export const authService = {
15
- * refreshToken: async (): Promise<{ accessToken: string; refreshToken:string }> => {
16
- * return refreshTokenSingleThreshold.promise()
17
- * }
18
- * }
19
- */
20
- export class SingleThresholdPromise<T> {
21
- protected _cache: {
22
- promises?: { resolve: (value: T | PromiseLike<T>) => void; reject: (reason?: any) => void }[]
23
- } = {}
24
-
25
- protected _factoryFn: AnyFunctionPromiseNoParams<T>
26
-
27
- constructor(factoryFn: AnyFunctionPromiseNoParams<T>) {
28
- this._factoryFn = factoryFn
29
- }
30
-
31
- protected _rejectPromises(): void {
32
- if (this._cache.promises) {
33
- this._cache.promises.forEach((promise) => promise.reject(new Error('Cache was cleaned')))
34
- }
35
- delete this._cache.promises
36
- }
37
-
38
- async promise(): Promise<T> {
39
- if ('promises' in this._cache) {
40
- return new Promise<T>((resolve, reject) => {
41
- this._cache.promises!.push({ reject, resolve })
42
- })
43
- }
44
-
45
- this._cache.promises = []
46
- const result = await this._factoryFn().catch((err) => {
47
- this._rejectPromises()
48
- throw err
49
- })
50
-
51
- this._cache.promises.forEach((promise) => promise.resolve(result))
52
- delete this._cache.promises
53
-
54
- return result
55
- }
56
- }