{"id":16182647,"url":"https://github.com/csvenke/compose-rules","last_synced_at":"2025-03-16T10:31:45.928Z","repository":{"id":37032945,"uuid":"254364834","full_name":"csvenke/compose-rules","owner":"csvenke","description":"Dead simple helpers for writing composable rules","archived":false,"fork":false,"pushed_at":"2024-05-14T08:04:08.000Z","size":1581,"stargazers_count":6,"open_issues_count":17,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-05-14T09:27:30.576Z","etag":null,"topics":["compose","composition","helpers","javascript","library","npm-package","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@csvenke/compose-rules","language":"TypeScript","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/csvenke.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2020-04-09T12:26:42.000Z","updated_at":"2024-05-14T09:27:32.199Z","dependencies_parsed_at":"2024-02-14T13:27:16.970Z","dependency_job_id":"6516f1c4-8a2f-4115-8399-c6d2d8e00114","html_url":"https://github.com/csvenke/compose-rules","commit_stats":{"total_commits":445,"total_committers":5,"mean_commits":89.0,"dds":"0.18651685393258421","last_synced_commit":"a5ca3d55f40915629964f2372cceb8f0587b0001"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/csvenke%2Fcompose-rules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/csvenke%2Fcompose-rules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/csvenke%2Fcompose-rules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/csvenke%2Fcompose-rules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/csvenke","download_url":"https://codeload.github.com/csvenke/compose-rules/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243814895,"owners_count":20352036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["compose","composition","helpers","javascript","library","npm-package","typescript"],"created_at":"2024-10-10T06:43:30.174Z","updated_at":"2025-03-16T10:31:45.654Z","avatar_url":"https://github.com/csvenke.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\" style=\"border-bottom: none;\"\u003e@csvenke/compose-rules\u003c/h1\u003e\n\u003ch3 align=\"center\"\u003eDead simple helpers for writing composable rules\u003c/h3\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@csvenke/compose-rules\"\u003e\n    \u003cimg src=\"https://badgen.net/npm/v/@csvenke/compose-rules\" alt=\"npm package\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=@csvenke/compose-rules\"\u003e\n    \u003cimg src=\"https://badgen.net/bundlephobia/min/@csvenke/compose-rules\" alt=\"min bundle size\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/csvenke/compose-rules/actions?query=workflow%3Amaster\"\u003e\n    \u003cimg src=\"https://github.com/csvenke/compose-rules/workflows/master/badge.svg\" alt=\"master workflow\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/csvenke/compose-rules/actions?query=workflow%3A%22pull+request%22\"\u003e\n    \u003cimg src=\"https://github.com/csvenke/compose-rules/workflows/pull%20request/badge.svg\" alt=\"pull request workflow\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/semantic-release/semantic-release\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\" alt=\"semantic release\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#overview\"\u003eOverview\u003c/a\u003e •\n  \u003ca href=\"#install\"\u003eInstall\u003c/a\u003e •\n  \u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e •\n  \u003ca href=\"#documentation\"\u003eDocumentation\u003c/a\u003e •\n  \u003ca href=\"#why\"\u003eWhy\u003c/a\u003e •\n  \u003ca href=\"#development\"\u003eDevelopment\u003c/a\u003e •\n  \u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e •\n  \u003ca href=\"#license\"\u003eLicense\u003c/a\u003e\n\u003c/p\u003e\n\n**@csvenke/compose-rules** provides dead simple helpers for writing composable rules.\nAttack complex problems by dividing them into smaller easier problems.\n\n\u003e \"Nothing is particularly hard if you divide it into small jobs\" - [Henry Ford](https://no.wikipedia.org/wiki/Henry_Ford)\n\n## Overview\n\n- Compose your rules with a dead simple API!\n\n```js\nimport { and, or, not } from \"@csvenke/compose-rules\";\n\nconst myRule = and(myRule1, or(myRule2, myRule3), not(myRule4));\n```\n\n- Rich typescript support!\n\n```ts\nimport { and, Rule } from \"@csvenke/compose-rules\";\n\ntype MyRule = Rule\u003c[string, string]\u003e;\n\nconst myRule1: MyRule = (firstName, lastName) =\u003e true;\n\nconst myRule2: MyRule = (firstName, lastName) =\u003e true;\n\n// type inference from first rule!\nconst myRule = and(myRule1, myRule2);\n\nmyRule(\"John\", \"Doe\"); // Ok!\nmyRule(\"John\"); // Error!\n```\n\n- No dependencies!\n- Tiny bundle size!\n- Tree shakeable and side effect free!\n- 100% test coverage!\n\n## Install\n\nUsing npm\n\n```\nnpm install --save @csvenke/compose-rules\n```\n\nUsing yarn\n\n```\nyarn add @csvenke/compose-rules\n```\n\n## Usage\n\n[Try it out online with repl.it!](https://repl.it/@csvenke/PunyCalculatingServers)\n\n```js\nimport { and } from \"@csvenke/compose-rules\";\n\nconst isLargerThanOne = n =\u003e n \u003e 1;\n\nconst isLessThanTen = n =\u003e n \u003c 10;\n\nconst isValidValue = and(isLargerThanOne, isLessThanTen);\n\nconsole.log(isValidValue(4)); // true\nconsole.log(isValidValue(14)); // false\n```\n\n## Documentation\n\nThe documentation can be found [here](https://csvenke.github.io/compose-rules)\n\n## Why\n\nLet's say you need to verify that some value complies with a series of requirements.\n\n- It must be a number\n- It must be larger than 1\n- It must be less than 10\n- It must be an odd number\n- It must be a prime number\n\nYou could just write a function that verifies all those requirements, but requirements tend to change and changes tend to cause regression in your code.\n\nYou should instead write separate functions that verify each requirement and then compose all those functions into a single function that verifies all the requirements.\n\nThe main benefit of this approach is when requirements change you simply add/remove/edit specific functions from the composer without affecting the other functions.\n\nSee the example below for what that might look like.\n\n### Example\n\n[Try it out online with repl.it!](https://repl.it/@csvenke/WorseMiserlyScale)\n\n```js\nimport { and, not } from \"@csvenke/compose-rules\";\n\n/**\n * Returns true if n is number\n */\nconst isNumber = n =\u003e typeof n === \"number\";\n\n/**\n * Returns true if n is larger than one\n */\nconst isNumberLargerThanOne = n =\u003e n \u003e 1;\n\n/**\n * Returns true if n is less than ten\n */\nconst isNumberLessThanTen = n =\u003e n \u003c 10;\n\n/**\n * Returns true if n is even\n */\nconst isNumberEven = n =\u003e n % 2 === 0;\n\n/**\n * Returns true if n is odd\n */\nconst isNumberOdd = not(isNumberEven);\n\n/**\n * Returns true if n is prime\n */\nconst isNumberPrime = n =\u003e {\n  for (let i = 2, s = Math.sqrt(n); i \u003c= s; i++) if (n % i === 0) return false;\n  return n \u003e 1;\n};\n\n/**\n * Returns true if all rules returns true\n */\nconst isValidValue = and(\n  isNumber,\n  isNumberLargerThanOne,\n  isNumberLessThanTen,\n  isNumberOdd,\n  isNumberPrime\n);\n\nconsole.log(isValidValue(5)); // true\nconsole.log(isValidValue(8)); // false\nconsole.log(isValidValue(\"Hello\")); // false\nconsole.log(isValidValue(undefined)); // false\n```\n\n## Development\n\nInstalling dependencies\n\n```\nyarn install\n```\n\nRunning tests\n\n```\nyarn test\n```\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style.\n\n## License\n\n[MIT](https://github.com/csvenke/compose-rules/blob/master/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcsvenke%2Fcompose-rules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcsvenke%2Fcompose-rules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcsvenke%2Fcompose-rules/lists"}