UNPKG

match-iz

Version:

A tiny pattern-matching library in the style of the TC39 proposal

882 lines (541 loc) 16.2 kB
# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased ## [5.0.7] - 2025-07-18 - Using `pluck()` now affects the type of the handler-argument. This is a WIP, it does not apply to all `when`-overloads. - Update types for `isStrictly`, `includedIn`, `falsy`, `truthy`, `includes`, `not`, `spread`, `defined`, `empty` ## [5.0.6] - 2025-07-17 - Fill-out some more JSDoc into the typedef files. ## [5.0.3] - 2025-07-04 - Added JSDoc descriptions/examples back into `index.d.ts` ## [5.0.2] - 2025-07-02 - Improved `index.d.ts` to give typings to `when()` callbacks and return-types for `match()` and `against()`. Not perfect, but better. ## [5.0.1] - 2025-01-14 ### Added - Very basic benchmarks. Use `pnpm run bench` ### Updated - README includes info about `rest` ## [5.0.0] - 2024-12-31 ### BREAKING - Exact array matches now require `eq`: ```javascript // // <= match-iz@4 behaviour // match([1, 2, 3])( when([1, 2], 1), when([1, 2, 3], 2), otherwise(3), ) // 2 (array-matching was exact by default) // // v5 behaviour onwards: // match([1, 2, 3])( when([1, 2], 1), when([1, 2, 3], 2), otherwise(3), ) // 1 (because array-matching is now partial) match([1, 2, 3])( when(eq([1, 2]), 1), when(eq([1, 2, 3]), 2), otherwise(3), ) // 2 (use `eq` to make array-matching exact) ``` Notice with v5 that array matching is now partial, hence the first example returning `1` instead of `2` as in `<=v4`. ### Added - `rest` introduced for slurping remaining values of arrays or objects: ```javascript // Objects match({ one: 1, two: 2, three: 3 })( when({ one: 1, ...rest(isNumber) }, (_, rest) => { console.log(rest); // { two: 2, three: 3 } }), ) // Arrays match([1, 2, 3])( when([1, rest(isNumber)], (_, rest) => { console.log(rest); // [2, 3] }), ) ``` Notice `rest()` is used for arrays, and `...rest()` for objects. You can omit the argument to `rest` to match/capture everything: ```javascript // Objects match({ one: 1, two: 2, three: 'three' })( when({ one: 1, ...rest() }, (_, rest) => { console.log(rest); // { two: 2, three: 'three' } }), ) // Arrays match([1, 2, 'three'])( when([1, rest()], (_, rest) => { console.log(rest); // [2, 'three'] }), ) ``` Caveat: `rest` cannot yet be nested in sub-arrays or sub-objects. ### Updated - `eq` now works with arrays as well as objects. Change made in order to support v5 `rest` helper, since that will require a breaking-change for which the updated `eq` is the fallback for. ```javascript match([1, 2, 3])( when(eq([1, 2]), 1), when(eq([1, 2, 3]), 2), otherwise(3), ) // 2 ``` ## [4.0.4] - 2024-04-14 ### Fixed - Adds types export to pkg.json#exports. Thanks to @olmesm. - Fix lint command ## [4.0.3] - 2024-01-23 ### Updated - `index.d.ts`: Updated to parse patterns into types when the input is sent into your `when` handlers: Some examples: ```typescript when({ one: 1 as const, two: isNumber }, (res) => { // res will be typed as = { one: 1, two: number } }) ``` ```javascript when({ name: isString, age: isNumber }, (res) => { // res will be typed as = { name: string, age: number } }) ``` You can have your own predicates conform by using the `is` keyword: ```typescript function isString(value: any): value is string { return typeof value === 'string'; } ``` ## [4.0.2] - 2023-11-16 ### Updated - `index.d.ts`: Pass `Input` into `TPattern` so we can get autocomplete in `when()`s. ## [4.0.1] - 2023-06-19 ### Fixed - 'months' was broken for `inTheNext/Future/Past` because the minutes RegExp got there first, making `inTheNext(6, 'months')` assume 6 minutes. ## [4.0.0] - 2023-06-03 ### BREAKING CHANGE - `matchiz` now includes a runtime exhaustiveness check. If no patterns match and no `otherwise` was specified, an error will be thrown. `4.0.0` is otherwise identical to `3.10.0`. ## [3.10.0] - 2023-03-11 ### Added - New date pattern-helpers: `inDay/s`, `inMonth/s`, `inYear/s` Usage: ```js let date = new Date(2021, 0, 1, 12, 0, 0) match(date)( when(inDay(new Date(2021, 0, 1)), 'January 1st 2021'), when(inDay(new Date(2021, 0, 2)), 'January 2nd 2021') ) ``` Use a 1-based month index by passing an array: ```js let date = new Date(2021, 0, 1, 12, 0, 0) match(date)( when(inDay([2021, 1, 1]), 'January 1st 2021'), when(inDay([2021, 1, 2]), 'January 2nd 2021') ) ``` The plural helpers accept arrays of date-objects and/or 1-based month-index arrays: ```js let date = new Date(2021, 0, 1, 12, 0, 0) match(date)( when(inDays([[2021, 1, 1], new Date(2021, 0, 2)]), 'January 1st or 2nd 2021') ) ``` ## [3.9.4] - 2022-10-14 ### Added - Test for browser build exports ### Fixed - Fix browser build ## [3.9.3] - 2022-10-12 ### Fixed - Fix browser build ## [3.9.2] - 2022-10-12 ### Added - Typedefs + JSDoc for `getIterationLimit` and `setIterationLimit` ## [3.9.1] - 2022-10-12 ### Fixed - Fix browser build. The following now exist on the `matchiz` object: `firstOf`, `lastOf`, `some`, `every`, `isStrictly`. ## [3.9.0] - 2022-10-12 ### Added - Now matches on `arguments` keyword - Now matches `Map`, `Set`, and iterators. See [PR for more details](https://github.com/shuckster/match-iz/pull/1). ## [3.8.1] - 2022-08-27 ### Fixed - Fix browser build ## [3.8.0] - 2022-06-23 ### Added - `eq` + `deepEq` for object equality comparison: ```js match({ one: '1', two: '2', three: '3' })( when({ one: '1', two: '2' }, 'partial match') ) // 'partial match' match({ one: '1', two: '2', three: '3' })( when(eq({ one: '1', two: '2' }), 'shallow match') ) // undefined match({ one: '1', two: '2', three: { four: '4', five: '5' } })( when( eq({ one: '1', two: '2', three: eq({ four: '4' }) }), 'deep match using nested eq()' ) ) // undefined match({ one: '1', two: '2', three: { four: '4', five: '5' } })( when( deepEq({ one: '1', two: '2', three: { four: '4' } }), 'deep match using deepEq()' ) ) // undefined ``` ## [3.7.1] - 2022-06-01 ### Added - `isStrictly` typedef ## [3.7.0] - 2022-06-01 ### Added - `isStrictly` exact-match pattern-helper ## [3.6.0] - 2022-05-31 ### Updated - Implement basic generics into the typedefs ### Fixed - Remove deprecated form of `anyOf()` from JSDoc - Use uncurried form of `when()` in JSDoc ## [3.5.4] - 2022-05-03 ### Fixed - `when()` typedef overloads were not working properly ## [3.5.3] - 2022-04-26 ### Updated - Simplify README, link to [Wiki](https://github.com/shuckster/match-iz/wiki) for further docs ## [3.5.0] - 2022-04-23 ### Added - `isBefore()` / `isAfter()` date matchers: ```js match(new Date())( when(isBefore([2001, 1, 1]))('Before midnight January 1st, 2001'), when(isAfter([1970, 5]))('After May 1970 (ie; June onwards)'), when(isBefore([1999]))('Before 1999 (ie; up to and including 1998)'), when(isAfter(new Date(2001, 0, 1)))('After midnight January 1st, 2001') ) ``` ## [3.4.2] - 2022-04-21 ### Fixed - Add missing typedefs ## [3.4.1] - 2022-04-20 ### Fixed - Add missing exports to the browser-build ## [3.4.0] - 2022-04-19 ### Added - `every()` / `some()` for matching patterns in array haystacks: ```js match(array)( when(every(isNumber))('all items are numbers'), when(some(isNumber))('some items are numbers'), when(every({ id: isNumber }))('all items have an id property') ) ``` ## [3.3.1] - 2022-04-15 ### Removed / Fixed - Remove `browser` setting from `package.json`; seems to cause issues with CodeSandbox build process, and isn't really necessary since the browser-build is something that's interacted with manually. ## [3.3.0] - 2022-04-14 ### Added - `inTheFuture` alias for `inTheNext` - `inTheFuture` + `inThePast` can be used without arguments now ## [3.2.2] - 2022-04-14 ### Updated - README tweaks, typos ## [3.2.0] - 2022-04-14 ### Added - `firstOf()` and `lastOf()` matchers: ```js match([1, 'a', 3, 4, 5, 6])( when(lastOf(isNumber, isString), () => { return 'last two items are a number and a string' }), when(firstOf(isNumber, isString), () => { return 'first two items are a number and a string' }) ) ``` - Support `when` guards, which are essentially just consecutive patterns: ```js match(haystack)( when(isNumber, gt(5), lte(10), num => { return 'a number between 6 and 10' }), when(isString, startsWith('a'), str => { return 'a string starting with "a"' }), when(isArray, lastOf(isNumber, isNumber), arr => { return 'the last two elements of the array are numbers' }) ) ``` ## [3.1.0] - 2022-04-12 ### Added - `isTime` for testing milliseconds since Unix epoch - New `match-iz/dates` methods for testing time-frames relative to now: ```js match(date)( // Test if a date is in the past when(inThePast(1, 'day'))(...), when(inThePast(2, 'days'))(...), // Test if a date is in the future when(inTheNext(30, 'minutes'))(...), ) ``` ### Removed - Old `isDate`/`isTime` typedefs were left behind ## [3.0.0] - 2022-04-09 ### Removed - Remove `isDate`/`isTime`. `isDate` conflicted with the same function in `types`, and could not have matchers passed into it in the same way as the individual helpers. ie; `isDate(inRange(), anyOf(), ...)` was not possible. - Removed deprecated `when` OR syntax that abuses arrays. Use `anyOf` matcher instead. ```js // Deprecated syntax: when([allOf(isFri, isHour(gte(17)), isSat, isSun)]) // ^__ _ _ _ _ __^ // Refactored using `anyOf`: when(anyOf(allOf(isFri, isHour(gte(17))), isSat, isSun)) // ^^^^^^__ _ _ _ _ __^ ``` ### Updated - `when` now accepts a result/handler as its second argument: ```js // New syntax: when(literalOrPattern, resultOrHandler) match(new Date())( when(allOf(nthSun(-1), isMar), dateObj => { return 'Last Sunday of March: Clocks go forward' }), when(anyOf(allOf(isFri, isHour(gte(17))), isSat, isSun), () => { return 'Ladies and Gentlemen; The Weekend' }), otherwise('The clock is ticking') ) // Existing syntax (still works): when(literalOrPattern)(resultOrHandler) match(new Date())( when(allOf(nthSun(-1), isMar))(dateObj => { return 'Last Sunday of March: Clocks go forward' }), when(anyOf(allOf(isFri, isHour(gte(17))), isSat, isSun))(() => { return 'Ladies and Gentlemen; The Weekend' }), otherwise('The clock is ticking') ) ``` ## [2.3.2] - 2022-04-07 ### Fixed - README typos, fixes ## [2.3.0] - 2022-04-07 ### Added - Simple date matchers now available in `match-iz/dates` and `match-iz/dates/utc` ## [2.2.0] - 2022-03-21 ### Updated - Permit use of anyOf() as standalone function instead of just match-iz pattern, eg: ```js // Before 2.2.0 const isStringOrRegExp = anyOf(isString, isRegExp) // [isString, isRegExp] // After 2.2.0 const isStringOrRegExp = anyOf(isString, isRegExp) // <Function> isStringOrRegExp('foo') // true isStringOrRegExp(/foo/) // true ``` ## [2.1.0] - 2022-03-06 ### Updated - inRange() will work with min/max swapped ## [2.0.7] - 2022-02-10 ### Fixed - README typo ## [2.0.6] - 2022-02-10 ### Updated - README cleanup ## [2.0.5] - 2022-02-08 ### Updated - README tweaks, update deps ## [2.0.4] - 2022-02-06 ### Fixed - Include package.json for sub-modules. ## [2.0.3] - 2022-02-06 ### Fixed - Another run at fixing import vs. require. ## [2.0.2] - 2022-02-03 ### Fixed - Fix .d.ts for allOf, anyOf, includedIn, hasOwn ## [2.0.1] - 2022-02-03 ### Fixed - Added isDate() to .d.ts ## [2.0.0] - 2022-02-01 ### Breaking Changes - If specified, named RegExp-groups will be passed-in to `when` handlers as the first argument, and the full-match the second. Before v2: ```js when(/(?<foo>.*)/)(fullMatch => { const foo = fullMatch.groups.foo console.log(foo) }) ``` After v2: ```js when(/(?<foo>.*)/)(({ foo }, fullMatch) => { console.log(foo) }) ``` - RegExps without named-groups work as before, with the full-match being the first and only argument to the handler. ## [1.12.0] - 2022-01-12 ### Added - cata() helper for integration with ADTs/monads ## [1.11.2] - 2022-01-11 ### Fixed - Fix esbuild errors by re-ordering package.json exports ## [1.11.1] - 2022-01-10 ### Updated - esbuild output was different after deps-update for the browser-build ## [1.11.0] - 2021-12-28 ### Added - isDate ## [1.10.4] - 2021-12-21 ### Fixed - Fix WebPack error: "Default condition should be last one" ## [1.10.3] - 2021-11-26 ### Updated - Above-the-fold README tweaks ## [1.10.2] - 2021-10-29 ### Fixed - Whoops, README example condition for >=500 will not run ## [1.10.1] - 2021-10-29 ### Updated - README example tweaks ## [1.10.0] - 2021-10-24 ### Added - pluck(predicate?) helper to extract a part of the haystack - instanceOf(constructor) helper ## [1.9.0] - 2021-10-23 ### Added - hasOwn(prop1, prop2...) helper ## [1.8.2] - 2021-10-18 ### Fixed - isNumber(NaN) should return false ## [1.8.1] - 2021-10-02 ### Updated - Tweak README - Mild code shrinking ## [1.8.0] - 2021-09-20 ### Added - allOf(), anyOf(), includedIn() ## [1.7.3] - 2021-09-14 ### Updated - Minor cleanup ## [1.7.2] - 2021-09-11 ### Updated - `not()` type definition ## [1.7.1] - 2021-09-10 ### Updated - `not()` can be used with literals as well as functions ## [1.7.0] - 2021-09-10 ### Added - `not()` will negate the output of a function ## [1.6.4] - 2021-08-18 ### Updated - README: Compact full examples into details/summary tags ## [1.6.3] - 2021-08-10 ### Fixed - We're exposing CJS as well as ESM, so use .mjs instead of "type": "module" for build/source files. Fixes CJS imports ## [1.6.2] - 2021-08-10 ### Fixed - Use ESM for source/build files - Fix ESM build (import { ... } from 'match-iz' was not working right) ## [1.6.1] - 2021-08-09 ### Updated - Will do the right thing with `NaN` - Can handle sub-arrays as well as sub-pojos ## [1.6.0] - 2021-08-09 ### Updated - When matching array-to-array, ensure exact lengths before comparing contents to make matches more predictable. Comparing variable length arrays is done better via a custom when-predicate ## [1.5.0] - 2021-08-09 ### Added - Can now match against contents of an array ## [1.4.1] - 2021-08-08 ### Added - Add runtime type checkers to index.d.ts ## [1.4.0] - 2021-08-07 ### Updated - Export runtime type checkers, why not ## [1.3.6] - 2021-07-24 ### Updated - NPM tags, README tweaks, no functional changes ## [1.3.5] - 2021-07-24 ### Fixed - Remove @params / @returns from JSDoc comments - fixes duplicate Intellisense suggestions ## [1.3.4] - 2021-07-24 ### Added - `index.d.ts` against() example ## [1.3.3] - 2021-07-23 ### Added - Basic `index.d.ts` for type hints and examples ## [1.3.2] - 2021-07-22 ### Fixed - otherwise() was returning all falsy values as `undefined` ## [1.3.1] - 2021-07-21 ### Updated - Updated test for nested patterns - Remove superfluous coercion ## [1.3.0] - 2021-07-21 ### Added - Support nested objects for patterns ## [1.2.1] - 2021-07-20 ### Updated - unpkg example in README ## [1.2.0] - 2021-07-19 ### Removed - Literals already cover use-case for isTrue/isFalse ## [1.1.2] - 2021-07-19 ### Updated - README: Above the fold examples ## [1.1.1] - 2021-07-18 ### Fixed - inRange() should check that value isNumber, not min/max ## [1.1.0] - 2021-07-18 ### Fixed - empty() should not include 'false' ### Added - Provide truthy/falsy/isTrue/isFalse ## [1.0.4] - 2021-07-18 ### Fixed - Update README to include correct empty/defined usage ## [1.0.3] - 2021-07-18 ### Fixed - defined, empty, spead() - More complete empty() - Number.isNumber() is not a thing ## [1.0.2] - 2021-07-18 ### Fixed - RegExps guard for strings - spread() should not mutate its argument ## [1.0.1] - 2021-07-18 ### Fixed - Browser-build global now `matchiz`, not `matches` ## [1.0.0] - 2021-07-18 ### Added - match-iz :)