catch-match 1.1.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -39,6 +39,10 @@ try {
39
39
  //> final
40
40
  ```
41
41
 
42
+ ## Features
43
+
44
+ Supporting sync/async functions
45
+
42
46
  ## Getting started
43
47
 
44
48
  ```shell
@@ -50,101 +54,96 @@ npm install catch-match
50
54
  ```
51
55
 
52
56
  ```javascript
53
- import _try from 'catch-match';
54
- // or
55
- import { _try } from 'catch-match';
57
+ import $try from 'catch-match';
56
58
  // or
57
- import { _try as customTry } from 'catch-match';
59
+ import { $try } from 'catch-match';
58
60
  ```
59
61
 
60
62
  ## Example 1
63
+
61
64
  ```javascript
62
- const result = _try(context => {
63
- context.tmp = 'any context data';
64
- console.log('start', context);
65
- return [1, 2, 3, 4, 5]; // value
66
- }).catch(SyntaxError, (context) => {
67
- // noop
68
- }).catch([TypeError, ReferenceError], (context) => {
69
- // noop
70
- }).other((error, context) => {
71
- // noop
72
- }).finally(({value, context, error}) => {
73
- // value: [1, 2, 3, 4, 5]
74
- // context: {tmp: 'any context data'}
75
- // error: undefined
76
- if (!error) {
77
- return value.reverse();
78
- }
65
+ const result = $try(() => {
66
+ throw SyntaxError;
67
+ }).catch(ReferenceError, () => {
68
+ // noop
69
+ }).catch([TypeError, SyntaxError], () => {
70
+ // to be called
71
+ }).other((error) => {
72
+ // noop
73
+ }).finally(({ result, error }) => {
74
+ return result;
79
75
  });
80
76
 
81
- console.log(result);
82
- // {
83
- // value: [5, 4, 3, 2, 1]
84
- // context: {tmp: 'any context data'}
85
- // error: undefined
86
- // }
87
-
77
+ console.log(result); // { error: SyntaxError, result: undefined }
88
78
  ```
89
79
 
90
80
  ## Example 2
81
+
91
82
  ```javascript
92
- const result = _try(context => {
93
- context.tmp = 'any context data';
94
- console.log('start', context);
95
- // ...
96
- throw ReferenceError;
97
- }).catch(SyntaxError, (context) => {
83
+ const result = $try(() => {
84
+ return [1, 2, 3];
85
+ }).catch(ReferenceError, () => {
98
86
  // noop
99
- }).catch([TypeError, ReferenceError], (context) => {
100
- // context: {tmp: 'any context data'}
101
- }).other((error, context) => {
87
+ }).catch([TypeError, SyntaxError], () => {
88
+ // to be called
89
+ }).other((error) => {
102
90
  // noop
103
- }).finally(({value, context, error}) => {
104
- // value: undefined
105
- // context: {tmp: 'any context data'}
106
- // error: ReferenceError
107
- if (!error) {
108
- return value.reverse();
109
- }
91
+ }).finally(({ result, error }) => {
92
+ return result;
110
93
  });
111
94
 
112
- console.log(result);
113
- // {
114
- // value: undefined
115
- // context: {tmp: 'any context data'}
116
- // error: ReferenceError
117
- // }
118
-
95
+ console.log(result); // {error: undefined, result: [1, 2, 3]}
119
96
  ```
120
97
 
121
98
  ## Example 3
99
+
122
100
  ```javascript
123
- const result = _try(context => {
124
- context.tmp = 'any context data';
125
- console.log('start', context);
126
- // ...
101
+ const result = $try(() => {
127
102
  throw SyntaxError;
128
- }).catch([TypeError, ReferenceError], (context) => {
129
- // noop
130
- }).other((error, context) => {
131
- // error: SyntaxError
132
- // context: {tmp: 'any context data'}
133
- context.unexpectedError = true;
134
- }).finally(({value, context, error}) => {
135
- // value: undefined
136
- // context: {tmp: 'any context data', unexpectedError: true}
137
- // error: SyntaxError
138
- if (!error) {
139
- return value.reverse();
140
- }
141
- });
103
+ })
104
+
105
+ console.log(result); // { error: SyntaxError, result: undefined }
106
+ ```
107
+
108
+ ## Promises example
109
+
110
+ ```typescript
111
+ class AuthError extends Error {}
112
+
113
+ function proc(event: string) {
114
+ return $try(() => new Promise((resolve, reject) => {
115
+ switch (event) {
116
+ case 'resolve':
117
+ resolve('resolved')
118
+ break;
119
+ case 'reject':
120
+ reject('rejected')
121
+ break;
122
+ case 'syntax':
123
+ throw SyntaxError
124
+ case 'auth':
125
+ throw AuthError
126
+ case 'error':
127
+ throw 'error'
128
+ default:
129
+ throw 'other errors'
130
+ }
131
+ }).catch('error', () => {
132
+ // console.log('error')
133
+ }).catch([SyntaxError, AuthError], (error) => {
134
+ // console.log(error)
135
+ }).other((error) => {
136
+ // console.log(error)
137
+ }).finally(({ value, error }) => {
138
+ // console.log({ value, error })
139
+ })
140
+ }
142
141
 
143
- console.log(result);
144
- // {
145
- // value: undefined
146
- // context: {tmp: 'any context data', unexpectedError: true}
147
- // error: SyntaxError
148
- // }
142
+ await proc('resolve') // { value: 'resolved' }}
143
+ await proc('reject') // { error: 'rejected' }
149
144
 
145
+ await proc('syntax') // { error: SyntaxError }
146
+ await proc('auth') // { error: AuthError }
147
+ await proc('error') // { error: 'error' }
148
+ await proc('other') // { error: 'other errors' }
150
149
  ```
package/jest.config.js ADDED
@@ -0,0 +1,10 @@
1
+ /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ globals: {
6
+ 'ts-jest': {
7
+ tsconfig: 'tsconfig.test.json',
8
+ },
9
+ },
10
+ };
package/package.json CHANGED
@@ -1,16 +1,35 @@
1
1
  {
2
2
  "name": "catch-match",
3
- "version": "1.1.0",
3
+ "version": "3.0.1",
4
4
  "repository": {
5
5
  "url": "https://github.com/kobzarvs/catch-match"
6
6
  },
7
- "keywords": ["try", "catch", "match", "pattern", "errors", "exceptions", "throw", "finally"],
8
- "type": "module",
7
+ "keywords": [
8
+ "try",
9
+ "catch",
10
+ "match",
11
+ "pattern",
12
+ "errors",
13
+ "exceptions",
14
+ "throw",
15
+ "finally",
16
+ "promises",
17
+ "resolve",
18
+ "reject",
19
+ "flow",
20
+ "control",
21
+ "process"
22
+ ],
9
23
  "main": "dist/main.js",
10
24
  "scripts": {
11
- "build": "tsc"
25
+ "build": "tsc",
26
+ "test": "jest"
27
+ },
28
+ "devDependencies": {
29
+ "@types/jest": "^27.4.0",
30
+ "jest": "^27.4.7",
31
+ "ts-jest": "^27.1.3"
12
32
  },
13
- "devDependencies": {},
14
33
  "dependencies": {
15
34
  "typescript": "^4.5.4"
16
35
  }
@@ -0,0 +1,502 @@
1
+ import $try, { PromisedTryReturn } from '../main';
2
+
3
+ describe('sync version', () => {
4
+ test('should be return result from `finally` branch', () => {
5
+ let matchReferenceError = jest.fn();
6
+ let matchArrayOfErrors = jest.fn();
7
+ let matchOther = jest.fn();
8
+ let matchFinally = jest.fn();
9
+
10
+ const result = $try(() => {
11
+ return [1, 2, 3];
12
+ }).catch(ReferenceError, () => {
13
+ matchReferenceError();
14
+ }).catch([TypeError, SyntaxError], (error) => {
15
+ matchArrayOfErrors(error);
16
+ }).other((error) => {
17
+ matchOther(error);
18
+ }).finally(({ value, error }) => { //?
19
+ matchFinally({ value, error });
20
+ });
21
+
22
+ expect(matchReferenceError).not.toBeCalled();
23
+ expect(matchArrayOfErrors).not.toBeCalled();
24
+ expect(matchOther).not.toBeCalled();
25
+ expect(matchFinally).toBeCalled();
26
+ expect(result).toMatchObject({ error: undefined, value: [1, 2, 3] });
27
+ });
28
+
29
+ test('should be match single exception', () => {
30
+ let matchReferenceError = jest.fn();
31
+ let matchArrayOfErrors = jest.fn();
32
+ let matchOther = jest.fn();
33
+ let matchFinally = jest.fn();
34
+
35
+ const result = $try(() => {
36
+ throw ReferenceError;
37
+ }).catch(ReferenceError, () => {
38
+ matchReferenceError();
39
+ }).catch([TypeError, SyntaxError], (error) => {
40
+ matchArrayOfErrors(error);
41
+ }).other((error) => {
42
+ matchOther(error);
43
+ }).finally(({ value, error }) => {
44
+ matchFinally({ value, error });
45
+ return value; // ?
46
+ });
47
+
48
+ expect(matchReferenceError).toBeCalled();
49
+ expect(matchArrayOfErrors).not.toBeCalled();
50
+ expect(matchOther).not.toBeCalled();
51
+ expect(matchFinally).toBeCalled();
52
+ expect(result).toMatchObject({ error: ReferenceError, value: undefined });
53
+ });
54
+
55
+ test('should be match array of exceptions', () => {
56
+ let matchReferenceError = jest.fn();
57
+ let matchArrayOfErrors = jest.fn();
58
+ let matchOther = jest.fn();
59
+ let matchFinally = jest.fn();
60
+
61
+ const result = $try(() => {
62
+ throw SyntaxError;
63
+ }).catch(ReferenceError, () => {
64
+ matchReferenceError();
65
+ }).catch([TypeError, SyntaxError], (error) => {
66
+ matchArrayOfErrors(error);
67
+ }).other((error) => {
68
+ matchOther(error);
69
+ }).finally(({ value, error }) => {
70
+ matchFinally({ value, error });
71
+ return value; // ?
72
+ });
73
+
74
+ expect(matchReferenceError).not.toBeCalled();
75
+ expect(matchArrayOfErrors).toBeCalledWith(SyntaxError);
76
+ expect(matchOther).not.toBeCalled();
77
+ expect(matchFinally).toBeCalled();
78
+ expect(result).toMatchObject({ error: SyntaxError, value: undefined });
79
+ });
80
+
81
+ test('should be match any type of exception', () => {
82
+ let matchReferenceError = jest.fn();
83
+ let matchArrayOfErrors = jest.fn();
84
+ let matchOther = jest.fn();
85
+ let matchFinally = jest.fn();
86
+
87
+ const result = $try(() => {
88
+ throw 'error';
89
+ }).catch(ReferenceError, () => {
90
+ matchReferenceError();
91
+ }).catch([TypeError, SyntaxError], (error) => {
92
+ matchArrayOfErrors(error);
93
+ }).other((error) => {
94
+ matchOther(error);
95
+ }).finally(({ value, error }) => {
96
+ matchFinally({ value, error });
97
+ return value; // ?
98
+ });
99
+
100
+ expect(matchReferenceError).not.toBeCalled();
101
+ expect(matchArrayOfErrors).not.toBeCalled();
102
+ expect(matchOther).toBeCalled();
103
+ expect(matchFinally).toBeCalled();
104
+ expect(result).toMatchObject({ error: 'error', value: undefined });
105
+ });
106
+
107
+ test('should be match custom exceptions', () => {
108
+ let matchCustomError = jest.fn();
109
+ let matchArrayOfErrors = jest.fn();
110
+ let matchOther = jest.fn();
111
+ let matchFinally = jest.fn();
112
+
113
+ class CustomError extends Error {
114
+ }
115
+
116
+ const result = $try(() => {
117
+ throw CustomError;
118
+ }).catch(CustomError, () => {
119
+ matchCustomError();
120
+ }).catch([TypeError, SyntaxError], (error) => {
121
+ matchArrayOfErrors(error);
122
+ }).other((error) => {
123
+ matchOther(error);
124
+ }).finally(({ value, error }) => {
125
+ matchFinally({ value, error });
126
+ });
127
+
128
+ expect(matchCustomError).toBeCalled();
129
+ expect(matchArrayOfErrors).not.toBeCalled();
130
+ expect(matchOther).not.toBeCalled();
131
+ expect(matchFinally).toBeCalled();
132
+ expect(result).toMatchObject({ error: CustomError, value: undefined });
133
+ });
134
+
135
+ test('should be return result from `finally` branch without `other`', () => {
136
+ let matchCustomError = jest.fn();
137
+ let matchArrayOfErrors = jest.fn();
138
+ let matchOther = jest.fn();
139
+ let matchFinally = jest.fn();
140
+
141
+ class CustomError extends Error {
142
+ }
143
+
144
+ const result = $try(() => {
145
+ throw CustomError;
146
+ }).catch([TypeError, SyntaxError], (error) => {
147
+ matchArrayOfErrors(error);
148
+ }).finally(({ value, error }) => {
149
+ matchFinally({ value, error });
150
+ return value; // ?
151
+ });
152
+
153
+ expect(matchCustomError).not.toBeCalled();
154
+ expect(matchArrayOfErrors).not.toBeCalled();
155
+ expect(matchOther).not.toBeCalled();
156
+ expect(matchFinally).toBeCalled();
157
+ expect(result).toMatchObject({ error: CustomError, value: undefined });
158
+ });
159
+
160
+ test('should be return result from `catch` branch', () => {
161
+ let matchCustomError = jest.fn();
162
+ let matchArrayOfErrors = jest.fn();
163
+ let matchOther = jest.fn();
164
+ let matchFinally = jest.fn();
165
+
166
+ class CustomError extends Error {
167
+ }
168
+
169
+ const result = $try(() => {
170
+ throw CustomError;
171
+ }).catch([TypeError, SyntaxError], (error) => {
172
+ matchArrayOfErrors(error);
173
+ });
174
+
175
+ expect(matchCustomError).not.toBeCalled();
176
+ expect(matchArrayOfErrors).not.toBeCalled();
177
+ expect(matchOther).not.toBeCalled();
178
+ expect(matchFinally).not.toBeCalled();
179
+ expect(result).toMatchObject({ error: CustomError, value: undefined });
180
+ });
181
+
182
+ test('should be return result from `other` branch', () => {
183
+ let matchCustomError = jest.fn();
184
+ let matchArrayOfErrors = jest.fn();
185
+ let matchOther = jest.fn();
186
+ let matchFinally = jest.fn();
187
+
188
+ class CustomError extends Error {
189
+ }
190
+
191
+ const result = $try(() => {
192
+ throw CustomError;
193
+ }).other((error) => {
194
+ matchOther(error);
195
+ });
196
+
197
+ expect(matchCustomError).not.toBeCalled();
198
+ expect(matchArrayOfErrors).not.toBeCalled();
199
+ expect(matchOther).toBeCalledWith(CustomError);
200
+ expect(matchFinally).not.toBeCalled();
201
+ expect(result).toMatchObject({ error: CustomError, value: undefined });
202
+ });
203
+
204
+ test('should be return result without branches', () => {
205
+ let matchCustomError = jest.fn();
206
+ let matchArrayOfErrors = jest.fn();
207
+ let matchOther = jest.fn();
208
+ let matchFinally = jest.fn();
209
+
210
+ const result = $try(() => {
211
+ throw SyntaxError;
212
+ });
213
+
214
+ expect(matchCustomError).not.toBeCalled();
215
+ expect(matchArrayOfErrors).not.toBeCalled();
216
+ expect(matchOther).not.toBeCalled();
217
+ expect(matchFinally).not.toBeCalled();
218
+ expect(result).toMatchObject({ error: SyntaxError, value: undefined });
219
+ });
220
+ });
221
+
222
+ /**
223
+ * async tests
224
+ */
225
+ describe('promised version', () => {
226
+ test('resolve try', async () => {
227
+ let matchCustomError = jest.fn();
228
+ let matchArrayOfErrors = jest.fn();
229
+ let matchOther = jest.fn();
230
+ let matchFinally = jest.fn();
231
+
232
+ const result = $try(() => {
233
+ return Promise.resolve(42);
234
+ });
235
+
236
+ await result;
237
+
238
+ expect(matchCustomError).not.toBeCalled();
239
+ expect(matchArrayOfErrors).not.toBeCalled();
240
+ expect(matchOther).not.toBeCalled();
241
+ expect(matchFinally).not.toBeCalled();
242
+
243
+ expect(result).toBeInstanceOf(Promise);
244
+ expect(await result).toEqual({
245
+ value: 42,
246
+ error: undefined,
247
+ });
248
+ });
249
+ test('reject try', async () => {
250
+ let matchCustomError = jest.fn();
251
+ let matchArrayOfErrors = jest.fn();
252
+ let matchOther = jest.fn();
253
+ let matchFinally = jest.fn();
254
+
255
+ const result = $try(() => {
256
+ return Promise.reject(42);
257
+ });
258
+
259
+ expect(matchCustomError).not.toBeCalled();
260
+ expect(matchArrayOfErrors).not.toBeCalled();
261
+ expect(matchOther).not.toBeCalled();
262
+ expect(matchFinally).not.toBeCalled();
263
+
264
+ expect(result).toBeInstanceOf(Promise);
265
+ expect(await result).toEqual({
266
+ value: undefined,
267
+ error: 42,
268
+ });
269
+ });
270
+ test('throw try', async () => {
271
+ const result = $try(() => {
272
+ return new Promise(() => {
273
+ throw new Error('error');
274
+ });
275
+ });
276
+
277
+ expect(result).toBeInstanceOf(Promise);
278
+
279
+ expect(await result).toEqual({
280
+ value: undefined,
281
+ error: Error('error'),
282
+ });
283
+ });
284
+
285
+ test('resolve try.catch', async () => {
286
+ let matchError = jest.fn();
287
+ let matchSyntaxError = jest.fn();
288
+ let matchOther = jest.fn();
289
+
290
+ const result = $try(() => {
291
+ return Promise.resolve(42);
292
+ }).catch(Error, () => {
293
+ matchError();
294
+ }).catch(SyntaxError, () => {
295
+ matchSyntaxError();
296
+ }).other((error) => {
297
+ matchOther(error);
298
+ });
299
+
300
+ expect(matchError).not.toBeCalled();
301
+ expect(matchSyntaxError).not.toBeCalled();
302
+ expect(matchOther).not.toBeCalled();
303
+
304
+ expect(result).toBeInstanceOf(Promise);
305
+ expect(await result).toEqual({
306
+ value: 42,
307
+ error: undefined,
308
+ });
309
+ });
310
+ test('reject try.catch', async () => {
311
+ let matchError = jest.fn();
312
+ let matchOther = jest.fn();
313
+
314
+ const result = $try(() => {
315
+ return Promise.reject(123);
316
+ }).catch(Error, () => {
317
+ matchOther();
318
+ }).catch(123, () => {
319
+ matchError();
320
+ }).catch('error', () => {
321
+ matchOther();
322
+ });
323
+
324
+ await result; //?
325
+
326
+ expect(matchOther).not.toBeCalled();
327
+ expect(matchError).toBeCalled();
328
+
329
+ expect(result).toBeInstanceOf(Promise);
330
+ expect(await result).toEqual({
331
+ value: undefined,
332
+ error: 123,
333
+ });
334
+ });
335
+ test('throw try.catch', async () => {
336
+ let matchError = jest.fn();
337
+ let matchOther = jest.fn();
338
+
339
+ const result = $try(() => {
340
+ return new Promise(() => {
341
+ throw 'error';
342
+ });
343
+ }).catch(Error, () => {
344
+ matchOther();
345
+ }).catch(123, () => {
346
+ matchError();
347
+ }).catch('error', () => {
348
+ matchOther();
349
+ });
350
+
351
+ expect(result).toBeInstanceOf(Promise);
352
+ expect(await result).toEqual({
353
+ value: undefined,
354
+ error: 'error',
355
+ });
356
+
357
+ expect(matchOther).toBeCalledTimes(1);
358
+ expect(matchError).not.toBeCalled();
359
+ });
360
+
361
+ test('resolve try.other', async () => {
362
+ let matchCustomError = jest.fn();
363
+ let matchArrayOfErrors = jest.fn();
364
+ let matchOther = jest.fn();
365
+ let matchFinally = jest.fn();
366
+
367
+ const result = $try(() => {
368
+ return Promise.resolve('ok');
369
+ }).other(({ value, error }) => {
370
+ matchOther({ value, error });
371
+ });
372
+
373
+ expect(result).toBeInstanceOf(Promise);
374
+ expect(await result).toEqual({
375
+ value: 'ok',
376
+ error: undefined,
377
+ });
378
+
379
+ expect(matchCustomError).not.toBeCalled();
380
+ expect(matchArrayOfErrors).not.toBeCalled();
381
+ expect(matchOther).not.toBeCalled();
382
+ expect(matchFinally).not.toBeCalled();
383
+ });
384
+ test('reject try.other', async () => {
385
+ let matchError = jest.fn();
386
+ let matchOther = jest.fn();
387
+
388
+ const result = $try(() => {
389
+ return Promise.reject('error');
390
+ }).catch('error1', () => {
391
+ matchError();
392
+ }).catch('error2', () => {
393
+ matchError();
394
+ }).other((error) => {
395
+ matchOther(error);
396
+ });
397
+
398
+ expect(result).toBeInstanceOf(Promise);
399
+ expect(await result).toEqual({
400
+ value: undefined,
401
+ error: 'error',
402
+ });
403
+
404
+ expect(matchError).not.toBeCalled();
405
+ expect(matchOther).toBeCalledWith('error');
406
+ });
407
+ test('throw try.other', async () => {
408
+ let matchError = jest.fn();
409
+ let matchOther = jest.fn();
410
+
411
+ const result = $try(() => {
412
+ return new Promise(() => {
413
+ throw 'error';
414
+ });
415
+ }).catch('error1', () => {
416
+ matchError();
417
+ }).catch('error2', () => {
418
+ matchError();
419
+ }).other((error) => {
420
+ matchOther(error);
421
+ });
422
+
423
+ expect(result).toBeInstanceOf(Promise);
424
+ expect(await result).toEqual({
425
+ value: undefined,
426
+ error: 'error',
427
+ });
428
+
429
+ expect(matchError).not.toBeCalled();
430
+ expect(matchOther).toBeCalledWith('error');
431
+ });
432
+
433
+ test('when throw should be match array or exception', async () => {
434
+ let matchSingleError = jest.fn();
435
+ let matchArrayError = jest.fn();
436
+ let matchOther = jest.fn();
437
+ let matchFinally = jest.fn();
438
+
439
+ const attach = (ctx: PromisedTryReturn<any>) => {
440
+ return ctx.catch(SyntaxError, () => {
441
+ matchSingleError(SyntaxError);
442
+ }).catch([ReferenceError, SyntaxError], (error) => {
443
+ matchArrayError(error);
444
+ }).other((error) => {
445
+ matchOther(error);
446
+ }).finally(({ value, error }) => {
447
+ matchFinally({ value, error });
448
+ });
449
+ };
450
+
451
+ const testSingle = $try(() => new Promise(() => {
452
+ throw SyntaxError;
453
+ }));
454
+
455
+ const testArray = $try(() => new Promise(() => {
456
+ throw ReferenceError;
457
+ }));
458
+
459
+ const testOther = $try(() => new Promise(() => {
460
+ throw TypeError;
461
+ }));
462
+
463
+ const testResolve = $try(() => new Promise((resolve) => {
464
+ resolve('ok');
465
+ }));
466
+
467
+ const testReject = $try(() => new Promise((_, reject) => {
468
+ reject('reject');
469
+ }));
470
+
471
+ const resultSingle = attach(testSingle);
472
+ const resultArray = attach(testArray);
473
+ const resultOther = attach(testOther);
474
+ const resultResolve = attach(testResolve);
475
+ const resultReject = attach(testReject);
476
+
477
+ expect(resultSingle).toBeInstanceOf(Promise);
478
+ expect(resultArray).toBeInstanceOf(Promise);
479
+ expect(resultOther).toBeInstanceOf(Promise);
480
+ expect(resultResolve).toBeInstanceOf(Promise);
481
+ expect(resultReject).toBeInstanceOf(Promise);
482
+
483
+ expect(await resultSingle).toEqual({
484
+ value: undefined,
485
+ error: SyntaxError,
486
+ });
487
+ expect(await resultArray).toEqual({
488
+ value: undefined,
489
+ error: ReferenceError,
490
+ });
491
+ expect(await resultOther).toEqual({
492
+ value: undefined,
493
+ error: TypeError,
494
+ });
495
+ expect(await resultResolve).toEqual({
496
+ value: 'ok',
497
+ });
498
+ expect(await resultReject).toEqual({
499
+ error: 'reject',
500
+ });
501
+ });
502
+ });
package/src/main.ts CHANGED
@@ -1,51 +1,124 @@
1
- type InternalData<T> = {
2
- value?: T;
3
- error?: any;
4
- context?: any;
5
- };
6
-
7
- export function _try<T>(body: (context: any) => T) {
8
- let error: any;
9
- let result: T;
10
- let context: any = {};
11
- const isSameInstance = (e1: any) => e1 === error || e1 === error?.constructor;
1
+ export type ErrrorHandler<ErrorType> = (error?: ErrorType) => void
12
2
 
13
- try {
14
- result = body(context);
15
- } catch (e) {
16
- error = e;
3
+ export type FinallyCallback<Result, ErrorType = any> = (params: ResultType<Result, ErrorType>) => void
4
+
5
+ export type TryBody<Result> = () => Result | Promise<Result> | never
6
+
7
+ export type ResultType<Result, ErrorType = any> = {
8
+ value?: Result;
9
+ error?: ErrorType;
10
+ }
11
+
12
+ export type FinallyReturn<Return, ErrorType = any> =
13
+ ResultType<Return, ErrorType>
14
+
15
+ export type OtherReturn<Return, ErrorType = any> =
16
+ FinallyReturn<Return, ErrorType> &
17
+ {
18
+ finally: (callback: FinallyCallback<Return, ErrorType>) => ResultType<Return, ErrorType>
17
19
  }
18
20
 
19
- const chain = {
20
- catch: (err: any, handler: (context: any) => void) => {
21
- if (!err || !handler) {
22
- return chain;
23
- }
24
- if (isSameInstance(err)) {
25
- handler && handler(context);
26
- } else if (Array.isArray(err)) {
27
- err.some(isSameInstance) && handler(context);
21
+ export type CatchReturn<Return, ErrorType = any> =
22
+ FinallyReturn<Return, ErrorType> &
23
+ OtherReturn<Return, ErrorType> &
24
+ {
25
+ catch: (error: ErrorType | ErrorType[], handler: ErrrorHandler<ErrorType>) => PromisedTryReturn<Return>;
26
+ other: (handler: ErrrorHandler<ErrorType>) => Pick<PromisedTryReturn<Return>, 'finally' | 'value' | 'error'>,
27
+ }
28
+
29
+ export type PromisedTryReturn<Return> =
30
+ CatchReturn<Return> |
31
+ (Promise<ResultType<Return>> & CatchReturn<Return>)
32
+
33
+ export function $try<Return>(body: TryBody<Return>): PromisedTryReturn<Return> {
34
+ let caught = false;
35
+ let error: any | { constructor?: any; } | Promise<any | { constructor?: any; }>;
36
+ let bodyResponse: Return | Promise<Return>;
37
+ let result: PromisedTryReturn<Return>;
38
+
39
+ const isSameError = (e1: any, error: any) => e1 === error || e1 === error?.constructor;
40
+
41
+ function handleErrors(err: any[], err2: any, handler: { (error?: any): void; (error?: any): void; (): any }) {
42
+ if (isSameError(err, err2) || (Array.isArray(err) && err.some(e => isSameError(e, err2)))) {
43
+ handler(err2);
44
+ caught = true;
45
+ }
46
+ }
47
+
48
+ function buildResult(br: typeof bodyResponse): ResultType<Return> | Promise<ResultType<Return>> {
49
+ if (br instanceof Promise) {
50
+ const bodyPromise = br as Promise<Return>;
51
+ return new Promise<ResultType<Return>>(async (resolve) => {
52
+ bodyPromise.then((response: any) => {
53
+ resolve({
54
+ value: response,
55
+ error: undefined,
56
+ });
57
+ }).catch((e: any) => {
58
+ resolve({
59
+ value: undefined,
60
+ error: e,
61
+ });
62
+ });
63
+ });
64
+ } else {
65
+ return {
66
+ value: br,
67
+ error: undefined,
68
+ };
69
+ }
70
+ }
71
+
72
+ const chain: CatchReturn<Return, typeof error> = {
73
+ catch: (err, handler) => {
74
+ if (result instanceof Promise) {
75
+ result.then((response) => {
76
+ typeof response.error !== 'undefined' && !caught && handleErrors(err, response.error, handler);
77
+ });
78
+ } else {
79
+ error && !caught && handleErrors(err, error, handler);
28
80
  }
29
- return chain;
81
+ return result;
30
82
  },
31
- other: (handler: (error: any, context: any) => void) => {
32
- if (error) {
33
- handler && handler(error, context);
83
+
84
+ other: (callback) => {
85
+ if (result instanceof Promise) {
86
+ result.then((response) => {
87
+ typeof response.error !== 'undefined' && !caught && callback(response.error);
88
+ });
89
+ } else {
90
+ typeof result.error !== 'undefined' && !caught && callback && callback(result.error);
34
91
  }
35
- return {
36
- finally: chain.finally
37
- };
92
+ return result;
38
93
  },
39
- finally: (callback: (params: InternalData<T>) => T): InternalData<T> => {
40
- return {
41
- value: callback ? callback({value: result, error, context}) : result,
42
- error,
43
- context,
44
- };
94
+
95
+ finally: (callback) => {
96
+ if (result instanceof Promise) {
97
+ result.then((response) => {
98
+ callback(response);
99
+ });
100
+ } else {
101
+ callback({
102
+ value: result.value,
103
+ error: result.error,
104
+ });
105
+ }
106
+ return result;
45
107
  },
46
108
  };
47
109
 
48
- return chain;
110
+ try {
111
+ bodyResponse = body();
112
+ result = Object.assign(buildResult(bodyResponse), chain);
113
+ } catch (e) {
114
+ error = e;
115
+ result = Object.assign(chain, {
116
+ value: undefined,
117
+ error: e,
118
+ });
119
+ }
120
+
121
+ return result;
49
122
  }
50
123
 
51
- export default _try;
124
+ export default $try;
package/tsconfig.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "target": "es6",
4
4
  "useDefineForClassFields": true,
5
5
  "module": "ESNext",
6
- "lib": ["ESNext"],
6
+ "lib": ["ESNext", "DOM"],
7
7
  "moduleResolution": "Node",
8
8
  "strict": true,
9
9
  "sourceMap": true,
@@ -15,7 +15,7 @@
15
15
  "noUnusedParameters": true,
16
16
  "noImplicitReturns": true,
17
17
  "alwaysStrict": true,
18
- "outDir": "dist"
18
+ "outDir": "dist",
19
19
  },
20
20
  "include": ["./src"]
21
21
  }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "./tsconfig.json"
3
+ }