@nemmtor/ts-databuilders 0.0.1-alpha.21 → 0.0.1-alpha.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Configuration is optional - it fallbacks to sensible defaults.
19
19
 
20
20
  ### Configure via CLI flags (optional):
21
21
  ```bash
22
- pnpm ts-databuilders --include "src/**/*.ts{,x}" --output-dir src/__generated__ --jsdoc-tag DataBuilder
22
+ pnpm ts-databuilders --include "src/**/*.ts{,x}" --output-dir src/__generated__ --builder-jsdoc-tag-name DataBuilder
23
23
  ```
24
24
  You can also provide configuration by going through interactive wizard:
25
25
  ```bash
@@ -34,8 +34,8 @@ Example of default config file:
34
34
  ```json
35
35
  {
36
36
  "$schema": "https://raw.githubusercontent.com/nemmtor/ts-databuilders/refs/heads/main/schema.json",
37
- "jsdocTag": "DataBuilder",
38
- "inlineDefaultJsdocTag": "DataBuilderDefault",
37
+ "builderJsDocTagName": "DataBuilder",
38
+ "inlineDefaultJsDocTagName": "DataBuilderDefault",
39
39
  "withNestedBuilders": true,
40
40
  "outputDir": "generated/builders",
41
41
  "include": "src/**/*.ts{,x}",
@@ -64,8 +64,9 @@ pnpm ts-databuilders init --wizard
64
64
 
65
65
  | Name (in config file) | Flag (cli flags) | Description | Default |
66
66
  |---------------|-------------------------------------------------------|-----------------------------------------|----------------------|
67
- | jsdocTag | `--jsdoc-tag` | JSDoc tag to mark types for generation | `DataBuilder` |
68
- | inlineDefaultJsdocTag | `--inline-default-jsdoc-tag` | JSDoc tag used to set default value of given field | `DataBuilderDefault` |
67
+ | tsconfig | `--tsconfig -t` | Path to tsconfig file | `tsconfig.json` |
68
+ | builderJsDocTagName | `--builder-jsdoc-tag-name` | JSDoc tag to mark types for generation | `DataBuilder` |
69
+ | inlineDefaultJsDocTagName | `--inline-default-jsdoc-tag-name` | JSDoc tag used to set default value of given field | `DataBuilderDefault` |
69
70
  | withNestedBuilders | `--with-nested-builders` | When set to true ts-databuilders will use nested builders approach | `true` |
70
71
  | outputDir | `--output-dir -o` | Output directory for generated builders | `generated/builders` |
71
72
  | include | `--include -i` | Glob pattern for source files | `src/**/*.ts{,x}` |
@@ -79,6 +80,20 @@ pnpm ts-databuilders init --wizard
79
80
  #### Debugging
80
81
  In order to turn on debug logs pass a flag: `--log-level debug`.
81
82
 
83
+ #### TSConfig References
84
+ If your project uses multiple tsconfig files, point ts-databuilders to the one that includes your source files in its `include` field.
85
+
86
+ ```bash
87
+ pnpm ts-databuilders --tsconfig tsconfig.app.json
88
+ ```
89
+
90
+ Or in config file:
91
+ ```json
92
+ {
93
+ "tsconfig": "tsconfig.app.json"
94
+ }
95
+ ```
96
+
82
97
  ## Quick Start
83
98
  **1. Annotate your types with JSDoc:**
84
99
  ```ts
package/dist/main.js CHANGED
@@ -1,24 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import*as ft from"@effect/platform-node/NodeContext";import*as pt from"@effect/platform-node/NodeRuntime";import*as ut from"effect/Effect";import*as mt from"effect/Layer";import*as gt from"effect/Logger";import*as St from"effect/LogLevel";import*as J from"@effect/cli/Command";import*as r from"@effect/cli/Options";import*as ne from"effect/Layer";import{Project as xt}from"ts-morph";import*as Ie from"@effect/platform/FileSystem";import*as ke from"@effect/platform/Path";import*as m from"effect/Effect";import*as D from"effect/Match";import*as Ye from"effect/Option";import*as H from"effect/Schema";import*as Ce from"@effect/platform/FileSystem";import*as je from"@effect/platform/Path";import*as Ge from"effect/Context";import*as x from"effect/Effect";import*as k from"effect/Option";import*as i from"effect/Schema";var C={jsdocTag:"JSDoc tag used to mark types for data building generation.",inlineDefaultJsdocTag:"JSDoc tag used to set default value of given field.",withNestedbuilders:"When set to true ts-databuilders will use nested builders approach.",outputDir:"Output directory for generated builders.",include:"Glob pattern for files included while searching for jsdoc tag.",fileSuffix:"File suffix for created builder files.",fileCase:"Naming convention for generated builder file",builderSuffix:"Suffix for generated classes.",defaults:"Default values to be used in data builder constructor.",defaultString:"Default string value to be used in data builder constructor.",defaultNumber:"Default number value to be used in data builder constructor.",defaultBoolean:"Default boolean value to be used in data builder constructor."};import*as ue from"effect/Effect";var R=class extends ue.Service()("@TSDataBuilders/Process",{succeed:{cwd:ue.sync(()=>process.cwd())}}){};var Tt=e=>e!==void 0,re=e=>Object.fromEntries(Object.entries(e).filter(([o,c])=>Tt(c)));var Oe="ts-databuilders.json",Et=i.Struct({jsdocTag:i.NonEmptyTrimmedString,inlineDefaultJsdocTag:i.NonEmptyTrimmedString,withNestedBuilders:i.Boolean,outputDir:i.NonEmptyTrimmedString,include:i.NonEmptyTrimmedString,fileSuffix:i.NonEmptyTrimmedString,fileCase:i.Literal("kebab","camel","pascal"),builderSuffix:i.NonEmptyTrimmedString,defaults:i.Struct({string:i.String,number:i.Number,boolean:i.Boolean})}),j=Et.make({jsdocTag:"DataBuilder",inlineDefaultJsdocTag:"DataBuilderDefault",withNestedBuilders:!0,outputDir:"generated/builders",include:"src/**/*.ts{,x}",fileSuffix:".builder",fileCase:"kebab",builderSuffix:"Builder",defaults:{string:"",number:0,boolean:!1}}),De=i.Struct({$schema:i.optional(i.String),jsdocTag:i.String.pipe(i.annotations({description:C.jsdocTag})),inlineDefaultJsdocTag:i.String.pipe(i.annotations({description:C.inlineDefaultJsdocTag})),withNestedBuilders:i.Boolean.pipe(i.annotations({description:C.withNestedbuilders})),outputDir:i.String.pipe(i.annotations({description:C.outputDir})),include:i.String.pipe(i.annotations({description:C.include})),fileSuffix:i.String.pipe(i.annotations({description:C.fileSuffix})),fileCase:i.Literal("kebab","camel","pascal").pipe(i.annotations({description:C.fileCase})),builderSuffix:i.String.pipe(i.annotations({description:C.builderSuffix})),defaults:i.Struct({string:i.String.pipe(i.annotations({description:C.defaultString})),number:i.Number.pipe(i.annotations({description:C.defaultNumber})),boolean:i.Boolean.pipe(i.annotations({description:C.defaultBoolean}))}).pipe(i.partial,i.annotations({description:C.defaults}))}).pipe(i.partial),L=class extends Ge.Tag("Configuration")(){},G=i.Struct({jsdocTag:i.NonEmptyTrimmedString,inlineDefaultJsdocTag:i.NonEmptyTrimmedString,withNestedBuilders:i.BooleanFromString,outputDir:i.NonEmptyTrimmedString,include:i.NonEmptyTrimmedString,fileSuffix:i.NonEmptyTrimmedString,fileCase:i.Literal("kebab","camel","pascal"),builderSuffix:i.NonEmptyTrimmedString,defaultString:i.String,defaultNumber:i.NumberFromString,defaultBoolean:i.BooleanFromString}),_e=e=>x.gen(function*(){yield*x.logDebug("[Configuration]: Loading configuration");let c=yield*(yield*R).cwd,d=(yield*je.Path).join(c,Oe),a=yield*Ot(d),E=yield*Nt({fromCLI:e,fromConfigFile:a});return L.of(E)}),Nt=e=>x.gen(function*(){let o=Ct(e),c=k.flatMap(e.fromConfigFile,E=>k.fromNullable(E.defaults)).pipe(k.map(E=>re(E)),k.getOrElse(()=>({}))),f=re({string:e.fromCLI.defaultString.pipe(k.getOrUndefined),number:e.fromCLI.defaultNumber.pipe(k.getOrUndefined),boolean:e.fromCLI.defaultBoolean.pipe(k.getOrUndefined)}),d={...c,...f},a={builderSuffix:yield*o("builderSuffix"),include:yield*o("include"),withNestedBuilders:yield*o("withNestedBuilders"),fileSuffix:yield*o("fileSuffix"),fileCase:yield*o("fileCase"),jsdocTag:yield*o("jsdocTag"),inlineDefaultJsdocTag:yield*o("inlineDefaultJsdocTag"),outputDir:yield*o("outputDir"),defaults:{...j.defaults,...d}};return yield*x.logDebug(`[Configuration]: Resolving config with value: ${JSON.stringify(a,null,4)}`),a}),Ct=e=>o=>e.fromCLI[o].pipe(x.orElse(()=>k.flatMap(e.fromConfigFile,c=>k.fromNullable(c[o]))),x.orElseSucceed(()=>j[o])),Ot=e=>x.gen(function*(){let o=yield*Ce.FileSystem;if(yield*x.orDie(o.exists(e))){yield*x.logDebug("[Configuration]: Found config file - attempting to read it");let f=yield*Dt(e),d=yield*i.decodeUnknown(De)(f);return k.some(d)}else return yield*x.logDebug("[Configuration]: No config file found"),k.none()}),Dt=e=>x.gen(function*(){let o=yield*Ce.FileSystem,c=yield*x.orDie(o.readFileString(e));return yield*x.try({try:()=>JSON.parse(c),catch:f=>`[FileSystem] Unable to read and parse JSON file from '${e}': ${String(f)}`})}).pipe(x.orDie);import*as B from"effect/Schema";var be=B.transform(B.String,B.String.pipe(B.brand("KebabCase")),{decode:e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z])([A-Z][a-z])/g,"$1-$2").replace(/_/g,"-").toLowerCase(),encode:e=>e}),we=B.transform(B.String,B.String.pipe(B.brand("PascalCase")),{decode:e=>e.split(/[-_\s]+/).flatMap(o=>o.split(/(?=[A-Z])/)).filter(Boolean).map(o=>o.charAt(0).toUpperCase()+o.slice(1).toLowerCase()).join(""),encode:e=>e}),xe=B.transform(B.String,B.String.pipe(B.brand("CamelCase")),{decode:e=>e.split(/[-_\s]+/).flatMap(o=>o.split(/(?=[A-Z])/)).filter(Boolean).map((o,c)=>{let f=o.toLowerCase();return c===0?f:f.charAt(0).toUpperCase()+f.slice(1)}).join(""),encode:e=>e});import{randomUUID as wt}from"crypto";import*as me from"effect/Effect";var z=class extends me.Service()("@TSDataBuilders/IdGenerator",{succeed:{generateUuid:me.sync(()=>wt())}}){};var ge=class extends m.Service()("@TSDataBuilders/BuilderGenerator",{effect:m.gen(function*(){let o=yield*Ie.FileSystem,c=yield*ke.Path,f=yield*R,d=yield*L,a=yield*z,{fileSuffix:E,builderSuffix:O,defaults:g,fileCase:T}=d,u=m.fnUntraced(function*(n){return yield*{kebab:be.pipe(H.decode),pascal:we.pipe(H.decode),camel:xe.pipe(H.decode)}[T](n)}),s=n=>Ye.getOrUndefined(n.inlineDefault)??D.value(n).pipe(D.when({kind:"STRING"},()=>`"${g.string}"`),D.when({kind:"NUMBER"},()=>g.number),D.when({kind:"BOOLEAN"},()=>g.boolean),D.when({kind:"UNDEFINED"},()=>{}),D.when({kind:"BIGINT"},()=>"BigInt(0)"),D.when({kind:"SYMBOL"},()=>"Symbol('')"),D.when({kind:"ANY"},()=>{}),D.when({kind:"UNKNOWN"},()=>{}),D.when({kind:"NULL"},()=>null),D.when({kind:"DATE"},()=>"new Date()"),D.when({kind:"ARRAY"},()=>"[]"),D.when({kind:"LITERAL"},l=>l.literalValue),D.when({kind:"TYPE_CAST"},l=>s(l.baseTypeMetadata)),D.when({kind:"TUPLE"},l=>`[${l.members.map(P=>s(P)).map(P=>`${P}`).join(", ")}]`),D.when({kind:"TYPE_LITERAL"},l=>`{${Object.entries(l.metadata).filter(([P,{optional:y}])=>!y).map(([P,y])=>`${P}: ${s(y)}`).join(", ")}}`),D.when({kind:"RECORD"},l=>{if(l.keyType.kind==="STRING"||l.keyType.kind==="NUMBER")return"{}";let S=s(l.keyType),P=s(l.valueType);return`{${S}: ${P}}`}),D.when({kind:"UNION"},l=>{let P=l.members.slice().sort((y,N)=>{let I=Je.indexOf(y.kind),w=Je.indexOf(N.kind);return(I===-1?1/0:I)-(w===-1?1/0:w)})[0];return P?s(P):"never"}),D.when({kind:"BUILDER"},l=>`new ${l.name}${O}().build()`),D.exhaustive);return{generateBaseBuilder:m.fnUntraced(function*(){let n=c.join(yield*f.cwd,d.outputDir),l=c.resolve(n,`${yield*u("dataBuilder")}.ts`);yield*m.logDebug(`[Builders]: Creating base builder at ${l}`),yield*m.orDie(o.writeFileString(l,`${It}
3
- `))}),generateBuilder:m.fnUntraced(function*(n){let l=new xt,S=n.name;yield*m.logDebug(`[Builders]: Creating builder for ${S}`);let P=c.join(yield*f.cwd,d.outputDir),y=c.resolve(P,`${yield*u(S)}${E}.ts`);yield*m.logDebug(`[Builders]: Creating builder content for ${S}`);let N=l.createSourceFile(`__temp_${yield*a.generateUuid}.ts`,"",{overwrite:!0}),I=c.resolve(n.path),w=c.relative(c.dirname(y),I).replace(/\.ts$/,"");if(N.addImportDeclaration({namedImports:[S],isTypeOnly:!0,moduleSpecifier:w}),N.addImportDeclaration({namedImports:["DataBuilder"],moduleSpecifier:"./data-builder"}),n.shape.kind!=="TYPE_LITERAL")return yield*m.dieMessage("[BuilderGenerator]: Expected root type to be type literal");let b=[...new Set(kt(n.shape.metadata))];yield*m.forEach(b,F=>be.pipe(H.decode)(F).pipe(m.andThen(A=>N.addImportDeclaration({namedImports:[`${F}${O}`],moduleSpecifier:`./${A}${E}`}))),{concurrency:"unbounded"});let v=Object.entries(n.shape.metadata).filter(([F,{optional:A}])=>!A).map(([F,A])=>`${F}: ${A.kind==="TYPE_CAST"?`${s(A)} as ${S}['${F}']`:s(A)}`),Z=yield*m.all(Object.entries(n.shape.metadata).map(([F,{optional:A,kind:fe}])=>Pt({fieldName:F,optional:A,typeName:S,isNestedBuilder:fe==="BUILDER"})),{concurrency:"unbounded"}),W=`{
4
- ${v.join(`,
5
- `)}
6
- }`;N.addClass({name:`${S}${O}`,isExported:!0,extends:`DataBuilder<${S}>`,methods:[{name:"constructor",statements:[`super(${W});`]},...Z]}),yield*m.logDebug(`[Builders]: Saving builder content at ${y}`),yield*o.writeFileString(y,`${N.getText()}
7
- `)})}}),dependencies:[z.Default]}){},Je=["UNDEFINED","BOOLEAN","NUMBER","STRING","DATE","LITERAL","TYPE_LITERAL","ARRAY","TUPLE","RECORD"],It=`export abstract class DataBuilder<T> {
8
- private data: T;
9
-
10
- constructor(initialData: T) {
11
- this.data = initialData;
12
- }
13
-
14
- public build(): Readonly<T> {
15
- return structuredClone(this.data);
16
- }
17
-
18
- protected with(partial: Partial<T>): this {
19
- this.data = { ...this.data, ...partial };
20
- return this;
21
- }
22
- }
23
- `;function kt(e){let o=[];function c(f){switch(f.kind){case"BUILDER":o.push(f.name);break;case"TYPE_LITERAL":Object.values(f.metadata).forEach(c);break;case"UNION":case"TUPLE":f.members.forEach(c);break;case"RECORD":c(f.keyType),c(f.valueType);break}}return Object.values(e).forEach(c),o}var Pt=e=>m.gen(function*(){let{fieldName:o,optional:c,typeName:f,isNestedBuilder:d}=e,a=o.replaceAll("'","").replaceAll('"',""),E=yield*xe.pipe(H.decode)(a),O=`with${yield*we.pipe(H.decode)(a)}`,g=[`return this.with({ ${o}: ${E} });`],T=[`return this.with({ ${o}: ${E}.build() });`],u=d?T:g,s=[`if (!${E}) {`,` const { "${a}": _unused, ...rest } = this.build();`," return this.with(rest);","}"],n=c?[...s,...u]:u,l=`${f}['${a}']`;return{name:O,isPublic:!0,parameters:[{name:E,type:d?`DataBuilder<${l}>`:l}],statements:n}}),Q=class extends m.Service()("@TSDataBuilders/BuildersGenerator",{effect:m.gen(function*(){let o=yield*Ie.FileSystem,c=yield*ge,f=yield*R,d=yield*ke.Path,a=yield*L;return{create:m.fnUntraced(function*(E){let O=d.join(yield*f.cwd,a.outputDir);(yield*m.orDie(o.exists(O)))&&(yield*m.logDebug(`[Builders]: Removing already existing output directory at ${O}`),yield*m.orDie(o.remove(O,{recursive:!0}))),yield*m.logDebug(`[Builders]: Creating output directory at ${O}`),yield*m.orDie(o.makeDirectory(O,{recursive:!0})),yield*c.generateBaseBuilder();let T=E.map(n=>n.name),u=T.filter((n,l)=>T.indexOf(n)!==l),s=[...new Set(u)];if(u.length>0)return yield*m.dieMessage(`Duplicated builders: ${s.join(", ")}`);yield*m.all(E.map(n=>c.generateBuilder(n)),{concurrency:"unbounded"})})}}),dependencies:[ge.Default]}){};import*as Ve from"@effect/platform/FileSystem";import*as Ze from"@effect/platform/Path";import*as ze from"effect/Effect";import*as U from"effect/Option";import*as qe from"effect/Schema";var He=e=>ze.gen(function*(){let o=yield*R,c=yield*Ve.FileSystem,f=yield*o.cwd,a=(yield*Ze.Path).join(f,Oe),E=re({string:e.defaultString.pipe(U.getOrUndefined),number:e.defaultNumber.pipe(U.getOrUndefined),boolean:e.defaultBoolean.pipe(U.getOrUndefined)}),O=yield*qe.decode(De)({$schema:"https://raw.githubusercontent.com/nemmtor/ts-databuilders/refs/heads/main/schema.json",builderSuffix:e.builderSuffix.pipe(U.getOrElse(()=>j.builderSuffix)),fileSuffix:e.fileSuffix.pipe(U.getOrElse(()=>j.fileSuffix)),fileCase:e.fileCase.pipe(U.getOrElse(()=>j.fileCase)),include:e.include.pipe(U.getOrElse(()=>j.include)),jsdocTag:e.jsdocTag.pipe(U.getOrElse(()=>j.jsdocTag)),inlineDefaultJsdocTag:e.inlineDefaultJsdocTag.pipe(U.getOrElse(()=>j.inlineDefaultJsdocTag)),withNestedBuilders:e.withNestedBuilders.pipe(U.getOrElse(()=>j.withNestedBuilders)),outputDir:e.outputDir.pipe(U.getOrElse(()=>j.outputDir)),defaults:{...j.defaults,...E}});yield*c.writeFileString(a,`${JSON.stringify(O,null,2)}
24
- `)});import*as ee from"effect/Chunk";import*as M from"effect/Effect";import*as ye from"effect/Option";import*as he from"effect/Stream";import*as Qe from"@effect/platform/FileSystem";import*as Xe from"effect/Chunk";import*as Y from"effect/Effect";import*as _ from"effect/Stream";var se=class extends Y.Service()("@TSDataBuilders/FileContentChecker",{effect:Y.gen(function*(){let o=yield*Qe.FileSystem,c=new TextDecoder;return{check:Y.fnUntraced(function*(f){let{content:d,filePath:a}=f;return yield*Y.logDebug(`[FileContentChecker](${a}): Checking file content`),yield*_.orDie(o.stream(a,{chunkSize:16*1024})).pipe(_.map(g=>c.decode(g,{stream:!0})),_.mapAccum("",(g,T)=>{let u=g+T;return[u.slice(-d.length+1),u.includes(d)]}),_.find(g=>!!g),_.tap(()=>Y.logDebug(`[FileContentChecker](${a}): found expected content`)),_.runCollect,Y.map(g=>g.pipe(Xe.get(0))))})}})}){};import*as et from"effect/Data";import*as q from"effect/Effect";import*as tt from"effect/Stream";import{glob as Ft}from"glob";import*as Se from"effect/Effect";var ce=class extends Se.Service()("@TSDataBuilders/Glob",{succeed:{iterate:o=>Se.sync(()=>Ft.iterate(o.path,{cwd:o.cwd,nodir:!0}))}}){};var de=class extends q.Service()("@TSDataBuilders/TreeWalker",{effect:q.gen(function*(){let o=yield*ce,c=yield*R;return{walk:q.fnUntraced(function*(f){let d=yield*c.cwd;return yield*q.logDebug(`[TreeWalker]: Walking path: ${d}/${f}`),tt.fromAsyncIterable(yield*o.iterate({path:f,cwd:d}),a=>new Pe({cause:a}))})}}),dependencies:[ce.Default]}){},Pe=class extends et.TaggedError("TreeWalkerError"){};var X=class extends M.Service()("@TSDataBuilders/Finder",{effect:M.gen(function*(){let o=yield*se,c=yield*de,{include:f,jsdocTag:d}=yield*L,a=`@${d}`;return{find:M.gen(function*(){yield*M.logDebug("[Finder]: Attempting to find files with builders");let O=yield*(yield*c.walk(f)).pipe(he.mapEffect(g=>o.check({filePath:g,content:a}).pipe(M.map(T=>T.pipe(ye.map(()=>g)))),{concurrency:"unbounded"}),he.runCollect,M.map(ee.filter(g=>ye.isSome(g))),M.map(ee.map(g=>g.value)));return yield*M.logDebug(`[Finder]: Found builders in files: ${O.pipe(ee.toArray).join(", ")}`),O}).pipe(M.catchTag("TreeWalkerError",E=>M.die(E)))}}),dependencies:[de.Default,se.Default]}){};import{Node as Rt,Project as Lt,SyntaxKind as h}from"ts-morph";import*as nt from"@effect/platform/FileSystem";import*as V from"effect/Data";import*as t from"effect/Effect";import*as le from"effect/Either";import*as p from"effect/Match";import*as K from"effect/Option";var Te=class extends t.Service()("@TSDataBuilders/TypeNodeParser",{effect:t.gen(function*(){let{jsdocTag:o,inlineDefaultJsdocTag:c,withNestedBuilders:f}=yield*L,d=yield*z,a=t.fnUntraced(function*(T){let u=T.getJsDocs();for(let s of u){let l=s.getTags().find(S=>S.getTagName()===c);if(l){let S=l.getComment();if(typeof S=="string")return K.some(S.trim())}}return K.none()}),E=t.fnUntraced(function*(T){let{type:u,contextNode:s}=T,n=u.getProperties(),l={};for(let S of n){let P=S.getName(),y=S.getTypeAtLocation(s),N=S.isOptional(),I=s.getProject().createSourceFile(`__temp_${yield*d.generateUuid}.ts`,`type __T = ${y.getText()}`,{overwrite:!0}),w=I.getTypeAliasOrThrow("__T").getTypeNodeOrThrow(),b=yield*t.suspend(()=>g({typeNode:w,optional:N,inlineDefault:K.none()}));l[P]=b,s.getProject().removeSourceFile(I)}return l}),O=t.fnUntraced(function*(T){let{type:u,contextNode:s,optional:n,inlineDefault:l}=T;return!u.isObject()||u.getProperties().length===0?yield*new Fe({raw:u.getText(),kind:s.getKind()}):{kind:"TYPE_LITERAL",metadata:yield*E({type:u,contextNode:s}),inlineDefault:l,optional:n}}),g=T=>t.gen(function*(){let{typeNode:u,optional:s,inlineDefault:n}=T,l=u.getKind(),S=p.value(l).pipe(p.when(p.is(h.StringKeyword),()=>t.succeed({kind:"STRING",inlineDefault:n,optional:s})),p.when(p.is(h.NumberKeyword),()=>t.succeed({kind:"NUMBER",inlineDefault:n,optional:s})),p.when(p.is(h.BooleanKeyword),()=>t.succeed({kind:"BOOLEAN",inlineDefault:n,optional:s})),p.when(p.is(h.UndefinedKeyword),()=>t.succeed({kind:"UNDEFINED",inlineDefault:n,optional:s})),p.when(p.is(h.BigIntKeyword),()=>t.succeed({kind:"BIGINT",inlineDefault:n,optional:s})),p.when(p.is(h.SymbolKeyword),()=>t.succeed({kind:"SYMBOL",inlineDefault:n,optional:s})),p.when(p.is(h.AnyKeyword),()=>t.succeed({kind:"ANY",inlineDefault:n,optional:s})),p.when(p.is(h.UnknownKeyword),()=>t.succeed({kind:"UNKNOWN",inlineDefault:n,optional:s})),p.when(p.is(h.ArrayType),()=>t.succeed({kind:"ARRAY",inlineDefault:n,optional:s})),p.when(p.is(h.LiteralType),()=>{let y=u.asKindOrThrow(h.LiteralType).getLiteral().getText();return y==="null"?t.succeed({kind:"NULL",inlineDefault:n,optional:s}):t.succeed({kind:"LITERAL",inlineDefault:n,literalValue:y,optional:s})}),p.when(p.is(h.TypeLiteral),()=>t.gen(function*(){let N=u.asKindOrThrow(h.TypeLiteral).getMembers(),I=yield*t.reduce(N,{},(w,b)=>t.gen(function*(){if(!b.isKind(h.PropertySignature))return w;let v=b.getTypeNode();if(!v)return w;let Z=b.getNameNode().getText(),W=b.hasQuestionToken(),F=yield*a(b),A=yield*t.suspend(()=>g({typeNode:v,optional:W,inlineDefault:F}));return{...w,[Z]:A}}));return{kind:"TYPE_LITERAL",inlineDefault:n,metadata:I,optional:s}})),p.when(p.is(h.ImportType),()=>t.gen(function*(){let y=u.asKindOrThrow(h.ImportType),N=y.getType(),I=N.getSymbol(),w=N.getText();if(!I)return yield*new Le({raw:w});let b=I.getDeclarations();if(b&&b.length>1)return yield*new Ne({raw:w});let[v]=b;return v?yield*O({type:N,contextNode:y,inlineDefault:n,optional:s}):yield*new Ee({raw:w})})),p.when(p.is(h.TupleType),()=>t.gen(function*(){let N=u.asKindOrThrow(h.TupleType).getElements(),I=yield*t.all(N.map(w=>t.suspend(()=>g({typeNode:w,optional:!1,inlineDefault:K.none()}))),{concurrency:"unbounded"});return{kind:"TUPLE",inlineDefault:n,optional:s,members:I}})),p.when(p.is(h.TypeReference),()=>t.gen(function*(){let y=u.asKindOrThrow(h.TypeReference),N=y.getTypeName().getText();if(N==="Date")return{kind:"DATE",optional:s,inlineDefault:n};if(N==="Array")return{kind:"ARRAY",optional:s,inlineDefault:n};let I=y.getTypeArguments();if(N==="Record"){let[pe,Ue]=I;if(!pe||!Ue)return yield*new te({kind:l,raw:u.getText()});let yt=yield*t.suspend(()=>g({typeNode:pe,optional:!1,inlineDefault:K.none()})),ht=yield*t.suspend(()=>g({typeNode:Ue,optional:!1,inlineDefault:K.none()}));return{kind:"RECORD",keyType:yt,valueType:ht,optional:s,inlineDefault:n}}if(["Pick","Omit","Partial","Required","Readonly","Extract","NonNullable"].includes(N))return yield*O({type:y.getType(),contextNode:y,optional:s,inlineDefault:n});let b=y.getType(),v=b.getText(),Z=b.getAliasSymbol();if(!Z)return yield*O({type:b,contextNode:y,optional:s,inlineDefault:n});let W=Z.getDeclarations();if(W&&W.length>1)return yield*new Ne({raw:v});let[F]=W;if(!F)return yield*new Ee({raw:v});let A=Z?.getJsDocTags().map(pe=>pe.getName()).includes(o);if(!Rt.isTypeAliasDeclaration(F))return yield*new Me;let fe=F.getTypeNode();return fe?!A||!f?yield*t.suspend(()=>g({typeNode:fe,optional:s,inlineDefault:n})):{kind:"BUILDER",name:F.getName(),inlineDefault:n,optional:s}:yield*new te({kind:l,raw:v})})),p.when(p.is(h.UnionType),()=>t.gen(function*(){let y=yield*t.all(u.asKindOrThrow(h.UnionType).getTypeNodes().map(N=>t.suspend(()=>g({typeNode:N,optional:!1,inlineDefault:K.none()}))),{concurrency:"unbounded"});return{kind:"UNION",optional:s,members:y,inlineDefault:n}})),p.when(p.is(h.IntersectionType),()=>t.gen(function*(){let y=u.asKindOrThrow(h.IntersectionType),N=y.getTypeNodes(),I=[h.StringKeyword,h.NumberKeyword,h.BooleanKeyword],w=N.find(W=>I.includes(W.getKind()));if(w&&N.length>1)return{kind:"TYPE_CAST",baseTypeMetadata:yield*t.suspend(()=>g({typeNode:w,optional:!1,inlineDefault:n})),inlineDefault:n,optional:s};let b=y.getType();return b.getProperties().length===0?yield*new te({kind:l,raw:u.getText()}):{kind:"TYPE_LITERAL",metadata:yield*E({type:b,contextNode:y}),inlineDefault:n,optional:s}})),p.option);return K.isNone(S)?yield*new te({kind:l,raw:u.getText()}):yield*S.value});return{generateMetadata:g}}),dependencies:[z.Default]}){},ie=class extends t.Service()("@TSDataBuilders/Parser",{effect:t.gen(function*(){let o=yield*nt.FileSystem,c=yield*Te,{jsdocTag:f}=yield*L;return{generateBuildersMetadata:d=>t.gen(function*(){yield*t.logDebug(`[Parser](${d}): Generating builder metadata`),yield*t.logDebug(`[Parser](${d}): Reading source code`);let a=yield*t.orDie(o.readFileString(d)),E=yield*t.try({try:()=>new Lt().createSourceFile(d,a,{overwrite:!0}).getTypeAliases().filter(n=>n.getJsDocs().flatMap(l=>l.getTags().flatMap(S=>S.getTagName())).includes(f)).map(n=>{let l=n.getName();if(!n.isExported())return le.left(new Ae({typeName:l}));let S=n.getTypeNode();return S?.isKind(h.TypeLiteral)||S?.isKind(h.TypeReference)?le.right({name:n.getName(),node:S}):le.left(new Re({typeName:n.getName()}))}).filter(Boolean),catch:T=>new Be({cause:T})}),O=yield*t.all(E.map(T=>T),{concurrency:"unbounded"});return yield*t.logDebug(`[Parser](${d}): Generating metadata for types: ${O.map(({name:T})=>T).join(", ")}`),yield*t.all(O.map(({name:T,node:u})=>c.generateMetadata({typeNode:u,optional:!1,inlineDefault:K.none()}).pipe(t.tap(()=>t.logDebug(`[Parser](${d}): Finished generating metadata for type: ${T}`)),t.map(s=>({name:T,shape:s,path:d})))),{concurrency:"unbounded"})}).pipe(t.catchTags({ParserError:a=>t.die(a),MissingSymbolDeclarationError:a=>t.dieMessage(`[Parser](${d}): Missing symbol declaration for type: ${a.raw}`),UnsupportedTypeAliasDeclarationError:()=>t.dieMessage(`[Parser](${d}): Unsupported type alias declaration`),MultipleSymbolDeclarationsError:a=>t.dieMessage(`[Parser](${d}): Missing symbol declaration error for type: ${a.raw}`),MissingSymbolError:a=>t.dieMessage(`[Parser](${d}): Missing symbol error for type: ${a.raw}`),UnexportedDatabuilderError:a=>t.dieMessage(`[Parser](${d}): Unexported databuilder ${a.typeName}`),UnsupportedSyntaxKindError:a=>t.dieMessage(`[Parser](${d}): Unsupported syntax kind of id: ${a.kind} for type: ${a.raw}`),CannotBuildTypeReferenceMetadataError:a=>t.dieMessage(`[Parser](${d}): Cannot build type reference metadata with kind of id: ${a.kind} for type: ${a.raw}. Is it a root of databuilder?`),UnsupportedBuilderTypeError:a=>t.dieMessage(`[Parser](${d}): Unsupported builder type ${a.typeName}`)}))}}),dependencies:[Te.Default]}){},te=class extends V.TaggedError("UnsupportedSyntaxKindError"){},Me=class extends V.TaggedError("UnsupportedTypeAliasDeclarationError"){},Fe=class extends V.TaggedError("CannotBuildTypeReferenceMetadataError"){},Be=class extends V.TaggedError("ParserError"){},Ae=class extends V.TaggedError("UnexportedDatabuilderError"){},Re=class extends V.TaggedError("UnsupportedBuilderTypeError"){},Le=class extends V.TaggedError("MissingSymbolError"){},Ee=class extends V.TaggedError("MissingSymbolDeclarationError"){},Ne=class extends V.TaggedError("MultipleSymbolDeclarationsError"){};import*as rt from"effect/Chunk";import*as $ from"effect/Effect";import*as at from"effect/Function";var st=$.gen(function*(){let e=yield*X,o=yield*ie,c=yield*Q;yield*$.logInfo("[TSDatabuilders]: Generating builders for your project.");let f=yield*e.find;yield*$.logInfo(`[TSDatabuilders]: Found builders in ${f.length} file(s).`),yield*$.logDebug("[TSDatabuilders]: Attempting to generate builders metadata");let d=yield*$.all(rt.map(f,a=>o.generateBuildersMetadata(a)),{concurrency:"unbounded"}).pipe($.map(a=>a.flatMap(at.identity)));d.length!==0&&(yield*$.logDebug("[TSDatabuilders]: Attempting to create builders files"),yield*c.create(d),yield*$.logInfo(`[TSDatabuilders]: Created ${d.length} builder(s).`))});var ct="0.0.1-alpha.21";var $t=r.text("jsdoc-tag").pipe(r.withDescription(C.jsdocTag),r.withSchema(G.fields.jsdocTag),r.optional),vt=r.text("inline-default-jsdoc-tag").pipe(r.withDescription(C.inlineDefaultJsdocTag),r.withSchema(G.fields.inlineDefaultJsdocTag),r.optional),jt=r.text("with-nested-builders").pipe(r.withDescription(C.withNestedbuilders),r.withSchema(G.fields.withNestedBuilders),r.optional),Gt=r.text("output-dir").pipe(r.withAlias("o"),r.withDescription(C.outputDir),r.withSchema(G.fields.outputDir),r.optional),_t=r.text("include").pipe(r.withAlias("i"),r.withDescription(C.include),r.withSchema(G.fields.include),r.optional),Kt=r.text("file-case").pipe(r.withDescription(C.fileCase),r.withSchema(G.fields.fileCase),r.optional),Jt=r.text("file-suffix").pipe(r.withDescription(C.fileSuffix),r.withSchema(G.fields.fileSuffix),r.optional),Yt=r.text("builder-suffix").pipe(r.withDescription(C.builderSuffix),r.withSchema(G.fields.builderSuffix),r.optional),Wt=r.text("default-string").pipe(r.withDescription(C.defaultString),r.withSchema(G.fields.defaultString),r.optional),Vt=r.text("default-number").pipe(r.withDescription(C.defaultNumber),r.withSchema(G.fields.defaultNumber),r.optional),Zt=r.text("default-boolean").pipe(r.withDescription(C.defaultBoolean),r.withSchema(G.fields.defaultBoolean),r.optional),dt={jsdocTag:$t,outputDir:Gt,withNestedBuilders:jt,include:_t,fileSuffix:Jt,fileCase:Kt,builderSuffix:Yt,defaultString:Wt,defaultNumber:Vt,defaultBoolean:Zt,inlineDefaultJsdocTag:vt},zt=J.make("init",dt).pipe(J.withHandler(He)),qt=J.make("ts-databuilders",dt),lt=qt.pipe(J.withHandler(()=>st),J.withSubcommands([zt]),J.provide(e=>ne.mergeAll(X.Default,ie.Default,Q.Default).pipe(ne.provide(ne.effect(L,_e(e))))),J.run({name:"Typescript Databuilders generator",version:ct}));var Ht=mt.mergeAll(gt.minimumLogLevel(St.Info),R.Default,ft.layer);lt(process.argv).pipe(ut.provide(Ht),pt.runMain);
2
+ import*as oi from"@effect/platform-node/NodeContext";import*as ni from"@effect/platform-node/NodeRuntime";import*as ai from"effect/Effect";import*as U from"@effect/cli/Command";import*as l from"@effect/cli/Options";import*as fe from"effect/Layer";import*as Yr from"@effect/platform/FileSystem";import*as Hr from"@effect/platform/Path";import*as pe from"effect/Effect";import*as xr from"@effect/platform/FileSystem";import*as Jr from"@effect/platform/Path";import*as $r from"effect/Context";import*as T from"effect/Effect";import*as P from"effect/Option";import*as o from"effect/Schema";import*as jr from"effect/Data";import*as Y from"effect/Effect";var x=class extends Y.Service()("@TSDataBuilders/Process",{effect:Y.gen(function*(){return yield*Y.logDebug("[Process]: Instantiating"),{cwd:Y.try({try:()=>process.cwd(),catch:t=>new Nr({cause:t})})}})}){},Nr=class extends jr.TaggedError("GetProcessCwdError"){};var fi=r=>r!==void 0,Le=r=>Object.fromEntries(Object.entries(r).filter(([t,a])=>fi(a)));var m={tsconfig:"Path to tsconfig file. Useful in repos with multiple tsconfig files.",builderJsDocTagName:"JSDoc tag used to mark types for data building generation.",inlineDefaultJsDocTagName:"JSDoc tag used to set default value of given field.",withNestedbuilders:"When set to true ts-databuilders will use nested builders approach.",outputDir:"Output directory for generated builders.",include:"Glob pattern for files included while searching for jsdoc tag.",fileSuffix:"File suffix for created builder files.",fileCase:"Naming convention for generated builder file",builderSuffix:"Suffix for generated classes.",defaults:"Default values to be used in data builder constructor.",defaultString:"Default string value to be used in data builder constructor.",defaultNumber:"Default number value to be used in data builder constructor.",defaultBoolean:"Default boolean value to be used in data builder constructor."};var br="ts-databuilders.json",li=o.Struct({tsconfig:o.NonEmptyTrimmedString,builderJsDocTagName:o.NonEmptyTrimmedString,inlineDefaultJsDocTagName:o.NonEmptyTrimmedString,withNestedBuilders:o.Boolean,outputDir:o.NonEmptyTrimmedString,include:o.NonEmptyTrimmedString,fileSuffix:o.NonEmptyTrimmedString,fileCase:o.Literal("kebab","camel","pascal"),builderSuffix:o.NonEmptyTrimmedString,defaults:o.Struct({string:o.String,number:o.Number,boolean:o.Boolean})}),w=li.make({tsconfig:"tsconfig.json",builderJsDocTagName:"DataBuilder",inlineDefaultJsDocTagName:"DataBuilderDefault",withNestedBuilders:!0,outputDir:"generated/builders",include:"src/**/*.ts{,x}",fileSuffix:".builder",fileCase:"kebab",builderSuffix:"Builder",defaults:{string:"",number:0,boolean:!1}}),Or=o.Struct({$schema:o.optional(o.String),tsconfig:o.String.pipe(o.annotations({description:m.tsconfig})),builderJsDocTagName:o.String.pipe(o.annotations({description:m.builderJsDocTagName})),inlineDefaultJsDocTagName:o.String.pipe(o.annotations({description:m.inlineDefaultJsDocTagName})),withNestedBuilders:o.Boolean.pipe(o.annotations({description:m.withNestedbuilders})),outputDir:o.String.pipe(o.annotations({description:m.outputDir})),include:o.String.pipe(o.annotations({description:m.include})),fileSuffix:o.String.pipe(o.annotations({description:m.fileSuffix})),fileCase:o.Literal("kebab","camel","pascal").pipe(o.annotations({description:m.fileCase})),builderSuffix:o.String.pipe(o.annotations({description:m.builderSuffix})),defaults:o.Struct({string:o.String.pipe(o.annotations({description:m.defaultString})),number:o.Number.pipe(o.annotations({description:m.defaultNumber})),boolean:o.Boolean.pipe(o.annotations({description:m.defaultBoolean}))}).pipe(o.partial,o.annotations({description:m.defaults}))}).pipe(o.partial),N=class extends $r.Tag("Configuration")(){},F=o.Struct({tsconfig:o.NonEmptyTrimmedString,builderJsDocTagName:o.NonEmptyTrimmedString,inlineDefaultJsDocTagName:o.NonEmptyTrimmedString,withNestedBuilders:o.BooleanFromString,outputDir:o.NonEmptyTrimmedString,include:o.NonEmptyTrimmedString,fileSuffix:o.NonEmptyTrimmedString,fileCase:o.Literal("kebab","camel","pascal"),builderSuffix:o.NonEmptyTrimmedString,defaultString:o.String,defaultNumber:o.NumberFromString,defaultBoolean:o.BooleanFromString}),Vr=T.fnUntraced(function*(r){yield*T.logDebug("[Configuration]: Loading configuration");let a=yield*(yield*x).cwd,c=(yield*Jr.Path).join(a,br);yield*T.logDebug("[Configuration]: Attempting to resolve config file");let n=yield*ui(c);yield*T.logDebug("[Configuration]: Attempting to resolve config");let e=yield*pi({fromCLI:r,fromConfigFile:n});return yield*T.logDebug(`[Configuration]: Config resolved with: ${yield*o.encode(o.parseJson({replacer:null,space:2}))(e)}`),N.of(e)}),pi=T.fnUntraced(function*(r){let t=di(r),a=P.flatMap(r.fromConfigFile,e=>P.fromNullable(e.defaults)).pipe(P.map(e=>Le(e)),P.getOrElse(()=>({}))),i=Le({string:r.fromCLI.defaultString.pipe(P.getOrUndefined),number:r.fromCLI.defaultNumber.pipe(P.getOrUndefined),boolean:r.fromCLI.defaultBoolean.pipe(P.getOrUndefined)}),c={...a,...i};return{tsconfig:yield*t("tsconfig"),builderSuffix:yield*t("builderSuffix"),include:yield*t("include"),withNestedBuilders:yield*t("withNestedBuilders"),fileSuffix:yield*t("fileSuffix"),fileCase:yield*t("fileCase"),builderJsDocTagName:yield*t("builderJsDocTagName"),inlineDefaultJsDocTagName:yield*t("inlineDefaultJsDocTagName"),outputDir:yield*t("outputDir"),defaults:{...w.defaults,...c}}}),di=r=>t=>r.fromCLI[t].pipe(T.orElse(()=>P.flatMap(r.fromConfigFile,a=>P.fromNullable(a[t]))),T.orElseSucceed(()=>w[t])),ui=T.fnUntraced(function*(r){let t=yield*xr.FileSystem;if(yield*T.logDebug(`[Configuration]: Checking if config file exists at ${r}`),yield*T.orDie(t.exists(r))){yield*T.logDebug("[Configuration]: Found config file - attempting to read it");let i=yield*mi(r),c=yield*o.decodeUnknown(Or)(i);return P.some(c)}else return yield*T.logDebug("[Configuration]: No config file found"),P.none()}),mi=T.fnUntraced(function*(r){let t=yield*xr.FileSystem,a=yield*T.orDie(t.readFileString(r));return yield*o.decodeUnknown(o.parseJson())(a)},T.orDie);import*as _r from"effect/Effect";import*as Z from"effect/Match";import*as y from"effect/Schema";var Wr=y.transform(y.String,y.String,{decode:r=>r.replace(/^['"]|['"]$/g,""),encode:r=>r}),yi=y.transform(y.String,y.String.pipe(y.brand("KebabCase")),{decode:r=>r.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z])([A-Z][a-z])/g,"$1-$2").replace(/_/g,"-").toLowerCase(),encode:r=>r}),wr=y.transform(y.String,y.String.pipe(y.brand("PascalCase")),{decode:r=>r.split(/[-_\s]+/).map(t=>t===t.toUpperCase()?t.charAt(0).toUpperCase()+t.slice(1).toLowerCase():t.split(/(?=[A-Z])/).filter(Boolean).map(a=>a.charAt(0).toUpperCase()+a.slice(1).toLowerCase()).join("")).join(""),encode:r=>r}),gi=y.transform(y.String,y.String.pipe(y.brand("CamelCase")),{decode:r=>r.split(/[-_\s]+/).flatMap(t=>t.split(/(?=[A-Z])/)).filter(Boolean).map((t,a)=>{let i=t.toLowerCase();return a===0?i:i.charAt(0).toUpperCase()+i.slice(1)}).join(""),encode:r=>r}),_e=_r.fnUntraced(function*(r){return Z.value(r).pipe(Z.when("kebab",()=>yi.pipe(y.decode)),Z.when("pascal",()=>wr.pipe(y.decode)),Z.when("camel",()=>gi.pipe(y.decode)),Z.exhaustive)});import Ti from"handlebars";import*as qr from"effect/Data";import*as ee from"effect/Effect";var X=class extends ee.Service()("@TSDataBuilders/TemplateCompiler",{effect:ee.gen(function*(){return{compile:ee.fnUntraced(function*(t,a){return yield*ee.try({try:()=>Ti.compile(t)(a),catch:i=>new Fr({cause:i})})})}})}){},Fr=class extends qr.TaggedError("TemplateCompileError"){};var de=class extends pe.Service()("@TSDataBuilders/BaseBuilderGenerator",{effect:pe.gen(function*(){let t=yield*Hr.Path,a=yield*x,i=yield*N,c=yield*Yr.FileSystem,n=yield*X,e=yield*_e(i.fileCase);return{generate:pe.gen(function*(){let f=t.join(yield*a.cwd,i.outputDir),s=t.resolve(f,`${yield*e("dataBuilder")}.ts`),p=yield*c.readFileString(t.join(import.meta.dirname,"templates/base-builder.hbs"),"utf-8");yield*pe.logDebug(`[Builders]: Creating base builder at ${s}`),yield*c.writeFileString(s,yield*n.compile(p))})}}),dependencies:[X.Default]}){};import*as ie from"effect/Effect";import{Chunk as ir}from"effect";import*as Ot from"@effect/platform/FileSystem";import*as wt from"@effect/platform/Path";import*as C from"effect/Effect";import*as De from"effect/Ref";import*as Lr from"effect/Schema";import*as te from"effect/Effect";import*as Ce from"effect/Effect";import*as d from"effect/Effect";import*as S from"effect/Match";import*as bt from"effect/Option";import{createPrinter as Xr,createProgram as et,createSourceFile as rt,EmitHint as tt,findConfigFile as it,getJSDocTags as ot,isArrayTypeNode as nt,isIndexedAccessTypeNode as at,isIndexSignatureDeclaration as st,isInterfaceDeclaration as ct,isIntersectionTypeNode as Qe,isMappedTypeNode as ft,isNamedTupleMember as kr,isOptionalTypeNode as lt,isParenthesizedTypeNode as pt,isPropertySignature as dt,isTemplateLiteralTypeNode as ut,isTupleTypeNode as mt,isTypeAliasDeclaration as yt,isTypeLiteralNode as qe,isTypeOperatorNode as gt,isTypeQueryNode as Tt,isTypeReferenceNode as ze,isUnionTypeNode as St,NodeBuilderFlags as re,parseJsonConfigFileContent as Et,readConfigFile as ht,ScriptTarget as Ct,SymbolFlags as Ye,SyntaxKind as E,sys as He}from"typescript";import{SyntaxKind as Si}from"typescript";var Zr=r=>r.kind===Si.LiteralType,Ei=["Date","Promise","Map","Set","WeakMap","WeakSet","RegExp","Error","BigInt","Array"],We=r=>Ei.includes(r);var Ze=r=>{let t=Object.entries(r);return t.length===0?"{}":`{${t.map(([i,c])=>`'${i.replace(/^['"](.*)['"]$/,"$1")}':${c}`).join(",")}}`};import*as tr from"effect/Data";var Xe=class extends tr.TaggedError("CannotGeneratorDefaultValueForNeverError"){},er=class extends tr.TaggedError("UnionMembersIsEmptyError"){},rr=class extends tr.TaggedError("MissingBuiltinTypeDefaultError"){};import*as Dt from"effect/Context";var ue=class extends Dt.Tag("@TSDataBuilders/TypeReferenceSideEffect")(){};var Ci={Date:"new Date()",Promise:"new Promise(() => {})",Map:"new Map()",Set:"new Set()",WeakMap:"new WeakMap()",WeakSet:"new WeakSet()",RegExp:'new RegExp("")',Error:"new Error()",BigInt:"BigInt(0)",Array:"[]"},Ie=class extends d.Service()("@TSDataBuilders/TypeNodeDefaultValueGenerator",{effect:d.gen(function*(){let{defaults:t,builderJsDocTagName:a}=yield*N,i=d.fnUntraced(function*(c,n){return yield*S.value(c).pipe(S.when({kind:"StringKeyword"},()=>d.succeed(`'${t.string}'`)),S.when({kind:"NumberKeyword"},()=>d.succeed(t.number.toString(10))),S.when({kind:"BooleanKeyword"},()=>d.succeed(String(t.boolean))),S.when({kind:"UndefinedKeyword"},()=>d.succeed("undefined")),S.when({kind:"LiteralType"},({literal:e})=>d.succeed(e)),S.when({kind:"BigIntKeyword"},()=>d.succeed("0n")),S.when({kind:"SymbolKeyword"},()=>d.succeed("Symbol('')")),S.when({kind:"AnyKeyword"},()=>d.succeed(String(Di))),S.when({kind:"UnknownKeyword"},()=>d.succeed(String(Pi))),S.when({kind:"NeverKeyword"},()=>new Xe),S.when({kind:"TypeLiteral"},({propertySignatures:e})=>d.gen(function*(){let f=yield*d.all(e.map(p=>n.onPropertySignature(p)),{concurrency:"unbounded"}),s=Object.assign({},...f);return Ze(s)})),S.when({kind:"ArrayType"},()=>d.succeed("[]")),S.when({kind:"TupleType"},({elements:e})=>d.all(e.map(f=>i(f,n)),{concurrency:"unbounded"}).pipe(d.map(f=>`[${f.join(", ")}]`))),S.when({kind:"UnionType"},({members:e})=>xt(e).pipe(d.flatMap(f=>i(f,n)))),S.when({kind:"IntersectionType"},({members:e})=>d.gen(function*(){return e.some(u=>u.kind!=="TypeLiteral"&&u.kind!=="TypeReference")?`${yield*xt(e).pipe(d.flatMap(h=>i(h,n)))} as any`:`{${(yield*d.all(e.map(u=>i(u,n)),{concurrency:"unbounded"})).map(u=>u.replace(/^\{|\}$/g,"").trim()).filter(u=>u.length>0).join(", ")}}`})),S.when({kind:"TypeReference"},e=>d.gen(function*(){let{onTypeReference:f}=yield*ue;return yield*f(e),e.jsDocTags.some(s=>s.name===a)?`new ${e.referenceName}Builder().build()`:yield*bt.match(e.inlineType,{onNone:()=>We(e.referenceName)?d.succeed(Ci[e.referenceName]):d.fail(new rr({referenceName:e.referenceName})),onSome:s=>i(s,n)})})),S.exhaustive)});return{generate:i}})}){},Nt={LiteralType:0,UndefinedKeyword:1,BooleanKeyword:2,NumberKeyword:3,StringKeyword:4,SymbolKeyword:5,BigIntKeyword:6,TypeLiteral:7,ArrayType:8,TupleType:9,UnionType:10,IntersectionType:11,UnknownKeyword:12,AnyKeyword:13,TypeReference:14,NeverKeyword:15},Di=void 0,Pi=void 0,xt=d.fnUntraced(function*(r){let t=r.toSorted((a,i)=>Nt[a.kind]-Nt[i.kind])[0];return t||(yield*new er({memberKinds:r.map(a=>a.kind)}))});var Be=class extends Ce.Service()("@TSDataBuilders/PropertySignatureDefaultValueGenerator",{effect:Ce.gen(function*(){let t=yield*Ie,{inlineDefaultJsDocTagName:a}=yield*N,i=Ce.fnUntraced(function*(c){if(c.hasQuestionToken)return{};let n=c.jsDocTags.find(e=>e.name===a)?.comment??(yield*t.generate(c.typeNode,{onPropertySignature:i}));return{[c.name]:n}});return{generate:i}}),dependencies:[Ie.Default]}){};var Ue=class extends te.Service()("@TSDataBuilders/DeclarationDefaultValueGenerator",{effect:te.gen(function*(){let t=yield*Be;return{generate:te.fnUntraced(function*(a){let i=yield*te.all(a.propertySignatures.map(n=>t.generate(n))),c=Object.assign({},...i);return Ze(c)})}}),dependencies:[Be.Default]}){};var Ae=class extends C.Service()("@TSDataBuilders/DeclarationBuilderGenerator",{effect:C.gen(function*(){let t=yield*Ue,a=yield*x,i=yield*wt.Path,c=yield*Ot.FileSystem,n=yield*X,e=yield*N,f=yield*_e(e.fileCase);return{generate:C.fnUntraced(function*(s){let{declaration:p,fileAbsolutePath:u}=s,h=yield*De.make(ir.empty()),M=yield*t.generate(p).pipe(C.provideService(ue,ue.of({onTypeReference:J=>C.if(J.jsDocTags.some(ke=>ke.name===e.builderJsDocTagName),{onTrue:()=>De.update(h,ir.append(J.referenceName)),onFalse:()=>C.void})}))),Oe=yield*De.get(h).pipe(C.map(ir.dedupe)),W=yield*C.all(Oe.pipe(ir.map(J=>f(J).pipe(C.map(ke=>({referenceName:J,path:`${ke}${e.fileSuffix}`}))))),{concurrency:"unbounded"}),he=p.name,Rr=i.join(yield*a.cwd,e.outputDir),we=i.resolve(Rr,`${yield*f(he)}${e.fileSuffix}.ts`),Cr=i.resolve(u),Fe=i.relative(i.dirname(we),Cr).replace(/\.ts$/,""),Dr=yield*C.all(p.propertySignatures.map(C.fnUntraced(function*(J){let ke=J.typeNode.kind==="TypeReference"&&J.typeNode.jsDocTags.some(ci=>ci.name===e.builderJsDocTagName),vr=yield*Wr.pipe(Lr.decode)(J.name);return{name:{original:vr,pascal:yield*wr.pipe(Lr.decode)(vr)},hasQuestionToken:J.hasQuestionToken,isBuilder:ke}})),{concurrency:"unbounded"}),Pr=yield*c.readFileString(i.join(import.meta.dirname,"templates/builder.hbs"),"utf-8"),si=yield*n.compile(Pr,{baseDataBuilderFileName:yield*f("dataBuilder"),builderSuffix:e.builderSuffix,typeName:he,originalFileImportPath:Fe,defaultValues:M,properties:Dr,subBuilders:W});yield*c.writeFileString(we,si)})}}),dependencies:[Ue.Default,X.Default]}){};var me=class extends ie.Service()("@TSDataBuilders/FileBuilderGenerator",{effect:ie.gen(function*(){let t=yield*Ae;return{generate:ie.fnUntraced(function*(a){yield*ie.all(a.declarations.map(i=>t.generate({fileAbsolutePath:a.fileAbsolutePath,declaration:i})),{concurrency:"unbounded"})})}}),dependencies:[Ae.Default]}){};import*as Pe from"effect/Chunk";import*as D from"effect/Effect";import*as or from"effect/Option";import*as nr from"effect/Stream";import*as kt from"@effect/platform/FileSystem";import*as Lt from"effect/Chunk";import*as k from"effect/Effect";import*as L from"effect/Stream";var Ge=class extends k.Service()("@TSDataBuilders/FileContentChecker",{effect:k.gen(function*(){yield*k.logDebug("[FileContentChecker]: Instantiating");let t=yield*kt.FileSystem,a=new TextDecoder;return{check:k.fnUntraced(function*(i){let{content:c,filePath:n}=i;return yield*k.logDebug(`[FileContentChecker]: Checking file content of ${n}`),yield*L.orDie(t.stream(n,{chunkSize:16*1024})).pipe(L.map(s=>a.decode(s,{stream:!0})),L.mapAccum("",(s,p)=>{let u=s+p;return[u.slice(-c.length+1),u.includes(c)]}),L.find(s=>!!s),L.tap(()=>k.logDebug(`[FileContentChecker]: Found expected content in ${n}`)),L.runCollect,k.map(s=>s.pipe(Lt.get(0))))})}})}){};import*as Ut from"effect/Data";import*as Q from"effect/Effect";import*as At from"effect/Stream";import*as It from"glob";import*as Bt from"effect/Data";import*as A from"effect/Effect";var Re=class extends A.Service()("@TSDataBuilders/Glob",{effect:A.gen(function*(){return yield*A.logDebug("[Glob]: Instantiating"),{iterate:A.fnUntraced(function*(t){return yield*A.logDebug(`[Glob]: Iterating ${t.path} in ${t.cwd}`),yield*A.try({try:()=>It.glob.iterate(t.path,{cwd:t.cwd,nodir:!0}),catch:a=>new Ir({cause:a})})})}})}){},Ir=class extends Bt.TaggedError("GlobIterationError"){};var ve=class extends Q.Service()("@TSDataBuilders/FileTreeWalker",{effect:Q.gen(function*(){yield*Q.logDebug("[FileTreeWalker]: Instantiating");let t=yield*Re,a=yield*x;return{walk:Q.fnUntraced(function*(i){let c=yield*a.cwd;return yield*Q.logDebug(`[FileTreeWalker]: Walking path: ${c}/${i}`),At.fromAsyncIterable(yield*t.iterate({path:i,cwd:c}),n=>new Br({cause:n}))})}}),dependencies:[Re.Default]}){},Br=class extends Ut.TaggedError("FileTreeWalkError"){};var ye=class extends D.Service()("@TSDataBuilders/Finder",{effect:D.gen(function*(){yield*D.logDebug("[Finder]: Instantiating");let t=yield*Ge,a=yield*ve;return{find:D.fnUntraced(function*(i){yield*D.logDebug(`[Finder]: Searching file paths in ${i.include}`);let c=yield*a.walk(i.include);yield*D.logDebug(`[Finder]: Checking which files include at least 1 occurance of ${i.pattern}`);let n=yield*c.pipe(nr.mapEffect(e=>t.check({filePath:e,content:i.pattern}).pipe(D.map(f=>f.pipe(or.map(()=>e)))),{concurrency:"unbounded"}),nr.runCollect,D.map(Pe.filter(e=>or.isSome(e))),D.map(Pe.map(e=>e.value)));return yield*D.logDebug(`[Finder]: Found files with expected pattern: ${n.pipe(Pe.toArray).join(", ")}`),n},D.catchTag("FileTreeWalkError",i=>D.die(i)))}}),dependencies:[ve.Default,Ge.Default]}){};import*as Rt from"effect/Context";var q=class extends Rt.Tag("@TSDataBuilders/ParseDeclarationPredicate")(){};import*as Wt from"effect/Chunk";import*as _ from"effect/Effect";import*as Mt from"@effect/platform/Path";import*as G from"effect/Effect";import*as Kt from"@effect/platform/Path";import*as z from"effect/Effect";import*as oe from"effect/Data";var ar=class extends oe.TaggedError("TSConfigNotFoundError"){},Ne=class extends oe.TaggedError("GetTSConfigError"){},sr=class extends oe.TaggedError("CreateProgramError"){},cr=class extends oe.TaggedError("GetTypeCheckerError"){},fr=class extends oe.TaggedError("GetSourceFileError"){},lr=class extends oe.TaggedError("CreateSourceFileError"){},pr=class extends oe.TaggedError("SourceFileNotFoundError"){};var je=class extends z.Service()("@TSDataBuilders/TSConfigResolver",{effect:z.gen(function*(){let t=yield*Kt.Path,i=yield*(yield*x).cwd,{tsconfig:c}=yield*N;return{resolve:z.gen(function*(){let n=yield*z.try({try:()=>it(i,He.fileExists,c),catch:f=>new Ne({cause:f})});if(!n)return yield*new ar;let e=yield*z.try({try:()=>{let{config:f,error:s}=ht(n,He.readFile);if(s)throw s;return f},catch:f=>new Ne({cause:f})});return yield*z.try({try:()=>Et(e,He,t.dirname(n)),catch:f=>new Ne({cause:f})})})}})}){};var I=class extends G.Service()("@TSDataBuilders/TypescriptProgram",{effect:G.gen(function*(){let t=yield*Mt.Path,i=yield*(yield*je).resolve,c=yield*G.try({try:()=>et(i.fileNames,i.options),catch:s=>new sr({cause:s})}),n=yield*G.try({try:()=>c.getTypeChecker(),catch:s=>new cr({cause:s})}),e=G.fnUntraced(function*(s){let p=t.resolve(s),u=yield*G.try({try:()=>c.getSourceFile(p),catch:h=>new fr({cause:h})});return u||(yield*new pr)});return{program:c,typeChecker:n,getSourceFile:e,createSourceFile:s=>G.try({try:()=>rt(s.fileName,s.sourceText,i.options.target??Ct.Latest),catch:p=>new lr({cause:p})})}}),dependencies:[je.Default]}){};import*as _t from"@effect/platform/Path";import*as K from"effect/Effect";import*as R from"effect/Data";var xe=class extends R.TaggedError("GetNodeChildrenError"){},dr=class extends R.TaggedError("SyntaxListNodeNotFoundError"){},ur=class extends R.TaggedError("UnsupportedTypeAliasDeclarationTypeNodeError"){},mr=class extends R.TaggedError("GetJsDocTagsNamesError"){},yr=class extends R.TaggedError("UnsupportedTypeLiteralNodeMemberError"){},gr=class extends R.TaggedError("MissingPropertySignatureTypeNodeError"){},ne=class extends R.TaggedError("GetTypeNodeNameTextError"){},ge=class extends R.TaggedError("CannotGetNodeTextError"){},Tr=class extends R.TaggedError("UnsupportedTypeNodeError"){},Te=class extends R.TaggedError("CannotCreateSyntheticTypeNodeError"){};import*as j from"effect/Effect";import*as hr from"effect/Option";import*as ce from"effect/Effect";import*as Er from"effect/Option";import*as Jt from"effect/Effect";var v=r=>Jt.try({try:()=>ot(r).map(t=>({name:t.tagName.getText(),comment:typeof t.comment=="string"?t.comment:void 0})),catch:t=>new mr({cause:t})});import*as V from"effect/Effect";import*as g from"effect/Effect";import*as Ke from"effect/Option";var ae=class extends g.Service()("@TSDataBuilders/TypeNodeParser",{effect:g.gen(function*(){yield*g.logDebug("[TypeNodeParser]: Instantiating");let t=yield*I,a=Xr(),i=yield*t.createSourceFile({fileName:"temp.ts",sourceText:""}),c=g.fnUntraced(function*(e){let f=t.typeChecker.typeToTypeNode(e.type,e.typeNode,re.InTypeAlias|re.NoTruncation);return f?yield*n(f,{onTypeLiteral:e.onTypeLiteral}):yield*new Te}),n=g.fnUntraced(function*(e,f){if(e.kind===E.StringKeyword)return{kind:"StringKeyword"};if(e.kind===E.NumberKeyword)return{kind:"NumberKeyword"};if(e.kind===E.BooleanKeyword)return{kind:"BooleanKeyword"};if(e.kind===E.UndefinedKeyword)return{kind:"UndefinedKeyword"};if(e.kind===E.BigIntKeyword)return{kind:"BigIntKeyword"};if(e.kind===E.SymbolKeyword)return{kind:"SymbolKeyword"};if(e.kind===E.AnyKeyword)return{kind:"AnyKeyword"};if(e.kind===E.UnknownKeyword)return{kind:"UnknownKeyword"};if(e.kind===E.NeverKeyword)return{kind:"NeverKeyword"};if(e.kind===E.ObjectKeyword)return{kind:"TypeLiteral",propertySignatures:[]};if(Zr(e)){let s=e.pos===-1||e.getSourceFile()===void 0;return{kind:"LiteralType",literal:yield*g.try({try:()=>s?a.printNode(tt.Unspecified,e,i):e.getText(),catch:p=>new ge({cause:p})})}}if(qe(e))return{kind:"TypeLiteral",propertySignatures:yield*f.onTypeLiteral(e)};if(nt(e))return{kind:"ArrayType"};if(mt(e))return{kind:"TupleType",elements:yield*g.all(e.elements.filter(p=>!(kr(p)&&p.dotDotDotToken)).map(p=>n(p,f)),{concurrency:"unbounded"})};if(kr(e))return yield*n(e.type,f);if(St(e))return{kind:"UnionType",members:yield*g.all(e.types.map(s=>n(s,f)),{concurrency:"unbounded"})};if(ze(e)){let s=yield*g.try({try:()=>"escapedText"in e.typeName?e.typeName.escapedText.toString():e.typeName.getText(),catch:W=>new ge({cause:W})});if(We(s))return{kind:"TypeReference",referenceName:s,inlineType:Ke.none(),jsDocTags:[]};if(["Awaited","Exclude","Extract","ReturnType","Parameters","ConstructorParameters","InstanceType"].includes(s)){let W=t.typeChecker.getTypeAtLocation(e);return yield*c({type:W,typeNode:e,onTypeLiteral:f.onTypeLiteral})}let u=t.typeChecker.getTypeAtLocation(e),h=u.getProperties();if(h.length>0&&!u.isUnion()){let he={kind:"TypeLiteral",propertySignatures:yield*g.all(h.map(g.fn(function*(Fe){let Dr=t.typeChecker.getTypeOfSymbol(Fe),Pr=yield*c({type:Dr,typeNode:e,onTypeLiteral:f.onTypeLiteral});return{name:Fe.getName(),typeNode:Pr,hasQuestionToken:!!(Fe.flags&Ye.Optional),jsDocTags:[]}})),{concurrency:"unbounded"})},we=(u.aliasSymbol??u.getSymbol())?.declarations?.[0],Cr=we?yield*v(we):[];return{kind:"TypeReference",referenceName:s,inlineType:Ke.some(he),jsDocTags:Cr}}let M=t.typeChecker.typeToTypeNode(u,e,re.InTypeAlias|re.NoTruncation);if(!M)return yield*new Te;let Oe=yield*n(M,f);return{kind:"TypeReference",referenceName:s,inlineType:Ke.some(Oe),jsDocTags:[]}}if(gt(e)){if(e.operator===E.KeyOfKeyword){let s=t.typeChecker.getTypeAtLocation(e);return yield*c({type:s,typeNode:e,onTypeLiteral:f.onTypeLiteral})}if(e.operator===E.ReadonlyKeyword)return yield*n(e.type,f)}if(Tt(e)){let s=t.typeChecker.getTypeAtLocation(e);return yield*c({type:s,typeNode:e,onTypeLiteral:f.onTypeLiteral})}if(at(e)){let s=t.typeChecker.getTypeAtLocation(e);return yield*c({type:s,typeNode:e,onTypeLiteral:f.onTypeLiteral})}if(ft(e)){let s=t.typeChecker.getTypeAtLocation(e);return yield*c({type:s,typeNode:e,onTypeLiteral:f.onTypeLiteral})}if(Qe(e))return{kind:"IntersectionType",members:yield*g.all(e.types.map(s=>n(s,f)),{concurrency:"unbounded"})};if(ut(e)){let s=yield*g.try({try:()=>e.head.text,catch:h=>new ge({cause:h})}),p=yield*g.all(e.templateSpans.map(h=>g.try({try:()=>h.literal.text,catch:M=>new ge({cause:M})})),{concurrency:"unbounded"});return{kind:"LiteralType",literal:`'${s+p.join("")}'`}}return lt(e)?yield*n(e.type,f):pt(e)?yield*n(e.type,f):yield*new Tr({kind:E[e.kind]})});return{parse:n}}),dependencies:[I.Default]}){};var se=class extends V.Service()("@TSDataBuilders/TypeLiteralParser",{effect:V.gen(function*(){let t=yield*ae,a=(c,n)=>V.all(c.filter(e=>!st(e)).map(V.fn(function*(e){if(!dt(e))return yield*new yr;if(!e.type)return yield*new gr;let f=yield*t.parse(e.type,{onTypeLiteral:n.onTypeLiteral});return{name:yield*V.try({try:()=>"escapedText"in e.name?e.name.escapedText.toString():e.name.getText(),catch:p=>new ne({cause:p})}),typeNode:f,hasQuestionToken:!!e.questionToken,jsDocTags:yield*v(e)}})),{concurrency:"unbounded"}),i=c=>a(c.members,{onTypeLiteral:i});return{parseMembers:a,parse:i}}),dependencies:[ae.Default]}){};var Me=class extends ce.Service()("@TSDataBuilders/InterfaceDeclarationParser",{effect:ce.gen(function*(){let t=yield*q,a=yield*se;return{parse:ce.fnUntraced(function*(i){let c=i.modifiers?.some(f=>f.kind===E.ExportKeyword)??!1,n=yield*v(i);if(!(yield*t({isExported:c,jsDocTags:n})))return Er.none();let e=yield*ce.try({try:()=>i.name.getText(),catch:f=>new ne({cause:f})});return Er.some({name:e,propertySignatures:yield*a.parseMembers(i.members,{onTypeLiteral:a.parse}),jsDocTags:yield*v(i)})})}}),dependencies:[se.Default]}){};import{Option as Ar}from"effect";import*as B from"effect/Effect";var Je=class extends B.Service()("@TSDataBuilders/TypeAliasDeclarationParser",{effect:B.gen(function*(){let t=yield*se,a=yield*ae,i=yield*I,c=yield*q;return{parse:B.fnUntraced(function*(n){let e=n.modifiers?.some(p=>p.kind===E.ExportKeyword)??!1,f=yield*v(n);if(!(yield*c({isExported:e,jsDocTags:f})))return Ar.none();let s=yield*B.try({try:()=>n.name.getText(),catch:p=>new ne({cause:p})});if(qe(n.type))return Ar.some({name:s,propertySignatures:yield*t.parse(n.type),jsDocTags:yield*v(n)});if(Qe(n.type)||ze(n.type)){let u=i.typeChecker.getTypeAtLocation(n.type).getProperties(),h=yield*B.all(u.map(B.fn(function*(M){let Oe=i.typeChecker.getTypeOfSymbol(M),W=i.typeChecker.typeToTypeNode(Oe,n.type,re.InTypeAlias|re.NoTruncation);if(!W)return yield*new Te;let he=yield*a.parse(W,{onTypeLiteral:t.parse});return{name:M.getName(),typeNode:he,hasQuestionToken:!!(M.flags&Ye.Optional),jsDocTags:[]}})),{concurrency:"unbounded"});return Ar.some({name:s,propertySignatures:h,jsDocTags:yield*v(n)})}return yield*new ur})}}),dependencies:[se.Default,ae.Default,I.Default]}){};var $e=class extends j.Service()("@TSDataBuilders/SyntaxListParser",{effect:j.gen(function*(){let t=yield*Je,a=yield*Me;return{parse:j.fnUntraced(function*(i){let c=yield*j.try({try:()=>i.getChildren(),catch:e=>new xe({cause:e})});return(yield*j.all(c.map(j.fnUntraced(function*(e){return yt(e)?yield*t.parse(e):ct(e)?yield*a.parse(e):hr.none()})),{concurrency:"unbounded"})).filter(e=>hr.isSome(e)).map(e=>e.value)})}}),dependencies:[Me.Default,Je.Default]}){};var Ve=class extends K.Service()("@TSDataBuilders/SourceFileParser",{effect:K.gen(function*(){let t=yield*$e,a=yield*_t.Path;return{parse:i=>K.gen(function*(){let n=(yield*K.try({try:()=>i.getChildren(),catch:e=>new xe({cause:e})})).find(e=>e.kind===E.SyntaxList);return n?{fileAbsolutePath:i.fileName,declarations:yield*t.parse(n)}:yield*new dr}).pipe(K.catchTags({UnsupportedTypeNodeError:c=>K.dieMessage(`Unsupported type node of kind ${c.kind} found in file ${a.relative(process.cwd(),i.fileName)}`)}))}}),dependencies:[$e.Default]}){};var Ee=class extends _.Service()("@TSDataBuilders/ProjectParser",{effect:_.gen(function*(){let t=yield*I,a=yield*Ve;return{parseFiles:_.fnUntraced(function*(i){return yield*_.all(i.pipe(Wt.map(n=>t.getSourceFile(n).pipe(_.flatMap(e=>a.parse(e))))),{concurrency:"unbounded"})})}}),dependencies:[I.Default,Ve.Default]}){};import*as qt from"@effect/platform/FileSystem";import*as zt from"@effect/platform/Path";import*as Yt from"effect/Effect";import*as O from"effect/Option";import*as be from"effect/Schema";var Ht=Yt.fnUntraced(function*(r){let t=yield*x,a=yield*qt.FileSystem,i=yield*t.cwd,n=(yield*zt.Path).join(i,br),e=Le({string:r.defaultString.pipe(O.getOrUndefined),number:r.defaultNumber.pipe(O.getOrUndefined),boolean:r.defaultBoolean.pipe(O.getOrUndefined)}),f=yield*be.decode(Or)({$schema:"https://raw.githubusercontent.com/nemmtor/ts-databuilders/refs/heads/main/schema.json",builderSuffix:r.builderSuffix.pipe(O.getOrElse(()=>w.builderSuffix)),fileSuffix:r.fileSuffix.pipe(O.getOrElse(()=>w.fileSuffix)),fileCase:r.fileCase.pipe(O.getOrElse(()=>w.fileCase)),include:r.include.pipe(O.getOrElse(()=>w.include)),builderJsDocTagName:r.builderJsDocTagName.pipe(O.getOrElse(()=>w.builderJsDocTagName)),inlineDefaultJsDocTagName:r.inlineDefaultJsDocTagName.pipe(O.getOrElse(()=>w.inlineDefaultJsDocTagName)),withNestedBuilders:r.withNestedBuilders.pipe(O.getOrElse(()=>w.withNestedBuilders)),outputDir:r.outputDir.pipe(O.getOrElse(()=>w.outputDir)),tsconfig:r.tsconfig.pipe(O.getOrElse(()=>w.tsconfig)),defaults:{...w.defaults,...e}});yield*a.writeFileString(n,`${yield*be.encode(be.parseJson({replacer:null,space:2}))(f)}
3
+ `)});import*as Zt from"@effect/platform/FileSystem";import*as b from"effect/Effect";import*as Xt from"effect/Layer";var ei=b.gen(function*(){let r=yield*Zt.FileSystem,t=yield*ye,a=yield*Ee,i=yield*me,c=yield*de,{include:n,builderJsDocTagName:e,outputDir:f}=yield*N;yield*b.logInfo(`Scanning '${n}' for files including types annotated with '@${e}'.`);let s=yield*t.find({include:n,pattern:`@${e}`});if(s.length===0){yield*b.logInfo("Nothing to generate.");return}yield*b.logInfo(`Found ${s.length} file(s), parsing it to understand data shape.`);let p=yield*a.parseFiles(s);yield*b.logInfo("Generating builders."),yield*r.makeDirectory(f,{recursive:!0}),yield*c.generate,yield*b.all(p.flatMap(h=>i.generate(h)),{concurrency:"unbounded"});let u=p.flatMap(h=>h.declarations).length;yield*b.logInfo(`Created ${u} builder(s).`)}),ri=Xt.effect(q,b.gen(function*(){let r=yield*N;return t=>t.isExported?t.jsDocTags.some(a=>a.name===r.builderJsDocTagName)?b.succeed(!0):b.succeed(!1):b.succeed(!1)}));var ti="0.0.1-alpha.23";var ji=l.text("tsconfig").pipe(l.withAlias("t"),l.withDescription(m.tsconfig),l.withSchema(F.fields.tsconfig),l.optional),Ki=l.text("builder-jsdoc-tag-name").pipe(l.withDescription(m.builderJsDocTagName),l.withSchema(F.fields.builderJsDocTagName),l.optional),Mi=l.text("inline-default-jsdoc-tag-name").pipe(l.withDescription(m.inlineDefaultJsDocTagName),l.withSchema(F.fields.inlineDefaultJsDocTagName),l.optional),Ji=l.text("with-nested-builders").pipe(l.withDescription(m.withNestedbuilders),l.withSchema(F.fields.withNestedBuilders),l.optional),$i=l.text("output-dir").pipe(l.withAlias("o"),l.withDescription(m.outputDir),l.withSchema(F.fields.outputDir),l.optional),Vi=l.text("include").pipe(l.withAlias("i"),l.withDescription(m.include),l.withSchema(F.fields.include),l.optional),_i=l.text("file-case").pipe(l.withDescription(m.fileCase),l.withSchema(F.fields.fileCase),l.optional),Wi=l.text("file-suffix").pipe(l.withDescription(m.fileSuffix),l.withSchema(F.fields.fileSuffix),l.optional),Qi=l.text("builder-suffix").pipe(l.withDescription(m.builderSuffix),l.withSchema(F.fields.builderSuffix),l.optional),qi=l.text("default-string").pipe(l.withDescription(m.defaultString),l.withSchema(F.fields.defaultString),l.optional),zi=l.text("default-number").pipe(l.withDescription(m.defaultNumber),l.withSchema(F.fields.defaultNumber),l.optional),Yi=l.text("default-boolean").pipe(l.withDescription(m.defaultBoolean),l.withSchema(F.fields.defaultBoolean),l.optional),ii={tsconfig:ji,builderJsDocTagName:Ki,outputDir:$i,withNestedBuilders:Ji,include:Vi,fileSuffix:Wi,fileCase:_i,builderSuffix:Qi,defaultString:qi,defaultNumber:zi,defaultBoolean:Yi,inlineDefaultJsDocTagName:Mi},Hi=U.make("init",ii).pipe(U.withHandler(Ht)),Zi=U.make("ts-databuilders",ii),Gr=Zi.pipe(U.withHandler(()=>ei),U.withSubcommands([Hi]),U.provide(r=>fe.mergeAll(ye.Default,Ee.Default,me.Default,de.Default).pipe(fe.provideMerge(ri),fe.provideMerge(fe.effect(N,Vr(r))),fe.provideMerge(x.Default))),U.run({name:"Typescript Databuilders generator",version:ti}));Gr(process.argv).pipe(ai.provide(oi.layer),ni.runMain);
@@ -0,0 +1,17 @@
1
+ export abstract class DataBuilder<T> {
2
+ private data: T;
3
+
4
+ constructor(initialData: T) {
5
+ this.data = initialData;
6
+ }
7
+
8
+ public build(): Readonly<T> {
9
+ return structuredClone(this.data);
10
+ }
11
+
12
+ protected with(partial: Partial<T>): this {
13
+ this.data = { ...this.data, ...partial };
14
+ return this;
15
+ }
16
+ }
17
+
@@ -0,0 +1,34 @@
1
+ import { DataBuilder } from './{{baseDataBuilderFileName}}';
2
+ import type { {{typeName}} } from '{{originalFileImportPath}}';
3
+
4
+ {{#each subBuilders}}
5
+ import { {{referenceName}}{{../builderSuffix}} } from './{{path}}';
6
+ {{/each}}
7
+
8
+ export class {{typeName}}{{builderSuffix}} extends DataBuilder<{{typeName}}> {
9
+ constructor() {
10
+ super({{{defaultValues}}});
11
+ }
12
+ {{#each properties}}
13
+
14
+ {{#if isBuilder}}
15
+ with{{{name.pascal}}}(builder: DataBuilder<{{../typeName}}['{{{name.original}}}']>) {
16
+ {{#if hasQuestionToken}}
17
+ const value = builder?.build();
18
+ {{else}}
19
+ const value = builder.build();
20
+ {{/if}}
21
+ {{else}}
22
+ with{{{name.pascal}}}(value: {{../typeName}}['{{{name.original}}}']) {
23
+ {{/if}}
24
+ {{#if hasQuestionToken}}
25
+ if (value === undefined) {
26
+ const { "{{{name.original}}}": _unused, ...rest } = this.build();
27
+ return this.with(rest);
28
+ }
29
+
30
+ {{/if}}
31
+ return this.with({ '{{{name.original}}}': value });
32
+ }
33
+ {{/each}}
34
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@nemmtor/ts-databuilders",
4
- "version": "0.0.1-alpha.21",
4
+ "version": "0.0.1-alpha.23",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "description": "CLI tool that automatically generates builder classes from annotated TypeScript types.",
@@ -33,11 +33,13 @@
33
33
  "@commitlint/cli": "^20.1.0",
34
34
  "@commitlint/config-conventional": "^20.0.0",
35
35
  "@commitlint/prompt-cli": "^20.1.0",
36
- "@effect/language-service": "^0.62.0",
36
+ "@effect/language-service": "^0.72.0",
37
37
  "@effect/vitest": "^0.27.0",
38
+ "@stryker-mutator/core": "^9.3.0",
39
+ "@stryker-mutator/vitest-runner": "^9.3.0",
38
40
  "@total-typescript/ts-reset": "^0.6.1",
39
41
  "@types/node": "^24.0.0",
40
- "@vitest/coverage-v8": "4.0.16",
42
+ "@vitest/coverage-v8": "4.0.18",
41
43
  "dependency-cruiser": "^17.2.0",
42
44
  "knip": "^5.66.4",
43
45
  "lefthook": "^2.0.2",
@@ -45,16 +47,14 @@
45
47
  "tsx": "^4.20.6",
46
48
  "vitest": "^4.0.6"
47
49
  },
48
- "peerDependencies": {
49
- "typescript": "^5.9.3"
50
- },
51
50
  "dependencies": {
52
51
  "@effect/cli": "^0.73.0",
53
52
  "@effect/platform": "^0.94.0",
54
53
  "@effect/platform-node": "^0.104.0",
55
54
  "effect": "^3.18.4",
56
55
  "glob": "^13.0.0",
57
- "ts-morph": "^27.0.2"
56
+ "handlebars": "^4.7.8",
57
+ "typescript": "^5.9.3"
58
58
  },
59
59
  "engines": {
60
60
  "node": ">=20.0.0"