{"id":25070781,"url":"https://github.com/yamiteru/pipu","last_synced_at":"2025-04-14T20:56:02.407Z","repository":{"id":63825713,"uuid":"570712315","full_name":"yamiteru/pipu","owner":"yamiteru","description":"🔥 hellishly fast, 🤏 tiny and 🤖 modular async/sync pipe toolkit for typescript.","archived":false,"fork":false,"pushed_at":"2023-07-22T00:24:54.000Z","size":1142,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-24T04:11:47.737Z","etag":null,"topics":["fp","functional-programming","javascript","pipe","pipe-operator","typescript"],"latest_commit_sha":null,"homepage":"","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/yamiteru.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}},"created_at":"2022-11-25T22:33:11.000Z","updated_at":"2023-04-18T10:03:37.000Z","dependencies_parsed_at":"2025-02-06T21:35:24.753Z","dependency_job_id":"1bf02a36-c471-44f0-8639-ec7c3c190d88","html_url":"https://github.com/yamiteru/pipu","commit_stats":null,"previous_names":["yamiteru/pipem"],"tags_count":4,"template":false,"template_full_name":"yamiteru/ts-package","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamiteru%2Fpipu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamiteru%2Fpipu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamiteru%2Fpipu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamiteru%2Fpipu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yamiteru","download_url":"https://codeload.github.com/yamiteru/pipu/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248961142,"owners_count":21189991,"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":["fp","functional-programming","javascript","pipe","pipe-operator","typescript"],"created_at":"2025-02-06T21:35:08.349Z","updated_at":"2025-04-14T20:56:02.371Z","avatar_url":"https://github.com/yamiteru.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pipu\n\n🔥 hellishly fast, 🤏 tiny and 🤖 modular async/sync pipe toolkit for typescript.\n\n---\n\n## Installation\n\n```bash\nyarn add pipu # pnpm add pipu\n```\n\n---\n\n## Concept\n\nPipu is designed to be as low-level and unopinionated as possible so you can build your own abstractions on top of it.\n\nIt supports both sync and async modes. That means you can use sync to solve problems where sync fits the job best and async where async fits the job best.\n\n---\n\n## Examples\n\n1. [Map](./examples/1-map.ts)\n2. [Filter](./examples/2-filter.ts)\n3. [Or](./examples/3-or.ts)\n4. [Wrap](./examples/4-wrap.ts)\n5. [Parse](./examples/5-parse.ts)\n6. [Resolve](./examples/6-resolve.ts)\n\n---\n\n## Pipeables\n\nPipeables are functions that you can put into a pipe (pipe itself is `Pipeable`).\n\nThere's just a few core pipeables so it's easy to build your own abstractions on top them.\n\n*(but I'm open to ideas and PRs regarding new pipeables)*\n\n### filter\n\nPipeable which runs either `truePipeable` or `falsePipeable` based on return value of `predicate`.\n\nBy default `truePipeable` returns `Ok\u003c$Input\u003e` and `falsePipeable` returns `Err\u003cError\u003c\"FILTER\", $Input\u003e\u003e`.\n\n```ts\nfilter((v: number) =\u003e !(v % 2));\n\nfilter(\n  (v: number) =\u003e !(v % 2),\n  () =\u003e ok(\"even\"),\n);\n\nfilter(\n  (v: number) =\u003e !(v % 2),\n  () =\u003e ok(\"even\"),\n  () =\u003e ok(\"odd\"),\n);\n```\n\n### map\n\nIt maps value from `$Input` to `$Output` and returns it as `Ok\u003c$Output\u003e`.\n\n```ts\n// Pipeable\u003cnumber, Result\u003cstring, Error\u003e\u003e\nconst doubleString = map((v: number) =\u003e `${v * 2}`);\n```\n\n### wrap\n\nPipeable which wraps a sub-pipeable and overrides its `Error`.\n\nIt's recommended to use `error` function to create a custom `Error`.\n\n```ts\n// Pipeable\u003cnumber, Result\u003cnumber, Error\u003c\"CUSTOM\", number\u003e\u003e\u003e\nwrap(\n  map((v: number) =\u003e v * 2),\n  error(\"CUSTOM\"),\n);\n```\n\n### and\n\nPipeable which takes N number of pipeables and returns either `Ok` returned by the last pipeable or `Err` returned by any of the pipeables.\n\n```ts\n// Pipeable\u003cnumber, Result\u003cstring, Error\u003c\"FILTER\", number\u003e | Error\u003c\"CUSTOM\", number\u003e\u003e\u003e\nconst customPipe = pipe(\n  filter((v: number) =\u003e !(v % 2)),\n  wrap(\n    map((v) =\u003e `${v}`),\n    error(\"CUSTOM\"),\n  ),\n);\n```\n\n### or\n\nPipeable which takes N number of pipeables and returns either `Ok` returned by any of the pipeables or `Err` if none of the pipeables returned `Ok`.\n\n```ts\n// Pipeable\u003cnumber, Result\u003cnumber, Error\u003c\"OR\", number\u003e\u003e\u003e\nconst customPipe = or(\n  filter((v: number) =\u003e !(v % 2)),\n  filter((v: number) =\u003e !(v % 3)),\n);\n```\n\n### resolve\n\nAsync pipeable which tries to resolve a promise and return `ResultOk`.\n\n```ts\n// PipeableAsync\u003cnumber, Result\u003cnumber, Error\u003c\"PROMISE\", number\u003e\u003e\u003e\nconst getUsersByAge = and(\n  filter((age: number) =\u003e age \u003e 18),\n  resolve((age) =\u003e api.getUsersByAge(age)),\n);\n```\n\n---\n\n## Utils\n\n### error\n\nCreates error tuple based on value and potential sub-error.\n\nIt should mainly be used in `wrap` function as a second parameter.\n\nAll `Pipeable`s should return error created with this function.\n\n```ts\nerror(\"TEST\", (value, error) =\u003e ({ valueType: typeof value, error }));\n```\n\n### parse\n\nAllows to run `Pipeable` with `unknown` input while infering everything else from the `Pipeable` as usual.\n\n```ts\nconst isStringOrNumber = pipe(...);\n// ResultErr\u003c[\"OR\", [], { }]\u003e\nconst result1 = parse(isStringOrNumber, []);\n// ResultOk\u003c1\u003e\nconst result2 = parse(isStringOrNumber, 1);\n```\n\n---\n\nHave a beautiful day 🍀.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyamiteru%2Fpipu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyamiteru%2Fpipu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyamiteru%2Fpipu/lists"}