{"id":38860191,"url":"https://github.com/shuckster/match-iz","last_synced_at":"2026-01-17T14:21:17.154Z","repository":{"id":38787599,"uuid":"387059194","full_name":"shuckster/match-iz","owner":"shuckster","description":"A tiny pattern-matching library in the style of the TC39 proposal.","archived":false,"fork":false,"pushed_at":"2025-07-18T13:19:45.000Z","size":862,"stargazers_count":165,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-08-24T16:47:11.730Z","etag":null,"topics":["declarative-conditionals","javascript","match-when","pattern-matching","switch-case"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shuckster.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-07-18T00:14:35.000Z","updated_at":"2025-07-29T10:07:14.000Z","dependencies_parsed_at":"2025-07-17T07:59:08.265Z","dependency_job_id":"b6c76386-ee24-4496-91ac-0767c3e875f7","html_url":"https://github.com/shuckster/match-iz","commit_stats":{"total_commits":406,"total_committers":1,"mean_commits":406.0,"dds":0.0,"last_synced_commit":"eb8bad35b2594ad34627dd2cfdc76679d1c55440"},"previous_names":[],"tags_count":92,"template":false,"template_full_name":null,"purl":"pkg:github/shuckster/match-iz","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuckster%2Fmatch-iz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuckster%2Fmatch-iz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuckster%2Fmatch-iz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuckster%2Fmatch-iz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shuckster","download_url":"https://codeload.github.com/shuckster/match-iz/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuckster%2Fmatch-iz/sbom","scorecard":{"id":821447,"data":{"date":"2025-08-11","repo":{"name":"github.com/shuckster/match-iz","commit":"f60bb8f3a2b54b14b237255867bb335c7aafcb9a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.2,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-xffm-g5w8-qvg7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T15:42:41.439Z","repository_id":38787599,"created_at":"2025-08-23T15:42:41.439Z","updated_at":"2025-08-23T15:42:41.439Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28509942,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T13:38:16.342Z","status":"ssl_error","status_checked_at":"2026-01-17T13:37:44.060Z","response_time":85,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["declarative-conditionals","javascript","match-when","pattern-matching","switch-case"],"created_at":"2026-01-17T14:21:16.750Z","updated_at":"2026-01-17T14:21:17.129Z","avatar_url":"https://github.com/shuckster.png","language":"JavaScript","readme":"\u003ch1 align=\"center\"\u003e\u003ccode\u003ematch-iz\u003c/code\u003e 🔥\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/shuckster/match-iz/blob/master/LICENSE\"\u003e\n    \u003cimg\n      alt=\"MIT license\"\n      src=\"https://img.shields.io/npm/l/match-iz?style=plastic\"\n    /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/match-iz\"\u003e\n    \u003cimg\n      alt=\"Downloads per week\"\n      src=\"https://img.shields.io/npm/dw/match-iz?style=plastic\"\n    /\u003e\u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=match-iz\"\u003e\n    \u003cimg\n      alt=\"npm bundle size\"\n      src=\"https://img.shields.io/bundlephobia/minzip/match-iz?style=plastic\"\n    /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/match-iz\"\u003e\n    \u003cimg\n      alt=\"Version\"\n      src=\"https://img.shields.io/npm/v/match-iz?style=plastic\"\n    /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA tiny functional, declarative [pattern-matching](https://github.com/tc39/proposal-pattern-matching) library.\n\n- 👋 [Introduction](#introduction)\n- 👩‍🏫 [Before / After Examples](#before--after-examples)\n- 🏁 [Benchmarks](#benchmarks)\n- 📀 [Install / Use](#install--use)\n- 📖 [Documentation](https://github.com/shuckster/match-iz/wiki)\n- ✍️ [Credits](#credits)\n- 📃 [License](#license)\n\n## Introduction\n\nPattern-matching is a declarative version of `if` and `switch`, where you describe the expected shape of your data using \"patterns\".\n\n```javascript\nimport { match, when, otherwise } from 'match-iz'\n\nlet result = match(data)(\n  when(pattern, result || handler),\n  when(pattern, result || handler),\n  otherwise(result || handler)\n)\n```\n\nPatterns are a combination of both functions and data, and because of this certain assumptions can be made by `match-iz` to help reduce the amount of boilerplate normally required to check that your data looks a certain way:\n\n```javascript\n// Imperative:\nif (typeof res?.statusCode === 'number') {\n  if (res.statusCode \u003e= 200 \u0026\u0026 res.statusCode \u003c 300) {\n    return res.body\n  }\n}\n\n// Declarative:\nreturn match(res)(\n  when({ statusCode: inRange(200, 299) }, () =\u003e res.body),\n  otherwise(() =\u003e {})\n)\n```\n\n1. `match-iz` will check that `statusCode` is a key of `res` by implication of the `when()` being passed an object-literal `{ ... }`.\n\n2. The `inRange()` pattern-helper guards against non-numbers before trying to determine if its input is within a certain range.\n\nMany [pattern-helpers](https://github.com/shuckster/match-iz/wiki) are provided to permit you to express terse, declarative, and reusable (just pop them into variables/constants) patterns.\n\nHere are some of the date ones:\n\n```javascript\nconst isLastSundayOfMarch = allOf(nthSun(-1), isMar)\nconst isTheWeekend = anyOf(allOf(isFri, isEvening), isSat, isSun)\n\nmatch(new Date())(\n  when(isLastSundayOfMarch, () =\u003e 'Last Sunday of March: Clocks go forward'),\n  when(isTheWeekend, () =\u003e 'Ladies and Gentlemen; The Weekend'),\n  otherwise(dateObj =\u003e {\n    return `The clock is ticking: ${dateObj.toString()}`\n  })\n)\n```\n\n[rest](https://github.com/shuckster/match-iz/wiki/Core-Library#rest) was introduced in `v5`:\n\n```javascript\n// For objects, use ...rest()\nmatch({ one: 1, two: 2, three: 3 })(\n  when({ one: 1, ...rest(isNumber) }, (_, rest) =\u003e {\n    console.log(rest);\n    // { two: 2, three: 3 }\n  }),\n)\n\n// For arrays, use rest()\nmatch([1, 2, 3])(\n  when([1, rest(isNumber)], (_, rest) =\u003e {\n    console.log(rest);\n    // [2, 3]\n  }),\n)\n```\n\nYou can browse a few more [examples below](#before--after-examples), and full [documentation is over on the Github Wiki](https://github.com/shuckster/match-iz/wiki).\n\n## Before / After Examples:\n\n- [getResponse()](#getresponse--testing-status-codes)\n- [performSearch()](#performsearch--overloaded-function-call)\n- [AccountPage()](#accountpage--react-component)\n- [calculateExpr()](#calculateexpr--regular-expressions)\n\n#### `getResponse` | Testing status-codes:\n\n\u003cdetails\u003e\n\u003csummary\u003eSee imperative equivalent\u003c/summary\u003e\n\n```text\nfunction getResponse(res) {\n  if (res \u0026\u0026 typeof res.statusCode === 'number') {\n    if (res.statusCode \u003e= 200 \u0026\u0026 res.statusCode \u003c 300) {\n      return res.body\n    } else if (res.statusCode === 404) {\n      return 'Not found'\n    }\n  }\n  throw new Error('Invalid response')\n}\n```\n\n\u003c/details\u003e\n\n```javascript\nfunction getResponse(res) {\n  return match(res)(\n    when({ statusCode: inRange(200, 299) }, () =\u003e res.body),\n    when({ statusCode: 404 }, () =\u003e 'Not found'),\n    otherwise(res =\u003e {\n      throw new Error(`Invalid response: ${res}`)\n    })\n  )\n}\n```\n\n#### `performSearch` | \"Overloaded\" function call:\n\n\u003cdetails\u003e\n\u003csummary\u003eSee imperative equivalent\u003c/summary\u003e\n\n```text\nfunction performSearch(...args) {\n  const [firstArg, secondArg] = args\n  if (args.length === 1) {\n    if (isString(firstArg)) {\n      return find({ pattern: firstArg })\n    }\n    if (isPojo(firstArg)) {\n      return find(firstArg)\n    }\n  }\n  if (args.length === 2 \u0026\u0026 isString(firstArg) \u0026\u0026 isPojo(secondArg)) {\n    return find({ pattern: firstArg, ...secondArg })\n  }\n  throw new Error('Invalid arguments')\n}\n```\n\n\u003c/details\u003e\n\n```javascript\nfunction performSearch(...args) {\n  return match(args)(\n    when(eq([isString]), ([pattern]) =\u003e find({ pattern })),\n    when(eq([isPojo]), ([options]) =\u003e find(options)),\n    when(eq([isString, isPojo]), ([pattern, options]) =\u003e\n      find({ pattern, ...options })\n    ),\n    otherwise(() =\u003e {\n      throw new Error('Invalid arguments')\n    })\n  )\n}\n```\n\n#### `AccountPage` | React Component:\n\n\u003cdetails\u003e\n\u003csummary\u003eSee imperative equivalent\u003c/summary\u003e\n\n```text\nfunction AccountPage(props) {\n  const { loading, error, data } = props || {}\n  const logout = !loading \u0026\u0026 !error \u0026\u0026 !data\n  return (\n    \u003c\u003e\n      {loading \u0026\u0026 \u003cLoading /\u003e}\n      {error \u0026\u0026 \u003cError {...props} /\u003e}\n      {data \u0026\u0026 \u003cPage {...props} /\u003e}\n      {logout \u0026\u0026 \u003cLogout /\u003e}\n    \u003c/\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n```javascript\nfunction AccountPage(props) {\n  return match(props)(\n    when({ loading: defined }, \u003cLoading /\u003e),\n    when({ error: defined }, \u003cError {...props} /\u003e),\n    when({ data: defined }, \u003cPage {...props} /\u003e),\n    otherwise(\u003cLogout /\u003e)\n  )\n}\n```\n\n#### `calculateExpr` | Regular Expressions:\n\n\u003cdetails\u003e\n\u003csummary\u003eSee imperative equivalent\u003c/summary\u003e\n\n```text\nfunction calculateExpr(expr) {\n  const rxAdd = /(?\u003cleft\u003e\\d+) \\+ (?\u003cright\u003e\\d+)/\n  const rxSub = /(?\u003cleft\u003e\\d+) \\- (?\u003cright\u003e\\d+)/\n  if (typeof expr === 'string') {\n    const addMatch = expr.match(rxAdd)\n    if (addMatch) {\n      const { left, right } = addMatch.groups\n      return add(left, right)\n    }\n    const subMatch = expr.match(rxAdd)\n    if (subMatch) {\n      const { left, right } = subMatch.groups\n      return subtract(left, right)\n    }\n  }\n  throw new Error(\"I couldn't parse that!\")\n}\n```\n\n\u003c/details\u003e\n\n```javascript\nfunction calculateExpr(expr) {\n  return match(expr)(\n    when(/(?\u003cleft\u003e\\d+) \\+ (?\u003cright\u003e\\d+)/, groups =\u003e\n      add(groups.left, groups.right)\n    ),\n    when(/(?\u003cleft\u003e\\d+) \\- (?\u003cright\u003e\\d+)/, groups =\u003e\n      subtract(groups.left, groups.right)\n    ),\n    otherwise(\"I couldn't parse that!\")\n  )\n}\n```\n\n## Benchmarks \n\nThere is a very small benchmarking suite that you can run yourself with:\n\n```sh\npnpm run bench\n```\n\nHere's a run to give you an example without needing to go anywhere else:\n\n```sh \ncalculateExpr_vanilla         165.63 ns/iter 163.72 ns  █\n                     (160.47 ns … 194.63 ns) 187.64 ns  █\n                     (603.13 kb … 608.66 kb) 512.93 kb ▄█▇▂▂▂▁▁▁▁▁▁▁▁▁▂▃▂▂▁▁\ncalculateExpr_matchiz_match   436.82 ns/iter 441.31 ns        █\n                     (418.42 ns … 689.60 ns) 479.57 ns  ▅     █▃\n                     (  2.65 mb …   2.86 mb) 879.46 kb ▆█▃▂▁▂▇██▄▂▁▁▁▁▁▁▁▁▁▁\ncalculateExpr_matchiz_against 380.36 ns/iter 389.14 ns  █▅\n                     (368.65 ns … 409.00 ns) 398.41 ns  ██▅         ██\n                     (  1.71 mb …   1.73 mb) 987.37 kb ▄███▇▄▃▁▁▂▂▁▅████▃▃▃▁\ncalculateExpr_tspattern       803.26 ns/iter 878.30 ns  ▄           █\n                       (632.93 ns … 1.24 µs) 995.19 ns  █           ██\n                     (  2.32 mb …   2.34 mb) 810.93 kb ▇█▁▁▁▁▁▁▁▁▂▁▆██▃▂▁▁▂▂\n\n                              ┌                                            ┐\n        calculateExpr_vanilla ┤ 165.63 ns\n  calculateExpr_matchiz_match ┤■■■■■■■■■■■■■■ 436.82 ns\ncalculateExpr_matchiz_against ┤■■■■■■■■■■■ 380.36 ns\n      calculateExpr_tspattern ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 803.26 ns\n                              └                                            ┘\n```\n\nThis compares `match-iz` with `ts-pattern`.\n\nOf course, when considering a library performance isn't the only thing that \nmight concern you. `ts-pattern` can calculate static-types for the patterns \ndescribed, while `match-iz` was written with JavaScripts dynamism in mind,\nand its TypeScript support is very basic and incomplete.\n\n# Install / Use:\n\n```\n$ pnpm i match-iz\n```\n\n```javascript\n// ESM\nimport { match, ...etc } from 'match-iz'\nimport { isSat, ...etc } from 'match-iz/dates'\nimport { isSat, ...etc } from 'match-iz/dates/utc'\n\n// CJS\nconst { match, ...etc } = require('match-iz')\n```\n\nBrowser/UMD:\n\n```html\n\u003cscript src=\"https://unpkg.com/match-iz/dist/match-iz.browser.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  const { match, ...etc } = matchiz\n  const { isSat, ...etc } = matchiz\n  const { isSat, ...etc } = matchiz.utc\n\u003c/script\u003e\n```\n\n## Documentation\n\nCheck out the [Github Wiki for complete documentation](https://github.com/shuckster/match-iz/wiki) of the library.\n\n## Credits\n\n`match-iz` was written by [Conan Theobald](https://github.com/shuckster/).\n\nI hope you found it useful! If so, I like [coffee ☕️](https://www.buymeacoffee.com/shuckster) :)\n\n## License\n\nMIT licensed: See [LICENSE](LICENSE)\n","funding_links":["https://www.buymeacoffee.com/shuckster"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuckster%2Fmatch-iz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshuckster%2Fmatch-iz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuckster%2Fmatch-iz/lists"}