@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 CHANGED
@@ -1,14 +1,15 @@
1
- image: node:12-alpine
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
- - npm publish --access public
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,2 @@
1
+ export { match, Match, MatchFn, MatchError } from './match';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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
@@ -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
@@ -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.1.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": "jest"
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
- "jest": "^26.5.3"
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
  }
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ plugins: ['@semantic-release/commit-analyzer', '@semantic-release/release-notes-generator', '@semantic-release/npm'],
3
+ branches: ['master', 'main']
4
+ }
@@ -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
@@ -1,3 +0,0 @@
1
- const {match} = require('./src/match')
2
-
3
- module.exports = {match}
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 }
@@ -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
- })