{"id":15382901,"url":"https://github.com/reggi/linear_builder_class","last_synced_at":"2025-03-27T22:42:30.324Z","repository":{"id":165249253,"uuid":"640595432","full_name":"reggi/linear_builder_class","owner":"reggi","description":"➡️👷💪 Code Generates Classes using the Linear Builder Class pattern","archived":false,"fork":false,"pushed_at":"2023-05-16T03:29:09.000Z","size":9,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-02T00:49:45.425Z","etag":null,"topics":["classes","codegen","deno","metaprogramming","oop"],"latest_commit_sha":null,"homepage":"https://deno.land/x/linear_builder_class","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reggi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2023-05-14T15:59:02.000Z","updated_at":"2023-05-16T03:33:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"dc987360-022d-4769-a37f-6b0037345c5f","html_url":"https://github.com/reggi/linear_builder_class","commit_stats":{"total_commits":7,"total_committers":1,"mean_commits":7.0,"dds":0.0,"last_synced_commit":"2a872689ae9a20ae5407be72b65bea38ab87ce7e"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reggi%2Flinear_builder_class","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reggi%2Flinear_builder_class/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reggi%2Flinear_builder_class/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reggi%2Flinear_builder_class/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reggi","download_url":"https://codeload.github.com/reggi/linear_builder_class/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245937896,"owners_count":20696985,"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":["classes","codegen","deno","metaprogramming","oop"],"created_at":"2024-10-01T14:34:38.765Z","updated_at":"2025-03-27T22:42:30.302Z","avatar_url":"https://github.com/reggi.png","language":"TypeScript","readme":"## Linear Builder Class\n\nMy goal is to define types and ensure that the generic values \"match\" from one method to the next. \n\n```ts\nnew Example()\n  .stringOrNumber(1)\n  .toObject((knowsItsANumber) =\u003e {\n    return { yepStillKnows: knowsItsANumber }\n  })\n  .chainMe(({ yepStillKnows }) =\u003e {\n    return yepStillKnows + 1\n  })\n  .done (stillANumber =\u003e {\n    console.log(stillANumber) // number\n  })\n```\n\n\u003e Note: this 👆 is `example_two`\n\nOne common approach to achieve this is to maintain separate class instances that are returned for each method, instead of returning this and having a regular class where all methods are on that one class. With the latter approach, each \"set\" value can't be dynamically typed. By passing in a value and returning a new class instance, you can keep track of the types. This is a linear process because you can only set one property at a time in the same sequence. Due to the way that generics work, the only way to do this effectivly is to create and return new class instances which can result in a lot of boilerplate code. That's where this tool comes in. This creates the scaffolding classes required to pull this off.\n\nWhat is a [builder class](https://refactoring.guru/design-patterns/builder/typescript/example)? It's a pattern of class creation where class methods generally return `this`, and you chain methods together, internal class state manages changes, an example is something like `builder.getProduct().listParts()`. With this project, I was interested in creating generating the code for a class from a small definition. \n\n```\nrequest*: Request\npathname*: string\nmatch: MatchHandler\u003cM\u003e\ndata: DataHandler\u003cM, D\u003e\ncomponent: ComponentHandler\u003cM\u003e\n```\n\n\u003e Note: the `*` syntax means the type is a \"native\" type and it shouldn't be included when using the `importsFrom` option.\n\nBuilds a class with these methods:\n\n```ts\nnew Leaf()\n  .request(new Request('https://example.com'))  \n  .pathname('/hello-world')\n  .match(async (_req, ctx) =\u003e {\n    const match = new URLPattern({ pathname: ctx.pathname }).exec(ctx.url.pathname)\n    const age = ctx.url.searchParams.get('age')\n    if (!match) return null\n    if (!age) throw new Error('missing age param')\n    const x = await Promise.resolve({ age })\n    return x\n  })\n  .data(async data =\u003e {\n    const x = await Promise.resolve({ ...data })\n    return { age: parseInt(x.age)}\n  })\n  .component(props =\u003e {\n    return \u003cdiv\u003e{props.age}\u003c/div\u003e\n  })\n```\n\nWhere the return value is a class with these properties.\n\n```\n{\n  request: Request\n  pathname: string,\n  match: MatchHandler\u003cM\u003e,\n  data: DataHandler\u003cM, D\u003e,\n  component: ComponentHandler\u003cM\u003e,\n}\n```\n\nThis example was created using Deno, you can build the code using:\n\n```bash\ndeno run -A ./example/build.ts \u003e example/leaf.ts\n```\n\nand run the usage using:\n\n```bash\ndeno run example/usage.tsx\n```\n\nCLI Usage example:\n\n```bash\ndeno run --allow-read ./bin.ts ./example/Leaf.lbc\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freggi%2Flinear_builder_class","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freggi%2Flinear_builder_class","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freggi%2Flinear_builder_class/lists"}