{"id":24503988,"url":"https://github.com/pujitm/fun-ov","last_synced_at":"2025-03-15T08:24:22.648Z","repository":{"id":58824664,"uuid":"459343645","full_name":"pujitm/fun-ov","owner":"pujitm","description":"Flexible functional object validation for API's \u0026 highly customized software","archived":false,"fork":false,"pushed_at":"2022-09-06T03:53:17.000Z","size":273,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-23T04:24:35.949Z","etag":null,"topics":["functional-programming","javascript","typescript","validation"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/fun-ov","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/pujitm.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}},"created_at":"2022-02-14T22:18:55.000Z","updated_at":"2024-11-27T00:11:04.000Z","dependencies_parsed_at":"2022-09-08T11:50:33.516Z","dependency_job_id":null,"html_url":"https://github.com/pujitm/fun-ov","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujitm%2Ffun-ov","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujitm%2Ffun-ov/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujitm%2Ffun-ov/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujitm%2Ffun-ov/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pujitm","download_url":"https://codeload.github.com/pujitm/fun-ov/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243704216,"owners_count":20334116,"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":["functional-programming","javascript","typescript","validation"],"created_at":"2025-01-21T23:19:24.497Z","updated_at":"2025-03-15T08:24:22.618Z","avatar_url":"https://github.com/pujitm.png","language":"TypeScript","readme":"# Functional Object Validation for Typescript and Javascipt\n\nFun-ov makes runtime validation easy, flexible, and maintainable at scale (I hope). It's great for API's, games, and business logic.\n\n## Getting Started\n\n```bash\nnpm install fun-ov\n# Or\nyarn add fun-ov\n```\n\n```ts\nimport { makeObjectChecker, makeListChecker, resultIsError } from \"fun-ov\";\n// Or\nimport * as Fun from \"fun-ov\";\n\n// You're ready to make or adapt your validators. Example:\nimport { is, or, resultIsError } from \"fun-ov\";\n\ntype Action = 'like' | 'comment' | 'subscribe';\nconst checkAction = or(is('like'), is('comment'), is('subscribe'));\n\n// Get a value from somewhere else, like an HTTP request. This time, it's 'dislike'\nconst result = checkAction(\"dislike\"); \nif (resultIsError(result)) {\n    console.log(\"Don't @ me - YT. Fix one of these:\", result);\n}\n\n// Technically, you could use a go-like pattern, but sometimes, false might mean an error.\nconst err = checkAction(\"dislike\"); \nif (err) console.log(\"yell\");\nif (checkAction(\"sleep\")) console.log(\"sleep is good, but not here :(\");\n```\n\n## Usage\n\nA validator (also called 'checker') is a function that returns any errors with the input value. No errors, no return value. \n\nThis behavior is defined in `lib/rules.ts` via the `resultIsError` function.\n\nOnce you know there's an error, you can log it, display it to an end-user, or fix it, but that gets unwieldy pretty quick, especially if rules can change on the fly.\n\nComposing these kinds of functions makes complex logic ([like the Stripe Connect API](https://stripe.com/docs/api/external_account_bank_accounts/create)) accessible and readable without much boilerplate.\n\nExample:\n\n```ts\n// From test/company.ts\nexport const validateBankAccount = makeObjectChecker\u003cBankAccount\u003e({\n  routing_number: isNonEmptyString, // Can replace these with any combined validation function\n  account_number: isNonEmptyString, // See the Validation type in lib/rules.ts\n  account_holder_name: isNonEmptyString,\n  account_holder_type: is(\"company\"),\n});\n\nexport const validateCompany = makeObjectChecker\u003cCompany\u003e({\n  name: validateNames, // another object validator made using `makeObjectChecker`\n  bank_account: optional(validateBankAccount),\n  website: optional(checkIfString),\n  tax_id: optional(checkIfString),\n  email: optional(checkIfString),\n  tos_accepted: and(checkIfBoolean, (accepted, company: Company) =\u003e {\n    if (company.bank_account \u0026\u0026 !accepted)\n      return \"must accept TOS to maintain bank account\";\n  }),\n});\n// Validation errors will retain shape of object, so you know what properties were erroneous\n```\n\nThis package provides building blocks to help you build your own validation. \n\n### Helpers\n\nThese functions return a Validator. You can run those validators with input, or you can combine them with other validators to make a bigger, overarching validator.\n\nThe format will be `function_name: Function input. What the returned validator will check, and how it will behave`.\n\nRemember, Validators will only return if there is an error.\n\n#### Identity \u0026 Equality\n\n*See lib/equal.ts*\n\n`is`: Takes one input. Validator checks if final input is equal (===) to that.\n\n#### Logical Operators\n\n*See lib/combinators.ts*\n\n`and`: Takes any number of validators. Checks that final input is validated by all of them. Returns the erroneous result, if any.\n\n`or`: Takes any number of validators. Checks that final input is validated by at least one of them. Returns list of errors (positions correspond to validators).\n\n`EagerAnd` and `EagerOr`: Eager variants will run all validators passed to them, no matter what. Logically, they behave the same. Returns a list of errors (if logical result is false).\n\n#### Type Checkers\n\n*See lib/type-checkers.ts*\n\n`checkIf\u003cType\u003e`: Takes an input. Checks if it meets the type criteria. Covers all JS Types, definitive-ness, and existence.\n\n`optional`: Takes a validator. Returns any error(s) from the validation, which only runs if the final input is not null, undefined, or NaN.\n\n#### Collection Checkers\n\n*See lib/object.ts and lib/list.ts*\n\nThese create convenient nest-able validators for objects, lists, and tuples. See in-code documentation for usage instructions.\n\n`makeObjectChecker`: Returns object of errors. Properties correspond to bad properties on input object.\n\n`makeListChecker`: Returns list of errors. Positions correspond to bad elements.\n\n`makeTupleChecker`: Returns list of errors. Positions correspond to bad elements.\n\n## Why does this exist?\n\nProbably because I couldn't find the right packages at the right time. [Zod](https://github.com/colinhacks/zod) is great for schema definition, manipulation, and parsing, and [tRPC](https://github.com/trpc/trpc) is good for front-to-backend type-safe http API's. \n\nZod is fun-ov's closest neighbor, but they differ in meaningful ways.\n\n`fun-ov` isn't a tool or a framework. It's an idea and a pattern, with helpers to cut through annoying details and boilerplate.\n\nIt can replicate some of zod's functionality and do some things it can't (context-aware validation, more error cases/types), but it's smaller and less intrusive than zod. \n\nThere isn't a tool to learn with `fun-ov`, just a pretty powerful idea made accessible. Fun-ov is a library of validation combinators that you can extend past validation use-cases.\n\n If the Wikipedia entry on combinators makes your eyes glaze over, this [SO question](https://stackoverflow.com/questions/7533837/explanation-of-combinators-for-the-working-man) is a good place to learn about them.\n\nThis package was created because validation is a recurring need, and existing solutions at the time of development\ndidn't meet my standards/needs for style, modularity, customizability, and extensibility.\n\n## Future\n\nPossible API changes:\n\n- `makeMapChecker` - excluded because keys/values can be validated before insertion","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpujitm%2Ffun-ov","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpujitm%2Ffun-ov","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpujitm%2Ffun-ov/lists"}