@othree.io/cerillo 0.1.0 → 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.
- package/.gitlab-ci.yml +7 -4
- package/README.md +108 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/match.d.ts +29 -0
- package/lib/match.d.ts.map +1 -0
- package/lib/match.js +59 -0
- package/lib/match.js.map +1 -0
- package/package.json +19 -4
- package/release.config.js +4 -0
- package/vitest.config.ts +18 -0
- package/index.js +0 -3
- package/src/match.js +0 -46
- package/test/match.test.js +0 -42
package/.gitlab-ci.yml
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
image: node:
|
|
1
|
+
image: node:20
|
|
2
2
|
|
|
3
3
|
cache:
|
|
4
4
|
key: ${CI_PIPELINE_ID}
|
|
5
5
|
paths:
|
|
6
6
|
- node_modules/
|
|
7
|
+
- lib/
|
|
7
8
|
|
|
8
9
|
build:
|
|
9
10
|
stage: build
|
|
10
11
|
script:
|
|
11
|
-
- npm install
|
|
12
|
+
- npm install && npm run build
|
|
12
13
|
|
|
13
14
|
test:
|
|
14
15
|
stage: test
|
|
@@ -17,9 +18,11 @@ test:
|
|
|
17
18
|
|
|
18
19
|
deploy:
|
|
19
20
|
stage: deploy
|
|
21
|
+
variables:
|
|
22
|
+
NPM_CONFIG_USERCONFIG: '$CI_PROJECT_DIR/.npmrc'
|
|
20
23
|
script:
|
|
21
24
|
- cat $NPM > .npmrc
|
|
22
|
-
-
|
|
25
|
+
- npx semantic-release
|
|
23
26
|
only:
|
|
24
27
|
refs:
|
|
25
|
-
- master
|
|
28
|
+
- master
|
package/README.md
CHANGED
|
@@ -1,2 +1,110 @@
|
|
|
1
1
|
# cerillo
|
|
2
2
|
|
|
3
|
+
A lightweight, lazy, and fully typed pattern-matching library for TypeScript. Matches are built as chainable expressions and only evaluated when you call `get`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @othree.io/cerillo
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Peer dependency: [`@othree.io/optional`](https://www.npmjs.com/package/@othree.io/optional) ^2.3.3
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Literal matching with `is`
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { match } from '@othree.io/cerillo'
|
|
19
|
+
|
|
20
|
+
const result = match<string, string>('hello')
|
|
21
|
+
.is('hello').then(_ => 'Hi there!')
|
|
22
|
+
.is('bye').then(_ => 'Goodbye!')
|
|
23
|
+
.get()
|
|
24
|
+
|
|
25
|
+
result.get() // 'Hi there!'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`is` accepts multiple values:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
const result = match<string, string>('b')
|
|
32
|
+
.is('a', 'b', 'c').then(_ => 'Matched!')
|
|
33
|
+
.getOrThrow() // 'Matched!'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Conditional matching with `when`
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const result = match<number, string>(42)
|
|
40
|
+
.when(n => n > 100).then(_ => 'big')
|
|
41
|
+
.when(n => n > 0).then(_ => 'positive')
|
|
42
|
+
.otherwise(_ => 'non-positive')
|
|
43
|
+
.getOrThrow() // 'positive'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Type narrowing
|
|
47
|
+
|
|
48
|
+
`when` supports type-guard callbacks, narrowing the type in the `then` branch:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
type Shape =
|
|
52
|
+
| { kind: 'circle'; radius: number }
|
|
53
|
+
| { kind: 'rectangle'; width: number; height: number }
|
|
54
|
+
|
|
55
|
+
const isCircle = (s: Shape): s is { kind: 'circle'; radius: number } =>
|
|
56
|
+
s.kind === 'circle'
|
|
57
|
+
|
|
58
|
+
const area = match<Shape, number>(shape)
|
|
59
|
+
.when(isCircle).then(c => Math.PI * c.radius ** 2) // c is narrowed
|
|
60
|
+
.when(isRectangle).then(r => r.width * r.height) // r is narrowed
|
|
61
|
+
.getOrThrow()
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Default / otherwise
|
|
65
|
+
|
|
66
|
+
Provide a fallback with `default` or its alias `otherwise`:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
match<string, string>('unknown')
|
|
70
|
+
.is('a').then(_ => 'A')
|
|
71
|
+
.default(_ => 'fallback')
|
|
72
|
+
.getOrThrow() // 'fallback'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Async matching
|
|
76
|
+
|
|
77
|
+
When `then` callbacks return promises, use `getAsync` or `getAsyncOrThrow`:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const result = await match<string, Promise<string>>('hello')
|
|
81
|
+
.is('hello').then(async _ => fetchGreeting())
|
|
82
|
+
.getAsyncOrThrow() // resolves to the greeting
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API
|
|
86
|
+
|
|
87
|
+
### `match<A, B>(value: A): Match<A, B>`
|
|
88
|
+
|
|
89
|
+
Creates a new match expression for `value`.
|
|
90
|
+
|
|
91
|
+
### `Match<A, B>`
|
|
92
|
+
|
|
93
|
+
| Method | Returns | Description |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `.is(...expected)` | `{ then }` | Match against one or more literal values |
|
|
96
|
+
| `.when(callback)` | `{ then }` | Match when callback returns `true` (supports type guards) |
|
|
97
|
+
| `.default(callback)` | `Match<A, B>` | Set a fallback handler |
|
|
98
|
+
| `.otherwise(callback)` | `Match<A, B>` | Alias for `default` |
|
|
99
|
+
| `.get()` | `Optional<B>` | Evaluate and return the result wrapped in `Optional` |
|
|
100
|
+
| `.getOrThrow()` | `B` | Evaluate and return the result, throws `MatchError` on no match |
|
|
101
|
+
| `.getAsync()` | `Promise<Optional<Awaited<B>>>` | Evaluate async and return the result wrapped in `Optional` |
|
|
102
|
+
| `.getAsyncOrThrow()` | `Promise<Awaited<B>>` | Evaluate async, rejects with `MatchError` on no match |
|
|
103
|
+
|
|
104
|
+
### `MatchError`
|
|
105
|
+
|
|
106
|
+
Thrown (or used as the `Optional` error) when no pattern matches and no default is defined.
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
ISC
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MatchError = exports.match = void 0;
|
|
4
|
+
var match_1 = require("./match");
|
|
5
|
+
Object.defineProperty(exports, "match", { enumerable: true, get: function () { return match_1.match; } });
|
|
6
|
+
Object.defineProperty(exports, "MatchError", { enumerable: true, get: function () { return match_1.MatchError; } });
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iCAA2D;AAAlD,8FAAA,KAAK,OAAA;AAAkB,mGAAA,UAAU,OAAA"}
|
package/lib/match.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Optional } from '@othree.io/optional';
|
|
2
|
+
type ThenCallback<A, B> = (value: A) => B;
|
|
3
|
+
type WhenCallback<A> = (value: A) => boolean;
|
|
4
|
+
export declare class MatchError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export type Match<A, B> = Readonly<{
|
|
8
|
+
get: () => Optional<B>;
|
|
9
|
+
getOrThrow: () => B;
|
|
10
|
+
getAsync: () => Promise<Optional<Awaited<B>>>;
|
|
11
|
+
getAsyncOrThrow: () => Promise<Awaited<B>>;
|
|
12
|
+
is: (...expected: ReadonlyArray<A>) => Readonly<{
|
|
13
|
+
then: (callback: ThenCallback<A, B>) => Match<A, B>;
|
|
14
|
+
}>;
|
|
15
|
+
when: {
|
|
16
|
+
<S extends A>(callback: (value: A) => value is S): Readonly<{
|
|
17
|
+
then: (callback: (value: S) => B) => Match<A, B>;
|
|
18
|
+
}>;
|
|
19
|
+
(callback: WhenCallback<A>): Readonly<{
|
|
20
|
+
then: (callback: ThenCallback<A, B>) => Match<A, B>;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
default: (callback: ThenCallback<A, B>) => Match<A, B>;
|
|
24
|
+
otherwise: (callback: ThenCallback<A, B>) => Match<A, B>;
|
|
25
|
+
}>;
|
|
26
|
+
export type MatchFn = <A, B>(value: A) => Match<A, B>;
|
|
27
|
+
export declare const match: MatchFn;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=match.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAS,MAAM,qBAAqB,CAAA;AAErD,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;AACzC,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAA;AAE5C,qBAAa,UAAW,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAU9B;AAOD,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC;IAC/B,GAAG,EAAE,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAA;IACtB,UAAU,EAAE,MAAM,CAAC,CAAA;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7C,eAAe,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1C,EAAE,EAAE,CAAC,GAAG,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC;QAC5C,IAAI,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;KACtD,CAAC,CAAA;IACF,IAAI,EAAE;QACF,CAAC,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC;YACxD,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;SACnD,CAAC,CAAA;QACF,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;YAClC,IAAI,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;SACtD,CAAC,CAAA;KACL,CAAA;IACD,OAAO,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACtD,SAAS,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAC3D,CAAC,CAAA;AAEF,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AA+CrD,eAAO,MAAM,KAAK,EAAE,OACuB,CAAA"}
|
package/lib/match.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.match = exports.MatchError = void 0;
|
|
13
|
+
const optional_1 = require("@othree.io/optional");
|
|
14
|
+
class MatchError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
const ErrorWithCapture = Error;
|
|
18
|
+
if (ErrorWithCapture.captureStackTrace) {
|
|
19
|
+
ErrorWithCapture.captureStackTrace(this, MatchError);
|
|
20
|
+
}
|
|
21
|
+
this.name = 'MatchError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.MatchError = MatchError;
|
|
25
|
+
const createMatch = (value, patterns, defaultCallback) => {
|
|
26
|
+
const get = () => (0, optional_1.Optional)(patterns.find(p => p.when(value)))
|
|
27
|
+
.map(pattern => pattern.then(value))
|
|
28
|
+
.orMap(() => (0, optional_1.Optional)(defaultCallback).map(cb => cb(value)))
|
|
29
|
+
.orMap(() => (0, optional_1.Empty)(new MatchError(`Nothing matched for value: ${value}`)));
|
|
30
|
+
const getAsync = () => (0, optional_1.Optional)(patterns.find(p => p.when(value)))
|
|
31
|
+
.map(pattern => pattern.then)
|
|
32
|
+
.orMap(() => (0, optional_1.Optional)(defaultCallback))
|
|
33
|
+
.mapAsync((cb) => __awaiter(void 0, void 0, void 0, function* () { return yield cb(value); }))
|
|
34
|
+
.then(opt => opt.orMap(() => (0, optional_1.Empty)(new MatchError(`Nothing matched for value: ${value}`))));
|
|
35
|
+
const defaultFn = (callback) => createMatch(value, patterns, callback);
|
|
36
|
+
return {
|
|
37
|
+
get,
|
|
38
|
+
getOrThrow: () => get().get(),
|
|
39
|
+
getAsync,
|
|
40
|
+
getAsyncOrThrow: () => getAsync().then(opt => opt.get()),
|
|
41
|
+
is: (...expected) => ({
|
|
42
|
+
then: (thenCallback) => createMatch(value, patterns.concat([{
|
|
43
|
+
when: (v) => expected.some(e => e === v),
|
|
44
|
+
then: thenCallback
|
|
45
|
+
}]), defaultCallback)
|
|
46
|
+
}),
|
|
47
|
+
when: (validationCallback) => ({
|
|
48
|
+
then: (thenCallback) => createMatch(value, patterns.concat([{
|
|
49
|
+
when: validationCallback,
|
|
50
|
+
then: thenCallback
|
|
51
|
+
}]), defaultCallback)
|
|
52
|
+
}),
|
|
53
|
+
default: defaultFn,
|
|
54
|
+
otherwise: defaultFn
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const match = (value) => createMatch(value, [], undefined);
|
|
58
|
+
exports.match = match;
|
|
59
|
+
//# sourceMappingURL=match.js.map
|
package/lib/match.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@othree.io/cerillo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Matching library",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./lib/index.d.ts",
|
|
10
|
+
"import": "./lib/index.js",
|
|
11
|
+
"require": "./lib/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
6
14
|
"scripts": {
|
|
7
|
-
"test": "
|
|
15
|
+
"test": "vitest run --coverage",
|
|
16
|
+
"build": "tsc"
|
|
8
17
|
},
|
|
9
18
|
"repository": {
|
|
10
19
|
"type": "git",
|
|
@@ -21,7 +30,13 @@
|
|
|
21
30
|
"url": "https://gitlab.com/othree.oss/cerillo/issues"
|
|
22
31
|
},
|
|
23
32
|
"homepage": "https://gitlab.com/othree.oss/cerillo#readme",
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@othree.io/optional": "^2.3.3"
|
|
35
|
+
},
|
|
24
36
|
"devDependencies": {
|
|
25
|
-
"
|
|
37
|
+
"@othree.io/optional": "^2.3.3",
|
|
38
|
+
"@vitest/coverage-v8": "^3.0.0",
|
|
39
|
+
"typescript": "^5.0.0",
|
|
40
|
+
"vitest": "^3.0.0"
|
|
26
41
|
}
|
|
27
42
|
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
coverage: {
|
|
6
|
+
provider: 'v8',
|
|
7
|
+
reporter: ['text', 'json', 'html'],
|
|
8
|
+
all: true,
|
|
9
|
+
include: ['src/**/*.ts'],
|
|
10
|
+
thresholds: {
|
|
11
|
+
lines: 100,
|
|
12
|
+
functions: 100,
|
|
13
|
+
branches: 100,
|
|
14
|
+
statements: 100
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
})
|
package/index.js
DELETED
package/src/match.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
function unboundMatch(value) {
|
|
2
|
-
const patterns = []
|
|
3
|
-
let def = undefined
|
|
4
|
-
|
|
5
|
-
const when = function (validationCallback) {
|
|
6
|
-
const then = function (thenCallback) {
|
|
7
|
-
patterns.push({
|
|
8
|
-
when: validationCallback,
|
|
9
|
-
then: thenCallback
|
|
10
|
-
})
|
|
11
|
-
return this
|
|
12
|
-
}.bind(this)
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
then
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
const defaultMatch = function(callback) {
|
|
19
|
-
def = callback
|
|
20
|
-
|
|
21
|
-
return this
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const response = {
|
|
25
|
-
get: () => {
|
|
26
|
-
const pattern = patterns.find(pattern => pattern.when(value))
|
|
27
|
-
if (pattern) {
|
|
28
|
-
return pattern.then(value)
|
|
29
|
-
} else {
|
|
30
|
-
if (def) {
|
|
31
|
-
return def(value)
|
|
32
|
-
} else {
|
|
33
|
-
throw new Error(`Nothing matched for value: ${value}`)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
response.when = when.bind(response)
|
|
40
|
-
response.default = defaultMatch.bind(response)
|
|
41
|
-
return response
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const match = unboundMatch.bind(unboundMatch)
|
|
45
|
-
|
|
46
|
-
module.exports = { match }
|
package/test/match.test.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const {match} = require('../src/match')
|
|
2
|
-
|
|
3
|
-
describe('match', () => {
|
|
4
|
-
|
|
5
|
-
const expectations = [
|
|
6
|
-
{
|
|
7
|
-
value: 'bye',
|
|
8
|
-
expectation: 'MEANT TO SAY GOODBYE'
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
value: 'hello',
|
|
12
|
-
expectation: 'HELLO'
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
value: 'unexpected',
|
|
16
|
-
expectation: 'DEFAULT VALUE'
|
|
17
|
-
}
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
expectations.forEach(expectation => {
|
|
21
|
-
it(`should match ${expectation.value} and return the expected value`, () => {
|
|
22
|
-
|
|
23
|
-
const result = match(expectation.value)
|
|
24
|
-
.when(_ => _ === 'bye').then(_ => 'MEANT TO SAY GOODBYE')
|
|
25
|
-
.when(_ => _ === 'hello').then(_ => _.toUpperCase())
|
|
26
|
-
.default(_ => 'DEFAULT VALUE')
|
|
27
|
-
.get()
|
|
28
|
-
|
|
29
|
-
expect(result).toStrictEqual(expectation.expectation)
|
|
30
|
-
})
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('throw an error if there is no match and no default defined', () => {
|
|
34
|
-
const value = 'unexpected'
|
|
35
|
-
const lazyMatch = match(value)
|
|
36
|
-
.when(_ => _ === 'bye').then(_ => 'MEANT TO SAY GOODBYE')
|
|
37
|
-
.when(_ => _ === 'hello').then(_ => _.toUpperCase())
|
|
38
|
-
|
|
39
|
-
expect(() => lazyMatch.get()).toThrow(`Nothing matched for value: ${value}`)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
})
|