Skip to content

Commit c682683

Browse files
committed
fix(exceptions): provide AggregateError polyfill
- prevent Exception#errors from always equaling undefined - https://github.com/es-shims/AggregateError
1 parent 3c07221 commit c682683

File tree

9 files changed

+86
-13
lines changed

9 files changed

+86
-13
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"bootstrap": ". ./.env && yarn prepack",
2323
"postinstall": "is-ci || chmod +x .husky/* && husky install",
2424
"prepack": "yarn workspaces foreach -iv --topological-dev run prepack",
25-
"check:ci": "yarn check:types && yarn check:format && yarn check:style && yarn build --tarball && rimraf packages/*/*.tgz",
25+
"check:ci": "yarn check:types && yarn check:format && yarn check:style && yarn test && yarn build --tarball && rimraf packages/*/*.tgz",
2626
"check:dedupe": "yarn dedupe --check",
2727
"check:format": "prettier --check .",
2828
"check:install": "yarn dlx @yarnpkg/doctor .",

packages/exceptions/.eslintrc.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module.exports = {
2525
'firebase',
2626
'oauth',
2727
'parallelization',
28+
'readonly',
2829
'resform',
2930
'saml',
3031
'satisfiable',

packages/exceptions/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@
9696
},
9797
"dependencies": {
9898
"@flex-development/tutils": "4.2.3",
99+
"@types/es-aggregate-error": "1.0.2",
100+
"es-aggregate-error": "1.0.7",
99101
"lodash.isplainobject": "4.0.6",
100102
"lodash.omit": "4.5.0",
101103
"lodash.pick": "4.4.0"

packages/exceptions/src/exceptions/__tests__/base.exception.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ describe('unit:exceptions/Exception', () => {
126126
expect(Subject.message).toBe(expected)
127127
})
128128
})
129+
130+
describe('#name', () => {
131+
it('should set #name to "Exception"', () => {
132+
expect(new TestSubject().name).toBe('Exception')
133+
})
134+
})
129135
})
130136

131137
describe('.findIdByCode', () => {

packages/exceptions/src/exceptions/__tests__/validation.exception.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ describe('unit:exceptions/ValidationException', () => {
5353
const { dto, expected } = testcase
5454

5555
// Act
56-
const result = new TestSubject('Model', { ...dto, errors: ERRORS }).toJSON()
56+
const result = new TestSubject('Model', { ...dto, errors: ERRORS })
5757

5858
// Expect
5959
expect(result.code).toBe(expected.code)
60-
expect(result.data).toStrictEqual(expected.data)
60+
expect(result.toJSON().data).toStrictEqual(expected.data)
6161
expect(result.message).toBe(expected.message)
62+
expect(result.name).toBe('ValidationException')
6263
})
6364
})

packages/exceptions/src/exceptions/base.exception.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
NextError
1717
} from '@packages/exceptions/interfaces'
1818
import { ExceptionData, ExceptionErrors } from '@packages/exceptions/types'
19+
import AggregateError from 'es-aggregate-error'
1920
import omit from 'lodash.omit'
2021
import pick from 'lodash.pick'
2122
import { DEM } from './constants.exceptions'
@@ -35,29 +36,41 @@ import { DEM } from './constants.exceptions'
3536
// eslint-disable-next-line unicorn/custom-error-definition
3637
export default class Exception<T = any> extends AggregateError {
3738
/**
39+
* @readonly
3840
* @property {ExceptionErrors<T>} errors - Aggregated errors
3941
*/
40-
override errors: ExceptionErrors<T>
42+
declare readonly errors: ExceptionErrors<T>
4143

4244
/**
45+
* @readonly
46+
* @property {'Exception'} name - Constructor name
47+
*/
48+
// @ts-expect-error '"Exception"' is not assignable to type '"AggregateError"
49+
override readonly name: 'Exception' = 'Exception'
50+
51+
/**
52+
* @readonly
4353
* @property {ExceptionClassName} className - Associated CSS class name
4454
*/
45-
className: ExceptionClassName
55+
readonly className: ExceptionClassName
4656

4757
/**
58+
* @readonly
4859
* @property {ExceptionCode} code - HTTP error response status code
4960
*/
50-
code: ExceptionCode
61+
readonly code: ExceptionCode
5162

5263
/**
64+
* @readonly
5365
* @property {ExceptionData} data - Custom error data
5466
*/
55-
data: ExceptionData
67+
readonly data: ExceptionData
5668

5769
/**
70+
* @readonly
5871
* @property {ExceptionId} id - HTTP error response status code name
5972
*/
60-
id: ExceptionId
73+
readonly id: ExceptionId
6174

6275
/**
6376
* Instantiates a new Exception.
@@ -77,7 +90,6 @@ export default class Exception<T = any> extends AggregateError {
7790
) {
7891
super([data.errors || []].flat(), data.message || message || DEM)
7992

80-
this.name = 'Exception'
8193
this.code = Exception.formatCode(code)
8294
this.data = omit(data, ['errors', 'message'])
8395
this.id = Exception.findIdByCode(this.code)

packages/exceptions/src/exceptions/validation.exception.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,17 @@ import Exception from './base.exception'
1919
*/
2020
export default class ValidationException extends Exception<ValidationError> {
2121
/**
22+
* @readonly
2223
* @property {ValidationExceptionErrors} errors - Aggregated validation errors
2324
*/
24-
declare errors: ValidationExceptionErrors
25+
declare readonly errors: ValidationExceptionErrors
26+
27+
/**
28+
* @readonly
29+
* @property {'ValidationException'} name - Constructor name
30+
*/
31+
// @ts-expect-error '"ValidationException"' !== '"Exception"
32+
override readonly name: 'ValidationException' = 'ValidationException'
2533

2634
/**
2735
* Instantiates a new `ValidationException`.
@@ -50,11 +58,13 @@ export default class ValidationException extends Exception<ValidationError> {
5058

5159
// Set message if custom message wasn't provided
5260
if (!dto.message) {
53-
this.message = `${model} validation failure`
61+
let message = `${model} validation failure`
5462

5563
if (this.errors.length > 0) {
56-
this.message += `: [${this.errors.map(e => e.property)}]`
64+
message += `: [${this.errors.map(error => error.property)}]`
5765
}
66+
67+
Object.assign(this, { message })
5868
}
5969
}
6070
}

packages/exceptions/src/types/exception-errors.type.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
*
99
* @template T - Error type
1010
*/
11-
export type ExceptionErrors<T = any> = Array<T>
11+
export type ExceptionErrors<T = any> = ReadonlyArray<T>

yarn.lock

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ __metadata:
839839
"@jest/types": 27.2.5
840840
"@packages/exceptions": "link:src"
841841
"@tests/utils": "link:../../__tests__/utils"
842+
"@types/es-aggregate-error": 1.0.2
842843
"@types/faker": 5.5.9
843844
"@types/jest": 27.0.2
844845
"@types/lodash.isplainobject": 4.0.6
@@ -848,6 +849,7 @@ __metadata:
848849
"@vates/toggle-scripts": 1.0.0
849850
axios: 0.24.0
850851
class-validator: 0.13.1
852+
es-aggregate-error: 1.0.7
851853
faker: 5.5.3
852854
firebase-admin: 10.0.0
853855
jest: 27.3.1
@@ -1940,6 +1942,15 @@ __metadata:
19401942
languageName: node
19411943
linkType: hard
19421944

1945+
"@types/es-aggregate-error@npm:1.0.2":
1946+
version: 1.0.2
1947+
resolution: "@types/es-aggregate-error@npm:1.0.2"
1948+
dependencies:
1949+
"@types/node": "*"
1950+
checksum: 076fd59b595f33c8c7e7eb68ec55bd43cf8b2cf7bbc6778e25d7ae1a5fa0538a0a56f149015f403d7bbcefe59f1d8182351685b59c1fe719fd46d0dd8a9737fa
1951+
languageName: node
1952+
linkType: hard
1953+
19431954
"@types/express-jwt@npm:0.0.42":
19441955
version: 0.0.42
19451956
resolution: "@types/express-jwt@npm:0.0.42"
@@ -4120,6 +4131,20 @@ __metadata:
41204131
languageName: node
41214132
linkType: hard
41224133

4134+
"es-aggregate-error@npm:1.0.7":
4135+
version: 1.0.7
4136+
resolution: "es-aggregate-error@npm:1.0.7"
4137+
dependencies:
4138+
define-properties: ^1.1.3
4139+
es-abstract: ^1.19.0
4140+
function-bind: ^1.1.1
4141+
functions-have-names: ^1.2.2
4142+
get-intrinsic: ^1.1.1
4143+
globalthis: ^1.0.2
4144+
checksum: 16b89fefdf56c0478cd21577249156cf83e44c2220c057cbfddd99c01e15e03d6d90a85ce73dece4728a5bfcb022dc160e04a66b1f83a620f140842c6f8325f9
4145+
languageName: node
4146+
linkType: hard
4147+
41234148
"es-to-primitive@npm:^1.2.1":
41244149
version: 1.2.1
41254150
resolution: "es-to-primitive@npm:1.2.1"
@@ -4975,6 +5000,13 @@ fsevents@^2.3.2:
49755000
languageName: node
49765001
linkType: hard
49775002

5003+
"functions-have-names@npm:^1.2.2":
5004+
version: 1.2.2
5005+
resolution: "functions-have-names@npm:1.2.2"
5006+
checksum: 25f44b6d1c41ac86ffdf41f25d1de81c0a5b4a3fcf4307a33cdfb23b9d4bd5d0d8bf312eaef5ad368c6500c8a9e19f692b8ce9f96aaab99db9dd936554165558
5007+
languageName: node
5008+
linkType: hard
5009+
49785010
"gauge@npm:~2.7.3":
49795011
version: 2.7.4
49805012
resolution: "gauge@npm:2.7.4"
@@ -5222,6 +5254,15 @@ fsevents@^2.3.2:
52225254
languageName: node
52235255
linkType: hard
52245256

5257+
"globalthis@npm:^1.0.2":
5258+
version: 1.0.2
5259+
resolution: "globalthis@npm:1.0.2"
5260+
dependencies:
5261+
define-properties: ^1.1.3
5262+
checksum: 5a5f3c7ab94708260a98106b35946b74bb57f6b2013e39668dc9e8770b80a3418103b63a2b4aa01c31af15fdf6a2940398ffc0a408573c34c2304f928895adff
5263+
languageName: node
5264+
linkType: hard
5265+
52255266
"globby@npm:^11.0.4":
52265267
version: 11.0.4
52275268
resolution: "globby@npm:11.0.4"

0 commit comments

Comments
 (0)