Skip to content

Commit cc6ce8a

Browse files
committed
Add support for multiple conditions
1 parent 297ebdf commit cc6ce8a

File tree

7 files changed

+104
-10
lines changed

7 files changed

+104
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# 4.1.0
22

33
- Conditions can now be [booleans](README.md#boolean-condition),
4-
[error properties objects](README.md#check-error-properties)
4+
[error properties objects](README.md#check-error-properties) or an
5+
[array of conditions](README.md#alternative-conditions)
56

67
# 4.0.1
78

README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ any type. However, the final value returned by
8686
[`.default()`](#switchdefaulteffects) is always an instance of `BaseError` or a
8787
subclass of it.
8888

89-
## Switch.case(condition, ...effects)
89+
## Switch.case(conditions, ...effects)
9090

91-
`condition`: [`Condition`](#condition)\
91+
`conditions`: [`Condition | Condition[]`](#condition)\
9292
`effect`: [`Effect`](#effect)\
9393
_Return value_: [`Switch`](#switchcasecondition-effects)
9494

95-
If `error` matches the `condition`, apply the `effects`. 0, 1 or multiple
95+
If `error` matches the `conditions`, apply the `effects`. 0, 1 or multiple
9696
effects can be applied.
9797

9898
## Switch.default(...effects)
@@ -105,7 +105,7 @@ apply those default `effects`.
105105

106106
## Condition
107107

108-
The `condition` can be:
108+
The `conditions` can be:
109109

110110
- An error class, matched with
111111
[`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof)
@@ -116,6 +116,7 @@ The `condition` can be:
116116
[error properties](https://github.com/ehmicky/modern-errors#%EF%B8%8F-error-properties)
117117
- A filtering function taking the `error` as argument and returning a boolean
118118
- A boolean
119+
- An array of the above types, checking if _any_ condition in the array matches
119120

120121
## Effect
121122

@@ -224,6 +225,16 @@ BaseError.switch(error)
224225
.default()
225226
```
226227

228+
## Alternative conditions
229+
230+
```js
231+
BaseError.switch(error)
232+
// If `error` is either a `DatabaseError` or has `isDatabase: true`,
233+
// append the following message
234+
.case([DatabaseError, { isDatabase: true }], 'Bug at the database layer.')
235+
.default()
236+
```
237+
227238
## Unknown errors
228239

229240
<!-- eslint-disable unicorn/no-null, no-throw-literal,

src/condition.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import isPlainObj from 'is-plain-obj'
33

44
// Add support for `error.message` and `ErrorClass` condition to
55
// the conditions already supported by `switch-functional`
6-
export const normalizeCondition = (condition) => {
6+
export const normalizeConditions = (conditions) =>
7+
Array.isArray(conditions)
8+
? conditions.map(normalizeCondition)
9+
: normalizeCondition(conditions)
10+
11+
const normalizeCondition = (condition) => {
712
if (typeof condition === 'string') {
813
return matchesErrorName.bind(undefined, condition)
914
}

src/condition.test-d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,19 @@ expectNotAssignable<Condition>((errorArg: unknown) => 'true')
5252
switchStatement.case(true)
5353
expectAssignable<Condition>(true)
5454

55+
switchStatement.case([])
56+
switchStatement.case([true])
57+
switchStatement.case([true, 'Error'])
58+
// @ts-expect-error
59+
switchStatement.case([0])
60+
// @ts-expect-error
61+
switchStatement.case([0, 'Error'])
62+
expectNotAssignable<Condition>([])
63+
expectNotAssignable<Condition>([true])
64+
expectNotAssignable<Condition>([true, 'Error'])
65+
expectNotAssignable<Condition>([0])
66+
expectNotAssignable<Condition>([0, 'Error'])
67+
5568
// @ts-expect-error
5669
switchStatement.case(0)
5770
expectNotAssignable<Condition>(0)

src/condition.test.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,68 @@ test('Can match by properties', (t) => {
8080
)
8181
})
8282

83+
test('Can match by multiple booleans', (t) => {
84+
const switchStatement = BaseError.switch(0)
85+
t.false(
86+
switchStatement
87+
.case([false, false], suffix)
88+
.default()
89+
.message.endsWith(suffix),
90+
)
91+
t.true(
92+
switchStatement
93+
.case([false, true], suffix)
94+
.default()
95+
.message.endsWith(suffix),
96+
)
97+
t.true(
98+
switchStatement
99+
.case([true, false], suffix)
100+
.default()
101+
.message.endsWith(suffix),
102+
)
103+
t.true(
104+
switchStatement
105+
.case([true, true], suffix)
106+
.default()
107+
.message.endsWith(suffix),
108+
)
109+
})
110+
111+
test('Can match by multiple error names', (t) => {
112+
const oneError = new OneError('test')
113+
const switchStatement = BaseError.switch(oneError)
114+
t.false(
115+
switchStatement
116+
.case(['.', TwoError.name], suffix)
117+
.default()
118+
.message.endsWith(suffix),
119+
)
120+
t.true(
121+
switchStatement
122+
.case(['.', OneError.name], suffix)
123+
.default()
124+
.message.endsWith(suffix),
125+
)
126+
})
127+
128+
test('Can match by mixed conditions', (t) => {
129+
const oneError = new OneError('test')
130+
const switchStatement = BaseError.switch(oneError)
131+
t.false(
132+
switchStatement
133+
.case([false, TwoError.name], suffix)
134+
.default()
135+
.message.endsWith(suffix),
136+
)
137+
t.true(
138+
switchStatement
139+
.case([false, OneError.name], suffix)
140+
.default()
141+
.message.endsWith(suffix),
142+
)
143+
})
144+
83145
test('Exceptions in filters are propagated', (t) => {
84146
t.throws(BaseError.switch('').case.bind(undefined, unsafeFunc, suffix))
85147
})

src/main.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type { ErrorInstance, Info } from 'modern-errors'
77
* - An error
88
* [`name`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/name)
99
* string
10+
* - An object containing of subset of
11+
* [error properties](https://github.com/ehmicky/modern-errors#%EF%B8%8F-error-properties)
1012
* - A filtering function taking the `error` as argument and returning a
1113
* boolean
1214
* - A boolean
@@ -47,10 +49,10 @@ export type Effect =
4749
*/
4850
export interface Switch {
4951
/**
50-
* If `error` matches the `condition`, apply the `effects`.
52+
* If `error` matches the `conditions`, apply the `effects`.
5153
* 0, 1 or multiple effects can be applied.
5254
*/
53-
case: (condition: Condition, ...effects: Effect[]) => Switch
55+
case: (conditions: Condition | Condition[], ...effects: Effect[]) => Switch
5456

5557
/**
5658
* If none of the `.case()` statements matched, apply those default `effects`.

src/main.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { normalizeCondition } from './condition.js'
1+
import { normalizeConditions } from './condition.js'
22
import { normalizeEffects } from './effect.js'
33
import { switchFunctional } from './switch.js'
44

@@ -11,7 +11,7 @@ const patchSwitch = (originalSwitch, ErrorClass) => ({
1111
case: (condition, ...effects) =>
1212
patchSwitch(
1313
originalSwitch.case(
14-
normalizeCondition(condition),
14+
normalizeConditions(condition),
1515
normalizeEffects(effects, ErrorClass),
1616
),
1717
ErrorClass,

0 commit comments

Comments
 (0)