{"id":30779324,"url":"https://github.com/aklinker1/zero-factory","last_synced_at":"2026-02-21T19:29:58.357Z","repository":{"id":309842191,"uuid":"1037573004","full_name":"aklinker1/zero-factory","owner":"aklinker1","description":"Zero dependency object factory generator for testing","archived":false,"fork":false,"pushed_at":"2025-08-21T18:41:49.000Z","size":32,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-29T11:58:11.147Z","etag":null,"topics":["factory","testing","zero-dependencies"],"latest_commit_sha":null,"homepage":"https://jsr.io/@aklinker1/zero-factory","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/aklinker1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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":"2025-08-13T19:28:31.000Z","updated_at":"2025-08-21T18:41:51.000Z","dependencies_parsed_at":"2025-08-21T20:30:57.709Z","dependency_job_id":null,"html_url":"https://github.com/aklinker1/zero-factory","commit_stats":null,"previous_names":["aklinker1/zero-factory"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/aklinker1/zero-factory","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aklinker1%2Fzero-factory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aklinker1%2Fzero-factory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aklinker1%2Fzero-factory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aklinker1%2Fzero-factory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aklinker1","download_url":"https://codeload.github.com/aklinker1/zero-factory/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aklinker1%2Fzero-factory/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273718984,"owners_count":25155631,"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","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["factory","testing","zero-dependencies"],"created_at":"2025-09-05T06:09:55.597Z","updated_at":"2026-02-21T19:29:58.351Z","avatar_url":"https://github.com/aklinker1.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# @aklinker1/zero-factory\n\n[![JSR](https://jsr.io/badges/@aklinker1/zero-factory)](https://jsr.io/@aklinker1/zero-factory) [![NPM Version](https://img.shields.io/npm/v/%40aklinker1%2Fzero-factory?logo=npm\u0026labelColor=red\u0026color=white)](https://www.npmjs.com/package/@aklinker1/zero-factory) [![Docs](https://img.shields.io/badge/Docs-blue?logo=readme\u0026logoColor=white)](https://jsr.io/@aklinker1/zero-factory) [![API Reference](https://img.shields.io/badge/API%20Reference-blue?logo=readme\u0026logoColor=white)](https://jsr.io/@aklinker1/zero-factory/doc) [![License](https://img.shields.io/npm/l/%40aklinker1%2Fzero-factory)](https://github.com/aklinker1/zero-factory/blob/main/LICENSE)\n\nZero dependency object factory generator for testing.\n\n\u003c/div\u003e\n\n```ts\nimport { createFactory, createSequence } from \"@aklinker1/zero-factory\";\n\nconst userFactory = createFactory\u003cUser\u003e({\n  id: createSequence(\"user-\"),\n  username: \"example-username\",\n  email: () =\u003e \"example-email-\" + Math.random(),\n});\n\nuserFactory({ id: \"test\", username: \"user\" });\n// =\u003e {\n//   id: \"test\",\n//   username: \"user\",\n//   email: \"example-email-0.20088082049103195\"\n// }\n```\n\n```sh\nnpm i @aklinker1/zero-factory\n```\n\n**Features:**\n\n- ✅ Type-safe\n- ✨ Deeply merge overrides with default values\n- 🔢 Sequence generator for IDs\n- 🎨 \"traits\" - define multiple variants of default values\n- ⚡ Compatible with all fake data generators (`@ngneat/falso`, `faker-js`, `chance`, `casual`, etc)\n\n**Not Supported:**\n\n- **Class instances**: Only objects can be created. Factories will not create class instances.\n\n## Usage\n\n### Factories\n\nUse `createFactory` to build an object factory. Object factories are simple functions that return an object:\n\n```ts\nconst userFactory = createFactory\u003cUser\u003e({\n  id: \"user-id\",\n  username: \"username\",\n  email: \"example@gmail.com\",\n  preferences: {\n    receiveMarketingEmails: true,\n    receiveSecurityEmails: true,\n  },\n});\n// typeof userFactory = (overrides?: DeepPartial\u003cUser\u003e) =\u003e User\n```\n\nThen, to get an object conforming to the `User` type, just call the factory as a function:\n\n```ts\nconst user = userFactory();\n// =\u003e {\n//   id: \"user-id\",\n//   username: \"username\",\n//   email: \"example@gmail.com\",\n//   preferences: {\n//     receiveMarketingEmails: true,\n//     receiveSecurityEmails: true,\n//   }\n// }\n```\n\nYou can also override specific properties at any level:\n\n```ts\nconst user = userFactory({\n  username: \"overridden\",\n  preferences: {\n    receiveMarketingEmails: false,\n  },\n});\n// =\u003e {\n//   id: \"user-id\",\n//   username: \"overridden\",\n//   email: \"example@gmail.com\",\n//   preferences: {\n//     receiveMarketingEmails: false,\n//     receiveSecurityEmails: true,\n//   }\n// }\n```\n\n\u003e [!IMPORTANT]\n\u003e Arrays are not deeply merged. If a property is an array, overrides will fully replace it, like any other value.\n\n#### Function Defaults\n\nIn addition to static values, the factory definition accepts functions for properties:\n\n```ts\nconst userFactory = createFactory({\n  email: () =\u003e `example.${Math.floor(Math.random() * 1000)}@gmail.com`,\n  // ...\n});\n```\n\nEvery time the factory is called, this will call the function and, in this case, generate a different `email` each time:\n\n```ts\nuserFactory(); // { email: \"example.424@gmail.com\", ... }\nuserFactory(); // { email: \"example.133@gmail.com\", ... }\n```\n\nThis is where [fake data generators](https://www.npmjs.com/search?q=fake%20data) and [sequences](#sequences) come in clutch:\n\n```ts\nimport { createFactory, createSequence } from \"@aklinker1/zero-factory\";\nimport {\n  randEmail, // () =\u003e string\n  randUsername, // () =\u003e string\n  randBoolean, // () =\u003e boolean\n} from \"@ngneat/falso\";\n\nconst userFactory = createFactory({\n  id: createSequence(\"user-\"),\n  username: randUsername,\n  email: randEmail,\n  preferences: {\n    receiveMarketingEmails: randBoolean,\n    receiveSecurityEmails: randBoolean,\n  },\n});\n```\n\n#### Many\n\nYou can generate multiple objects using `factory.many(...)`. This method will return an array of objects.\n\n```ts\nuserFactory.many(2, { username: \"override\" });\n// [\n//   { usenrame: \"override\", ... }\n//   { usenrame: \"override\", ... }\n// ]\n```\n\nOverridden fields apply to all the returned objects.\n\n#### Traits\n\nIf there are common variants or \"traits\" of an object you want to be able to generate, use `factory.trait(...)`:\n\n```ts\nconst userFactory = createFactory({\n  // same as above\n}).trait(\"noEmails\", {\n  preferences: {\n    receiveMarketingEmails: false,\n    receiveSecurityEmails: false,\n  },\n});\n```\n\nThen, to generate an object using this trait, the trait is a function defined on the object factory:\n\n```ts\nconst user = userFactory.noEmails();\n// =\u003e {\n//   id: \"user-id\",\n//   username: \"username\",\n//   email: \"example@gmail.com\",\n//   preferences: {\n//     receiveMarketingEmails: false,\n//     receiveSecurityEmails: false,\n//   }\n// }\n```\n\nWhen using a trait and overriding specific properties, the trait's default values are applied before the overrides:\n\n```ts\nconst user = userFactory.noEmails({ username: \"overridden\" });\n// =\u003e {\n//   id: \"user-id\",\n//   username: \"overridden\",\n//   email: \"example@gmail.com\",\n//   preferences: {\n//     receiveMarketingEmails: false,\n//     receiveSecurityEmails: false,\n//   }\n// }\n```\n\n#### Associations\n\nIf you want to override one or more fields based on a single value, use associations:\n\n```ts\nconst postFactory = createFactory\u003cPost\u003e({\n  id: createSequence(),\n  userId: userIdSequence,\n  // ...\n}).associate(\"user\", (user: User) =\u003e ({ userId: user.id }));\n```\n\nThen to generate a post associated with a user, use `with`:\n\n```ts\nuser;\n// =\u003e {\n//   id: 3,\n//   ...\n// }\n\npostFactory.with({ user })();\n// =\u003e {\n//   id: 0,\n//   userId: 3,\n//   ...\n// }\n```\n\nNote that `with` returns a factory function, which needs to be called to generate the final object. This allows you to chain other utilities like `.many` and/or traits:\n\n```ts\npostFactory.with({ user }).noEmails.many(3);\n```\n\n### Sequences\n\nFor values like IDs, it can be useful to generate them incrementally instead of using randomized values. Use the `createSequence` function to do this:\n\n```ts\nconst userIdSequence = createSequence((i) =\u003e `user-${i}`);\n\nuserIdSequence(); // \"user-0\"\nuserIdSequence(); // \"user-1\"\nuserIdSequence(); // \"user-2\"\n// ...\n```\n\nThe argument `i` is a number starting at 0 that gets incremented by 1 each time the sequence is called. The return value can be anything (string, boolean, object, integer, etc).\n\n```ts\nconst intSequence = createSequence((i) =\u003e i + 1);\nintSequence(); // 1\nintSequence(); // 2\nintSequence(); // 3\n// ...\n\nconst boolSequence = createSequence((i) =\u003e i % 2 === 0);\nboolSequence(); // true\nboolSequence(); // false\nboolSequence(); // true\n// ...\n```\n\nHowever, the most common types of return values are integers and strings. For both, there is a shorthand:\n\n```ts\nconst intSequence = createSequence();\nintSequence(); // 0\nintSequence(); // 1\nintSequence(); // 2\n// ...\n\nconst strSequence = createSequence(\"prefix-\");\nintSequence(); // \"prefix-0\"\nintSequence(); // \"prefix-1\"\nintSequence(); // \"prefix-2\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faklinker1%2Fzero-factory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faklinker1%2Fzero-factory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faklinker1%2Fzero-factory/lists"}