{"id":15287000,"url":"https://github.com/ben-laird/yatabl","last_synced_at":"2026-04-29T11:02:24.780Z","repository":{"id":211235986,"uuid":"728569337","full_name":"ben-laird/yatabl","owner":"ben-laird","description":"Yet another tagging and branding library. Safety, dx, and perf conscious!","archived":false,"fork":false,"pushed_at":"2023-12-09T06:56:24.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-26T06:59:46.196Z","etag":null,"topics":["branded-types","branding","deno","safe","safety","schema","schema-validation","tag","tagging","typescript","typescript-library","validation","yatabl"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ben-laird.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-12-07T08:16:01.000Z","updated_at":"2023-12-07T08:19:03.000Z","dependencies_parsed_at":"2023-12-07T09:31:02.625Z","dependency_job_id":"9ebe20c5-d6e9-49e0-9fec-c7c48df55953","html_url":"https://github.com/ben-laird/yatabl","commit_stats":{"total_commits":14,"total_committers":1,"mean_commits":14.0,"dds":0.0,"last_synced_commit":"b0eda12d78e28106e0c343d1cce16a7d599c3252"},"previous_names":["ben-laird/yatabl"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ben-laird/yatabl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ben-laird%2Fyatabl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ben-laird%2Fyatabl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ben-laird%2Fyatabl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ben-laird%2Fyatabl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ben-laird","download_url":"https://codeload.github.com/ben-laird/yatabl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ben-laird%2Fyatabl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32422532,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T06:29:02.080Z","status":"ssl_error","status_checked_at":"2026-04-29T06:29:00.631Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["branded-types","branding","deno","safe","safety","schema","schema-validation","tag","tagging","typescript","typescript-library","validation","yatabl"],"created_at":"2024-09-30T15:20:15.755Z","updated_at":"2026-04-29T11:02:24.749Z","avatar_url":"https://github.com/ben-laird.png","language":"TypeScript","funding_links":["https://www.buymeacoffee.com/benlaird"],"categories":[],"sub_categories":[],"readme":"# Yet Another Tagging and Branding Library\n\nYatabl (pronounced \"YEA-tuh-bull\") is a dead-simple tagging and branding library\nthat focuses on doing one thing and doing it well.\n\n## Features\n\n- Small, Performant, Flexible\n  - 0 dependencies\n  - Browser/Node/Bun/Deno/Edge friendly\n  - Built with core JS/TS language constructs: if your runtime supports classes\n    and `Object.assign()`, it supports `yatabl`\n  - Incredibly small footprint: entire source code (before bundling, including\n    doc comments + types) is about 240 lines across 3 files (an average of about\n    80 lines per file)\n  - Tree-shakeable: don't pay for what you don't use (not a lot to pay for with\n    this lib anyways)\n- Great DX\n  - Type \u0026 runtime safe: made with love in TypeScript, doesn't lose any safety\n    guarantees when compiled to JavaScript\n  - Aggressive inferences: stay highly type-safe while barely having to write\n    your own types\n  - Easy interoperability: `yatabl` plays nice with pretty much any schema\n    validation library, like Zod, Yup, runtypes, and more\n  - Easy adoptability: `yatabl` only adds metadata to objects and doesn't wrap\n    them, allowing devs to just drop it in and perform easy validation checks\n    wherever\n  - Validate once, enforce everywhere: save time and resources by\n    - asserting in your function types that something must pass validation\n      before being passed in, or\n    - validating something once in your code and checking if it passed\n      everywhere else, or\n    - enforcing assumptions or type/validation contracts you make in your code\n  - Docs included: JSDoc comments included so you never have to look at this\n    page again :smile:\n\n## Installation\n\nUsing a package manager like `npm`:\n\n```sh\nnpm install yatabl\n```\n\n```ts\nimport { y } from \"yatabl\";\n```\n\nUsing Deno:\n\n```ts\nimport { y } from \"https://deno.land/x/yatabl/mod.ts\";\n```\n\n## Usage and Patterns\n\nHere's a quick guide by example on the ideal patterns to use:\n\n```ts\nimport { assertThrows } from \"https://deno.land/std@0.208.0/assert/mod.ts\";\n\nimport { y } from \"https://deno.land/x/yatabl/mod.ts\"; // Convenient zod-style import\n\nDeno.test(async function Patterns(t) {\n  await t.step({\n    name: \"Quickstart\",\n    fn() {\n      // Step 1: define a tag function\n      const Clone = y.tag(\n        \"Clone Trooper\",\n        y.yatable\u003c{\n          rank: string;\n          id: number;\n          name?: string;\n        }\u003e(),\n      );\n\n      // Step 2: use tag function wherever you want!\n      const _fives = Clone({\n        id: 5555,\n        rank: \"Trooper\",\n        name: \"Fives\",\n      });\n    },\n  });\n\n  await t.step({\n    name: \"Tag function with validation\",\n    fn() {\n      // interfaces are unsupported because of a TypeScript language issue :(\n      type JediInfo = {\n        affiliation: \"Jedi\";\n        rank: \"General\";\n        name: string;\n      };\n\n      // You can include validation logic in your tag functions too!\n      const Jedi = y.tag(\"Jedi General\", (x) =\u003e {\n        if (!(x \u0026\u0026 typeof x === \"object\")) {\n          throw new Error(\"validation failed!\");\n        }\n\n        if (!(\"affiliation\" in x \u0026\u0026 x.affiliation === \"Jedi\")) {\n          throw new Error(\"should be affiliated with the Jedi!\");\n        }\n\n        if (!(\"rank\" in x \u0026\u0026 x.rank === \"General\")) {\n          throw new Error(\"should be a Jedi General!\");\n        }\n\n        if (!(\"name\" in x \u0026\u0026 typeof x.name === \"string\")) {\n          throw new Error(\"Jedi should have a name!\");\n        }\n\n        // `as` casting here doesn't compromise type safety because x has passed validation\n        return x as JediInfo;\n      });\n\n      // input argument infers from return type...\n      const _ObiWan = Jedi({\n        affiliation: \"Jedi\",\n        rank: \"General\",\n        name: \"Obi-Wan Kenobi\",\n      });\n\n      // So this throws an error in TypeScript and at runtime!\n      assertThrows(() =\u003e {\n        const _Anakin = Jedi({\n          //@ts-expect-error: intentionally incorrect\n          affiliation: \"Sith\",\n          rank: \"General\",\n          name: \"Anakin Skywalker\",\n        });\n      });\n    },\n  });\n\n  await t.step({\n    name: \"Tag function inside validation\",\n    fn() {\n      // interfaces are unsupported because of a TypeScript language issue :(\n      type JediInfo = {\n        affiliation: \"Jedi\";\n        rank: \"General\";\n        name: string;\n      };\n\n      type JediValidation = {\n        affiliation: string;\n        rank: string;\n        name: string;\n      };\n\n      // This is a much safer way to validate data, as it won't throw any errors\n      // and will instead return `undefined` on validation failure\n      function validateJedi(jedi: JediValidation) {\n        if (jedi.affiliation === \"Jedi\" \u0026\u0026 jedi.rank === \"General\") {\n          return y.tag(\"Jedi General\", jedi as JediInfo);\n        }\n      }\n\n      const _ObiWan = validateJedi({\n        affiliation: \"Jedi\",\n        rank: \"General\",\n        name: \"Obi-Wan Kenobi\",\n      });\n\n      const _Anakin = validateJedi({\n        affiliation: \"Sith\",\n        rank: \"General\",\n        name: \"Anakin Skywalker\",\n      });\n    },\n  });\n\n  await t.step({\n    name: \"Tag function with transformation, and checking if validation passed\",\n    fn() {\n      interface Clone {\n        id: number;\n        name?: string;\n      }\n\n      type RankedClone = {\n        id: number;\n        name?: string;\n        rank: string;\n      };\n\n      function salute(clone: RankedClone) {\n        // We test to see if the clone has passed Arc Trooper validation\n        if (\n          y.isTagged(\"Arc Trooper\", clone) ||\n          y.isTagged(\"Commander\", clone)\n        ) {\n          // We now know this clone is an Arc Trooper or a Commander!\n          // Notice you can still use `clone` as its original type.\n          // Yatabl only adds metadata and never alters your objects otherwise\n          const message = `Attention! ${clone.rank} ${\n            clone.name ?? clone.id\n          } is on deck!`;\n\n          console.log(message);\n        } else {\n          console.log(`${clone.name ?? clone.id} is not recognized!`);\n        }\n      }\n\n      /**\n       * Trooper tag functions\n       */\n      const Trooper = {\n        // You can even include transformation logic and combine it with validation logic!\n        Arc: y.tag(\"Arc Trooper\", ({ name, id }: Clone): RankedClone =\u003e {\n          return { rank: \"Arc Trooper\", name, id };\n        }),\n        Commander: y.tag(\"Commander\", ({ name, id }: Clone): RankedClone =\u003e {\n          return { rank: \"Commander\", name, id };\n        }),\n        Trooper: y.tag(({ name, id }: Clone): RankedClone =\u003e {\n          return { rank: \"Trooper\", name, id };\n        }),\n      };\n\n      const Jesse = Trooper.Arc({ id: 5597, name: \"Jesse\" });\n\n      const Cody = Trooper.Commander({ id: 2224, name: \"Cody\" });\n\n      const Crosshair = Trooper.Trooper({ id: 9904, name: \"Crosshair\" });\n\n      salute(Jesse); // prints \"Attention! Arc Trooper Jesse is on deck!\"\n\n      salute(Cody); // prints \"Attention! Commander Cody is on deck!\"\n\n      salute(Crosshair); // prints \"Crosshair is not recognized!\"\n    },\n  });\n});\n```\n\n## The Secret Sauce: Yatables\n\nThe secret sauce of `yatabl` is a function type called a `Yatable`. It\nrepresents any processing (validation and/or same-type transformation) function.\n\n```ts\nexport type Yatable\u003cT extends DataStructure, U = T\u003e = (thing: U) =\u003e T;\n```\n\nIt's generic enough to allow for working with any schema validation library (or\ntype narrowing system in general), yet it allows for us to constrain any values\nwe pass into our tagging functions to type `T` or to type `U` if transformation\nis needed. We could even write simple functions to convert schema validation\nconstructs into `Yatable`s, and in the future, there will be some official\nutility functions to convert things like type guards, type assertions, and Zod\nschemas into `Yatable`s.\n\n## Roadmap\n\n- [ ] `Yatable` Converters\n  - [ ] Zod\n  - [ ] Yup\n  - [ ] Type guard\n  - [ ] Type assertion\n- [ ] Metadata\n  - [ ] Ctx\n  - [ ] Validator auth (to determine which validator did what)\n- [ ] Error handling (maybe need a new library for that)\n- [ ] Event emission (for error logging or pub/sub programming, may also need a\n      new library)\n- [x] Full transformation functions (a la `new`-able objects)\n\n## Support\n\nIf you like this library, thanks so much! I'm glad to make something people like\nusing. If you _really_ like it and want to support me, star this library on\n[GitHub](https://github.com/ben-laird/yatabl) or\n[buy me a coffee](https://www.buymeacoffee.com/benlaird). Any\nsupport/encouragement is greatly appreciated!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fben-laird%2Fyatabl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fben-laird%2Fyatabl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fben-laird%2Fyatabl/lists"}