@devup-api/generator 0.1.0

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.
Files changed (35) hide show
  1. package/README.md +26 -0
  2. package/dist/__tests__/convert-case.test.d.ts +2 -0
  3. package/dist/__tests__/convert-case.test.d.ts.map +1 -0
  4. package/dist/__tests__/create-url-map.test.d.ts +2 -0
  5. package/dist/__tests__/create-url-map.test.d.ts.map +1 -0
  6. package/dist/__tests__/index.test.d.ts +2 -0
  7. package/dist/__tests__/index.test.d.ts.map +1 -0
  8. package/dist/__tests__/wrap-interface-key-guard.test.d.ts +2 -0
  9. package/dist/__tests__/wrap-interface-key-guard.test.d.ts.map +1 -0
  10. package/dist/convert-case.d.ts +5 -0
  11. package/dist/convert-case.d.ts.map +1 -0
  12. package/dist/create-url-map.d.ts +4 -0
  13. package/dist/create-url-map.d.ts.map +1 -0
  14. package/dist/generate-interface.d.ts +15 -0
  15. package/dist/generate-interface.d.ts.map +1 -0
  16. package/dist/generate-schema.d.ts +44 -0
  17. package/dist/generate-schema.d.ts.map +1 -0
  18. package/dist/index.cjs +36 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +36 -0
  22. package/dist/wrap-interface-key-guard.d.ts +2 -0
  23. package/dist/wrap-interface-key-guard.d.ts.map +1 -0
  24. package/package.json +27 -0
  25. package/src/__tests__/convert-case.test.ts +125 -0
  26. package/src/__tests__/create-url-map.test.ts +318 -0
  27. package/src/__tests__/index.test.ts +9 -0
  28. package/src/__tests__/wrap-interface-key-guard.test.ts +42 -0
  29. package/src/convert-case.ts +22 -0
  30. package/src/create-url-map.ts +43 -0
  31. package/src/generate-interface.ts +594 -0
  32. package/src/generate-schema.ts +482 -0
  33. package/src/index.ts +2 -0
  34. package/src/wrap-interface-key-guard.ts +6 -0
  35. package/tsconfig.json +34 -0
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @devup-api/generator
2
+
3
+ devup API Type Generator
4
+
5
+ Type generation package that generates TypeScript types from schemas.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @devup-api/generator
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { generateTypes, generateTypeFromSchema } from '@devup-api/generator';
17
+
18
+ // Generate types
19
+ await generateTypes({
20
+ outputPath: './types',
21
+ format: 'typescript',
22
+ });
23
+
24
+ // Generate type from schema
25
+ const typeString = generateTypeFromSchema(schema);
26
+ ```
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=convert-case.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert-case.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/convert-case.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=create-url-map.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-url-map.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/create-url-map.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wrap-interface-key-guard.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-interface-key-guard.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/wrap-interface-key-guard.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Convert string based on convertCase option
3
+ */
4
+ export declare function convertCase(str: string, caseType?: 'snake' | 'camel' | 'pascal' | 'maintain'): string;
5
+ //# sourceMappingURL=convert-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert-case.d.ts","sourceRoot":"","sources":["../src/convert-case.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAoB,GAC5D,MAAM,CAaR"}
@@ -0,0 +1,4 @@
1
+ import type { DevupApiTypeGeneratorOptions, UrlMapValue } from '@devup-api/core';
2
+ import type { OpenAPIV3_1 } from 'openapi-types';
3
+ export declare function createUrlMap(schema: OpenAPIV3_1.Document, options?: DevupApiTypeGeneratorOptions): Record<string, UrlMapValue>;
4
+ //# sourceMappingURL=create-url-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-url-map.d.ts","sourceRoot":"","sources":["../src/create-url-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAGhD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,WAAW,CAAC,QAAQ,EAC5B,OAAO,CAAC,EAAE,4BAA4B,+BAoCvC"}
@@ -0,0 +1,15 @@
1
+ import type { DevupApiTypeGeneratorOptions } from '@devup-api/core';
2
+ import type { OpenAPIV3_1 } from 'openapi-types';
3
+ export interface ParameterDefinition extends Omit<OpenAPIV3_1.ParameterObject, 'schema'> {
4
+ type: unknown;
5
+ default?: unknown;
6
+ }
7
+ export interface EndpointDefinition {
8
+ params?: Record<string, ParameterDefinition>;
9
+ body?: unknown;
10
+ query?: Record<string, ParameterDefinition>;
11
+ response?: unknown;
12
+ error?: unknown;
13
+ }
14
+ export declare function generateInterface(schema: OpenAPIV3_1.Document, options?: DevupApiTypeGeneratorOptions): string;
15
+ //# sourceMappingURL=generate-interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-interface.d.ts","sourceRoot":"","sources":["../src/generate-interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAA;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAUhD,MAAM,WAAW,mBACf,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,QAAQ,CAAC;IACnD,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AASD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,CAAC,QAAQ,EAC5B,OAAO,CAAC,EAAE,4BAA4B,GACrC,MAAM,CA6iBR"}
@@ -0,0 +1,44 @@
1
+ import type { OpenAPIV3_1 } from 'openapi-types';
2
+ import type { ParameterDefinition } from './generate-interface';
3
+ /**
4
+ * Resolve $ref reference in OpenAPI parameter
5
+ */
6
+ export declare function resolveParameterRef(ref: string, document: OpenAPIV3_1.Document): OpenAPIV3_1.ParameterObject | null;
7
+ /**
8
+ * Resolve $ref reference in OpenAPI schema
9
+ */
10
+ export declare function resolveSchemaRef(ref: string, document: OpenAPIV3_1.Document): OpenAPIV3_1.SchemaObject | null;
11
+ /**
12
+ * Convert OpenAPI schema to TypeScript type representation
13
+ */
14
+ export declare function getTypeFromSchema(schema: OpenAPIV3_1.SchemaObject | OpenAPIV3_1.ReferenceObject, document: OpenAPIV3_1.Document, options?: {
15
+ defaultNonNullable?: boolean;
16
+ }): {
17
+ type: unknown;
18
+ default?: unknown;
19
+ };
20
+ /**
21
+ * Check if all properties in an object are optional
22
+ */
23
+ export declare function areAllPropertiesOptional(obj: Record<string, unknown>): boolean;
24
+ /**
25
+ * Format a type object to TypeScript interface/type string
26
+ */
27
+ export declare function formatType(obj: Record<string, unknown>, indent?: number): string;
28
+ /**
29
+ * Format a type value to TypeScript type string
30
+ */
31
+ export declare function formatTypeValue(value: unknown, indent?: number): string;
32
+ /**
33
+ * Extract parameters from OpenAPI operation
34
+ */
35
+ export declare function extractParameters(pathItem: OpenAPIV3_1.PathItemObject | undefined, operation: OpenAPIV3_1.OperationObject | undefined, document: OpenAPIV3_1.Document): {
36
+ pathParams: Record<string, ParameterDefinition>;
37
+ queryParams: Record<string, ParameterDefinition>;
38
+ headerParams: Record<string, ParameterDefinition>;
39
+ };
40
+ /**
41
+ * Extract request body from OpenAPI operation
42
+ */
43
+ export declare function extractRequestBody(requestBody: OpenAPIV3_1.RequestBodyObject | OpenAPIV3_1.ReferenceObject | undefined, document: OpenAPIV3_1.Document): unknown;
44
+ //# sourceMappingURL=generate-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-schema.d.ts","sourceRoot":"","sources":["../src/generate-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAE/D;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,WAAW,CAAC,QAAQ,GAC7B,WAAW,CAAC,eAAe,GAAG,IAAI,CAqBpC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,WAAW,CAAC,QAAQ,GAC7B,WAAW,CAAC,YAAY,GAAG,IAAI,CAqBjC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,CAAC,YAAY,GAAG,WAAW,CAAC,eAAe,EAC9D,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAC9B,OAAO,CAAC,EAAE;IACR,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,GACA;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAqItC;AAeD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,OAAO,CAqCT;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,MAAM,GAAE,MAAU,GACjB,MAAM,CAyDR;AAiBD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM,CAe1E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,WAAW,CAAC,cAAc,GAAG,SAAS,EAChD,SAAS,EAAE,WAAW,CAAC,eAAe,GAAG,SAAS,EAClD,QAAQ,EAAE,WAAW,CAAC,QAAQ,GAC7B;IACD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAC/C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAChD,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;CAClD,CAkEA;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EACP,WAAW,CAAC,iBAAiB,GAC7B,WAAW,CAAC,eAAe,GAC3B,SAAS,EACb,QAAQ,EAAE,WAAW,CAAC,QAAQ,GAC7B,OAAO,CA+BT"}
package/dist/index.cjs ADDED
@@ -0,0 +1,36 @@
1
+ var{defineProperty:p,getOwnPropertyNames:H$,getOwnPropertyDescriptor:J$}=Object,L$=Object.prototype.hasOwnProperty;var o=new WeakMap,U$=($)=>{var L=o.get($),Y;if(L)return L;if(L=p({},"__esModule",{value:!0}),$&&typeof $==="object"||typeof $==="function")H$($).map((J)=>!L$.call(L,J)&&p(L,J,{get:()=>$[J],enumerable:!(Y=J$($,J))||Y.enumerable}));return o.set($,L),L};var X$=($,L)=>{for(var Y in L)p($,Y,{get:L[Y],enumerable:!0,configurable:!0,set:(J)=>L[Y]=()=>J})};var Q$={};X$(Q$,{generateInterface:()=>W$,createUrlMap:()=>Y$});module.exports=U$(Q$);var i=require("@devup-api/utils");function O($,L="camel"){switch(L){case"snake":return i.toSnake($);case"camel":return i.toCamel($);case"pascal":return i.toPascal($);case"maintain":return $;default:return $}}function Y$($,L){let Y=L?.convertCase??"camel",J={};for(let[H,X]of Object.entries($.paths??{})){if(!X)continue;for(let W of["get","post","put","delete","patch"]){let U=X[W];if(!U)continue;let x=H.replace(/\{([^}]+)\}/g,(P,R)=>{return`{${O(R,Y)}}`});if(U.operationId)J[O(U.operationId,Y)]={method:W.toUpperCase(),url:x};J[x]={method:W.toUpperCase(),url:x}}}return J}var e=require("@devup-api/utils");function Z$($,L){if(!$.startsWith("#/"))return null;let Y=$.slice(2).split("/"),J=L;for(let H of Y)if(J&&typeof J==="object"&&H in J)J=J[H];else return null;if(J&&typeof J==="object"&&!("$ref"in J))return J;return null}function c($,L){if(!$.startsWith("#/"))return null;let Y=$.slice(2).split("/"),J=L;for(let H of Y)if(J&&typeof J==="object"&&H in J)J=J[H];else return null;if(J&&typeof J==="object"&&!("$ref"in J))return J;return null}function D($,L,Y){let J=Y?.defaultNonNullable??!1;if("$ref"in $){let X=c($.$ref,L);if(X)return D(X,L,Y);return{type:"unknown",default:void 0}}let H=$;if(H.allOf){let X=H.allOf.map((W)=>D(W,L,Y));return{type:X.length>0?X.map((W)=>k(W.type)).join(" & "):"unknown",default:H.default}}if(H.anyOf||H.oneOf){let X=(H.anyOf||H.oneOf||[]).map((W)=>D(W,L,Y));return{type:X.length>0?`(${X.map((W)=>k(W.type)).join(" | ")})`:"unknown",default:H.default}}if(H.enum)return{type:H.enum.map((X)=>`"${String(X)}"`).join(" | "),default:H.default};if(H.type==="string"){if(H.format==="date"||H.format==="date-time")return{type:"string",default:H.default};return{type:"string",default:H.default}}if(H.type==="number"||H.type==="integer")return{type:"number",default:H.default};if(H.type==="boolean")return{type:"boolean",default:H.default};if(H.type==="array"){let X=H.items;if(X){let W=D(X,L,Y);return{type:`Array<${k(W.type)}>`,default:H.default}}return{type:"unknown[]",default:H.default}}if(H.type==="object"||H.properties){let X={},W=H.required||[];if(H.properties)for(let[U,x]of Object.entries(H.properties)){let P=D(x,L,Y),R=!1;if("$ref"in x){let G=c(x.$ref,L);if(G)R=G.default!==void 0}else R=x.default!==void 0;let F=W.includes(U);if(J&&R&&!F)X[U]=P;else if(!F)X[`${U}?`]=P;else X[U]=P}if(H.additionalProperties){if(H.additionalProperties===!0)X["[key: string]"]={type:"unknown",default:void 0};else if(typeof H.additionalProperties==="object"){let U=D(H.additionalProperties,L,Y);X["[key: string]"]={type:U.type,default:U.default}}}return{type:{...X},default:H.default}}return{type:"unknown",default:void 0}}function t($){return typeof $==="object"&&$!==null&&"type"in $&&"in"in $&&"name"in $}function m($){let L=Object.entries($);if(L.length===0)return!0;return L.every(([Y,J])=>{if(Y.endsWith("?"))return!0;if(t(J))return J.required===!1;if(n(J)){if(typeof J.type==="object"&&J.type!==null&&!Array.isArray(J.type))return m(J.type);return!1}if(typeof J==="object"&&J!==null&&!Array.isArray(J))return m(J);return!1})}function _$($,L=0){let Y=" ".repeat(L),J=L+1,H=" ".repeat(J),X=Object.entries($).map(([W,U])=>{if(typeof U==="string")return`${H}${W}: ${U}`;if(t(U)){let F=k(U.type,J),S=U.required===!1?`${W}?`:W,g="";if(U.description){if(g+=`${H}/**
2
+ ${H} * ${U.description}`,typeof U.default<"u")g+=`
3
+ ${H} * @default {${U.default}}`;g=`${g}
4
+ ${H} */
5
+ ${H}`}else if(typeof U.default<"u")g+=`${H}/** @default {${U.default}} */
6
+ ${H}`;else g=H;return`${g}${S}: ${F}`}if(n(U)){let F=k(U.type,J);return`${H}${W}: ${F}`}let P=typeof U==="object"&&U!==null&&!Array.isArray(U)&&m(U)?"?":"",R=k(U,J);return`${H}${W}${P}: ${R}`}).join(`;
7
+ `);if(X.length===0)return"{}";return`{
8
+ ${X};
9
+ ${Y}}`}function n($){return typeof $==="object"&&$!==null&&"type"in $&&Object.keys($).length<=2&&(!("default"in $)||Object.keys($).length===2)}function k($,L=0){if(typeof $==="string")return $;if(n($))return k($.type,L);if(typeof $==="object"&&$!==null&&!Array.isArray($))return _$($,L);return String($)}function a($,L,Y){let J={},H={},X={},W=[...$?.parameters||[],...L?.parameters||[]];for(let U of W){if("$ref"in U){let G=Z$(U.$ref,Y);if(G&&"in"in G&&"name"in G&&typeof G.in==="string"&&typeof G.name==="string"){let S="schema"in G&&G.schema?G.schema:{},{type:g,default:d}=D(S,Y,{defaultNonNullable:!1}),N={...G,type:g,default:d};if(G.in==="path")J[G.name]=N;else if(G.in==="query")H[G.name]=N;else if(G.in==="header")X[G.name]=N}continue}let x=U.schema||{},{type:P,default:R}=D(x,Y,{defaultNonNullable:!1}),F={...U,type:P,default:R};if(U.in==="path")J[U.name]=F;else if(U.in==="query")H[U.name]=F;else if(U.in==="header")X[U.name]=F}return{pathParams:J,queryParams:H,headerParams:X}}function l($,L){if(!$)return;if("$ref"in $){let J=c($.$ref,L);if(J&&"content"in J&&J.content){let X=J.content["application/json"];if(X&&"schema"in X&&X.schema)return D(X.schema,L,{defaultNonNullable:!1}).type}return"unknown"}let Y=$.content;if(Y){let J=Y["application/json"];if(J&&"schema"in J&&J.schema)return D(J.schema,L,{defaultNonNullable:!1}).type}return}function v($){if($.includes("/"))return`[\`${$}\`]`;return $}function f($){if($.startsWith("#/components/schemas/"))return $.replace("#/components/schemas/","");return null}function W$($,L){let Y={get:{},post:{},put:{},delete:{},patch:{}},J=L?.convertCase??"camel",H=(Q,z)=>{if("$ref"in Q){let A=f(Q.$ref);if(A)z.add(A);return}let w=Q;if(w.allOf)w.allOf.forEach((A)=>{H(A,z)});if(w.anyOf)w.anyOf.forEach((A)=>{H(A,z)});if(w.oneOf)w.oneOf.forEach((A)=>{H(A,z)});if(w.properties)Object.values(w.properties).forEach((A)=>{H(A,z)});if(w.type==="array"&&"items"in w&&w.items)H(w.items,z)},X=new Set,W=new Set,U=new Set,x=(Q)=>{if(Q==="default")return!0;let z=parseInt(Q,10);return z>=400&&z<600};if($.paths)for(let Q of Object.values($.paths)){if(!Q)continue;let z=["get","post","put","delete","patch"];for(let w of z){let A=Q[w];if(!A)continue;if(A.requestBody)if("$ref"in A.requestBody){let Z=f(A.requestBody.$ref);if(Z)X.add(Z)}else{let M=A.requestBody.content?.["application/json"];if(M&&"schema"in M&&M.schema)H(M.schema,X)}if(A.responses)for(let[Z,M]of Object.entries(A.responses)){let C=x(Z);if("$ref"in M){let j=f(M.$ref);if(j)if(C)U.add(j);else W.add(j)}else if("content"in M){let q=M.content?.["application/json"];if(q&&"schema"in q&&q.schema)if(C)H(q.schema,U);else H(q.schema,W)}}}}if($.paths)for(let[Q,z]of Object.entries($.paths)){if(!z)continue;let w=["get","post","put","delete","patch"];for(let A of w){let Z=z[A];if(!Z)continue;let M={},{pathParams:C,queryParams:j}=a(z,Z,$),q={};for(let[E,B]of Object.entries(C)){let _=O(E,J);q[_]=B}let h={};for(let[E,B]of Object.entries(j)){let _=O(E,J);h[_]=B}if(Object.keys(q).length>0)M.params=q;if(Object.keys(h).length>0)M.query=h;let y;if(Z.requestBody)if("$ref"in Z.requestBody){let E=l(Z.requestBody,$);if(E!==void 0)y=E}else{let B=Z.requestBody.content?.["application/json"];if(B&&"schema"in B&&B.schema)if("$ref"in B.schema){let _=f(B.schema.$ref);if(_&&$.components?.schemas?.[_]&&X.has(_))y=`DevupRequestComponentStruct['${_}']`;else{let K=l(Z.requestBody,$);if(K!==void 0)y=K}}else{let _=l(Z.requestBody,$);if(_!==void 0)y=_}}if(y!==void 0)M.body=y;let b;if(Z.responses){let E=Z.responses["200"]||Z.responses["201"]||Object.values(Z.responses)[0];if(E){if("$ref"in E);else if("content"in E){let _=E.content?.["application/json"];if(_&&"schema"in _&&_.schema)if("$ref"in _.schema){let K=f(_.schema.$ref);if(K&&$.components?.schemas?.[K]&&W.has(K))b=`DevupResponseComponentStruct['${K}']`;else{let V=L?.responseDefaultNonNullable??!0,{type:I}=D(_.schema,$,{defaultNonNullable:V});b=I}}else{let K=_.schema;if(K.type==="array"&&K.items&&"$ref"in K.items){let V=f(K.items.$ref);if(V&&$.components?.schemas?.[V]&&W.has(V))b=`Array<DevupResponseComponentStruct['${V}']>`;else{let I=L?.responseDefaultNonNullable??!0,{type:u}=D(_.schema,$,{defaultNonNullable:I});b=u}}else{let V=L?.responseDefaultNonNullable??!0,{type:I}=D(_.schema,$,{defaultNonNullable:V});b=I}}}}}if(b!==void 0)M.response=b;let T;if(Z.responses){let E=Z.responses["400"]||Z.responses["401"]||Z.responses["403"]||Z.responses["404"]||Z.responses["422"]||Z.responses["500"]||Z.responses.default||Object.entries(Z.responses).find(([B])=>x(B))?.[1];if(E){if("$ref"in E);else if("content"in E){let _=E.content?.["application/json"];if(_&&"schema"in _&&_.schema)if("$ref"in _.schema){let K=f(_.schema.$ref);if(K&&$.components?.schemas?.[K]&&U.has(K))T=`DevupErrorComponentStruct['${K}']`;else{let V=L?.responseDefaultNonNullable??!0,{type:I}=D(_.schema,$,{defaultNonNullable:V});T=I}}else{let K=_.schema;if(K.type==="array"&&K.items&&"$ref"in K.items){let V=f(K.items.$ref);if(V&&$.components?.schemas?.[V]&&U.has(V))T=`Array<DevupErrorComponentStruct['${V}']>`;else{let I=L?.responseDefaultNonNullable??!0,{type:u}=D(_.schema,$,{defaultNonNullable:I});T=u}}else{let V=L?.responseDefaultNonNullable??!0,{type:I}=D(_.schema,$,{defaultNonNullable:V});T=I}}}}}if(T!==void 0)M.error=T;let $$=Q.replace(/\{([^}]+)\}/g,(E,B)=>{return`{${O(B,J)}}`});if(Y[A][$$]=M,Z.operationId){let E=O(Z.operationId,J);Y[A][E]=M}}}let P={},R={},F={};if($.components?.schemas){for(let[Q,z]of Object.entries($.components.schemas))if(z){let w=L?.requestDefaultNonNullable??!1,Z=L?.responseDefaultNonNullable??!0;if(X.has(Q))Z=w;let{type:M}=D(z,$,{defaultNonNullable:Z});if(X.has(Q))P[Q]=M;if(W.has(Q))R[Q]=M;if(U.has(Q))F[Q]=M}}let G=Object.entries(Y).flatMap(([Q,z])=>{let w=Object.entries(z);if(w.length>0){let A=w.map(([Z,M])=>{let C=k(M,2);return` ${v(Z)}: ${C}`}).join(`;
10
+ `);return[` interface Devup${e.toPascal(Q)}ApiStruct {
11
+ ${A};
12
+ }`]}return[]}).join(`
13
+ `),S=Object.entries(P).map(([Q,z])=>{let w=k(z,2);return` ${v(Q)}: ${w}`}).join(`;
14
+ `),g=S.length>0?` interface DevupRequestComponentStruct {
15
+ ${S};
16
+ }`:" interface DevupRequestComponentStruct {}",d=Object.entries(R).map(([Q,z])=>{let w=k(z,2);return` ${v(Q)}: ${w}`}).join(`;
17
+ `),N=d.length>0?` interface DevupResponseComponentStruct {
18
+ ${d};
19
+ }`:" interface DevupResponseComponentStruct {}",r=Object.entries(F).map(([Q,z])=>{let w=k(z,2);return` ${v(Q)}: ${w}`}).join(`;
20
+ `),s=r.length>0?` interface DevupErrorComponentStruct {
21
+ ${r};
22
+ }`:" interface DevupErrorComponentStruct {}";return`import "@devup-api/fetch";
23
+
24
+ declare module "@devup-api/fetch" {
25
+ ${G?`${G}
26
+
27
+ ${g}
28
+
29
+ ${N}
30
+
31
+ ${s}`:`${g}
32
+
33
+ ${N}
34
+
35
+ ${s}`}
36
+ }`}
@@ -0,0 +1,3 @@
1
+ export * from './create-url-map';
2
+ export * from './generate-interface';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,sBAAsB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ import{toCamel as t,toPascal as a,toSnake as e}from"@devup-api/utils";function O($,U="camel"){switch(U){case"snake":return e($);case"camel":return t($);case"pascal":return a($);case"maintain":return $;default:return $}}function Z$($,U){let _=U?.convertCase??"camel",J={};for(let[H,X]of Object.entries($.paths??{})){if(!X)continue;for(let W of["get","post","put","delete","patch"]){let L=X[W];if(!L)continue;let x=H.replace(/\{([^}]+)\}/g,(P,R)=>{return`{${O(R,_)}}`});if(L.operationId)J[O(L.operationId,_)]={method:W.toUpperCase(),url:x};J[x]={method:W.toUpperCase(),url:x}}}return J}import{toPascal as J$}from"@devup-api/utils";function $$($,U){if(!$.startsWith("#/"))return null;let _=$.slice(2).split("/"),J=U;for(let H of _)if(J&&typeof J==="object"&&H in J)J=J[H];else return null;if(J&&typeof J==="object"&&!("$ref"in J))return J;return null}function u($,U){if(!$.startsWith("#/"))return null;let _=$.slice(2).split("/"),J=U;for(let H of _)if(J&&typeof J==="object"&&H in J)J=J[H];else return null;if(J&&typeof J==="object"&&!("$ref"in J))return J;return null}function D($,U,_){let J=_?.defaultNonNullable??!1;if("$ref"in $){let X=u($.$ref,U);if(X)return D(X,U,_);return{type:"unknown",default:void 0}}let H=$;if(H.allOf){let X=H.allOf.map((W)=>D(W,U,_));return{type:X.length>0?X.map((W)=>k(W.type)).join(" & "):"unknown",default:H.default}}if(H.anyOf||H.oneOf){let X=(H.anyOf||H.oneOf||[]).map((W)=>D(W,U,_));return{type:X.length>0?`(${X.map((W)=>k(W.type)).join(" | ")})`:"unknown",default:H.default}}if(H.enum)return{type:H.enum.map((X)=>`"${String(X)}"`).join(" | "),default:H.default};if(H.type==="string"){if(H.format==="date"||H.format==="date-time")return{type:"string",default:H.default};return{type:"string",default:H.default}}if(H.type==="number"||H.type==="integer")return{type:"number",default:H.default};if(H.type==="boolean")return{type:"boolean",default:H.default};if(H.type==="array"){let X=H.items;if(X){let W=D(X,U,_);return{type:`Array<${k(W.type)}>`,default:H.default}}return{type:"unknown[]",default:H.default}}if(H.type==="object"||H.properties){let X={},W=H.required||[];if(H.properties)for(let[L,x]of Object.entries(H.properties)){let P=D(x,U,_),R=!1;if("$ref"in x){let G=u(x.$ref,U);if(G)R=G.default!==void 0}else R=x.default!==void 0;let F=W.includes(L);if(J&&R&&!F)X[L]=P;else if(!F)X[`${L}?`]=P;else X[L]=P}if(H.additionalProperties){if(H.additionalProperties===!0)X["[key: string]"]={type:"unknown",default:void 0};else if(typeof H.additionalProperties==="object"){let L=D(H.additionalProperties,U,_);X["[key: string]"]={type:L.type,default:L.default}}}return{type:{...X},default:H.default}}return{type:"unknown",default:void 0}}function r($){return typeof $==="object"&&$!==null&&"type"in $&&"in"in $&&"name"in $}function p($){let U=Object.entries($);if(U.length===0)return!0;return U.every(([_,J])=>{if(_.endsWith("?"))return!0;if(r(J))return J.required===!1;if(c(J)){if(typeof J.type==="object"&&J.type!==null&&!Array.isArray(J.type))return p(J.type);return!1}if(typeof J==="object"&&J!==null&&!Array.isArray(J))return p(J);return!1})}function H$($,U=0){let _=" ".repeat(U),J=U+1,H=" ".repeat(J),X=Object.entries($).map(([W,L])=>{if(typeof L==="string")return`${H}${W}: ${L}`;if(r(L)){let F=k(L.type,J),S=L.required===!1?`${W}?`:W,g="";if(L.description){if(g+=`${H}/**
2
+ ${H} * ${L.description}`,typeof L.default<"u")g+=`
3
+ ${H} * @default {${L.default}}`;g=`${g}
4
+ ${H} */
5
+ ${H}`}else if(typeof L.default<"u")g+=`${H}/** @default {${L.default}} */
6
+ ${H}`;else g=H;return`${g}${S}: ${F}`}if(c(L)){let F=k(L.type,J);return`${H}${W}: ${F}`}let P=typeof L==="object"&&L!==null&&!Array.isArray(L)&&p(L)?"?":"",R=k(L,J);return`${H}${W}${P}: ${R}`}).join(`;
7
+ `);if(X.length===0)return"{}";return`{
8
+ ${X};
9
+ ${_}}`}function c($){return typeof $==="object"&&$!==null&&"type"in $&&Object.keys($).length<=2&&(!("default"in $)||Object.keys($).length===2)}function k($,U=0){if(typeof $==="string")return $;if(c($))return k($.type,U);if(typeof $==="object"&&$!==null&&!Array.isArray($))return H$($,U);return String($)}function s($,U,_){let J={},H={},X={},W=[...$?.parameters||[],...U?.parameters||[]];for(let L of W){if("$ref"in L){let G=$$(L.$ref,_);if(G&&"in"in G&&"name"in G&&typeof G.in==="string"&&typeof G.name==="string"){let S="schema"in G&&G.schema?G.schema:{},{type:g,default:v}=D(S,_,{defaultNonNullable:!1}),N={...G,type:g,default:v};if(G.in==="path")J[G.name]=N;else if(G.in==="query")H[G.name]=N;else if(G.in==="header")X[G.name]=N}continue}let x=L.schema||{},{type:P,default:R}=D(x,_,{defaultNonNullable:!1}),F={...L,type:P,default:R};if(L.in==="path")J[L.name]=F;else if(L.in==="query")H[L.name]=F;else if(L.in==="header")X[L.name]=F}return{pathParams:J,queryParams:H,headerParams:X}}function d($,U){if(!$)return;if("$ref"in $){let J=u($.$ref,U);if(J&&"content"in J&&J.content){let X=J.content["application/json"];if(X&&"schema"in X&&X.schema)return D(X.schema,U,{defaultNonNullable:!1}).type}return"unknown"}let _=$.content;if(_){let J=_["application/json"];if(J&&"schema"in J&&J.schema)return D(J.schema,U,{defaultNonNullable:!1}).type}return}function i($){if($.includes("/"))return`[\`${$}\`]`;return $}function f($){if($.startsWith("#/components/schemas/"))return $.replace("#/components/schemas/","");return null}function M$($,U){let _={get:{},post:{},put:{},delete:{},patch:{}},J=U?.convertCase??"camel",H=(Q,z)=>{if("$ref"in Q){let A=f(Q.$ref);if(A)z.add(A);return}let w=Q;if(w.allOf)w.allOf.forEach((A)=>{H(A,z)});if(w.anyOf)w.anyOf.forEach((A)=>{H(A,z)});if(w.oneOf)w.oneOf.forEach((A)=>{H(A,z)});if(w.properties)Object.values(w.properties).forEach((A)=>{H(A,z)});if(w.type==="array"&&"items"in w&&w.items)H(w.items,z)},X=new Set,W=new Set,L=new Set,x=(Q)=>{if(Q==="default")return!0;let z=parseInt(Q,10);return z>=400&&z<600};if($.paths)for(let Q of Object.values($.paths)){if(!Q)continue;let z=["get","post","put","delete","patch"];for(let w of z){let A=Q[w];if(!A)continue;if(A.requestBody)if("$ref"in A.requestBody){let Y=f(A.requestBody.$ref);if(Y)X.add(Y)}else{let M=A.requestBody.content?.["application/json"];if(M&&"schema"in M&&M.schema)H(M.schema,X)}if(A.responses)for(let[Y,M]of Object.entries(A.responses)){let C=x(Y);if("$ref"in M){let j=f(M.$ref);if(j)if(C)L.add(j);else W.add(j)}else if("content"in M){let q=M.content?.["application/json"];if(q&&"schema"in q&&q.schema)if(C)H(q.schema,L);else H(q.schema,W)}}}}if($.paths)for(let[Q,z]of Object.entries($.paths)){if(!z)continue;let w=["get","post","put","delete","patch"];for(let A of w){let Y=z[A];if(!Y)continue;let M={},{pathParams:C,queryParams:j}=s(z,Y,$),q={};for(let[E,B]of Object.entries(C)){let Z=O(E,J);q[Z]=B}let l={};for(let[E,B]of Object.entries(j)){let Z=O(E,J);l[Z]=B}if(Object.keys(q).length>0)M.params=q;if(Object.keys(l).length>0)M.query=l;let y;if(Y.requestBody)if("$ref"in Y.requestBody){let E=d(Y.requestBody,$);if(E!==void 0)y=E}else{let B=Y.requestBody.content?.["application/json"];if(B&&"schema"in B&&B.schema)if("$ref"in B.schema){let Z=f(B.schema.$ref);if(Z&&$.components?.schemas?.[Z]&&X.has(Z))y=`DevupRequestComponentStruct['${Z}']`;else{let K=d(Y.requestBody,$);if(K!==void 0)y=K}}else{let Z=d(Y.requestBody,$);if(Z!==void 0)y=Z}}if(y!==void 0)M.body=y;let b;if(Y.responses){let E=Y.responses["200"]||Y.responses["201"]||Object.values(Y.responses)[0];if(E){if("$ref"in E);else if("content"in E){let Z=E.content?.["application/json"];if(Z&&"schema"in Z&&Z.schema)if("$ref"in Z.schema){let K=f(Z.schema.$ref);if(K&&$.components?.schemas?.[K]&&W.has(K))b=`DevupResponseComponentStruct['${K}']`;else{let V=U?.responseDefaultNonNullable??!0,{type:I}=D(Z.schema,$,{defaultNonNullable:V});b=I}}else{let K=Z.schema;if(K.type==="array"&&K.items&&"$ref"in K.items){let V=f(K.items.$ref);if(V&&$.components?.schemas?.[V]&&W.has(V))b=`Array<DevupResponseComponentStruct['${V}']>`;else{let I=U?.responseDefaultNonNullable??!0,{type:h}=D(Z.schema,$,{defaultNonNullable:I});b=h}}else{let V=U?.responseDefaultNonNullable??!0,{type:I}=D(Z.schema,$,{defaultNonNullable:V});b=I}}}}}if(b!==void 0)M.response=b;let T;if(Y.responses){let E=Y.responses["400"]||Y.responses["401"]||Y.responses["403"]||Y.responses["404"]||Y.responses["422"]||Y.responses["500"]||Y.responses.default||Object.entries(Y.responses).find(([B])=>x(B))?.[1];if(E){if("$ref"in E);else if("content"in E){let Z=E.content?.["application/json"];if(Z&&"schema"in Z&&Z.schema)if("$ref"in Z.schema){let K=f(Z.schema.$ref);if(K&&$.components?.schemas?.[K]&&L.has(K))T=`DevupErrorComponentStruct['${K}']`;else{let V=U?.responseDefaultNonNullable??!0,{type:I}=D(Z.schema,$,{defaultNonNullable:V});T=I}}else{let K=Z.schema;if(K.type==="array"&&K.items&&"$ref"in K.items){let V=f(K.items.$ref);if(V&&$.components?.schemas?.[V]&&L.has(V))T=`Array<DevupErrorComponentStruct['${V}']>`;else{let I=U?.responseDefaultNonNullable??!0,{type:h}=D(Z.schema,$,{defaultNonNullable:I});T=h}}else{let V=U?.responseDefaultNonNullable??!0,{type:I}=D(Z.schema,$,{defaultNonNullable:V});T=I}}}}}if(T!==void 0)M.error=T;let o=Q.replace(/\{([^}]+)\}/g,(E,B)=>{return`{${O(B,J)}}`});if(_[A][o]=M,Y.operationId){let E=O(Y.operationId,J);_[A][E]=M}}}let P={},R={},F={};if($.components?.schemas){for(let[Q,z]of Object.entries($.components.schemas))if(z){let w=U?.requestDefaultNonNullable??!1,Y=U?.responseDefaultNonNullable??!0;if(X.has(Q))Y=w;let{type:M}=D(z,$,{defaultNonNullable:Y});if(X.has(Q))P[Q]=M;if(W.has(Q))R[Q]=M;if(L.has(Q))F[Q]=M}}let G=Object.entries(_).flatMap(([Q,z])=>{let w=Object.entries(z);if(w.length>0){let A=w.map(([Y,M])=>{let C=k(M,2);return` ${i(Y)}: ${C}`}).join(`;
10
+ `);return[` interface Devup${J$(Q)}ApiStruct {
11
+ ${A};
12
+ }`]}return[]}).join(`
13
+ `),S=Object.entries(P).map(([Q,z])=>{let w=k(z,2);return` ${i(Q)}: ${w}`}).join(`;
14
+ `),g=S.length>0?` interface DevupRequestComponentStruct {
15
+ ${S};
16
+ }`:" interface DevupRequestComponentStruct {}",v=Object.entries(R).map(([Q,z])=>{let w=k(z,2);return` ${i(Q)}: ${w}`}).join(`;
17
+ `),N=v.length>0?` interface DevupResponseComponentStruct {
18
+ ${v};
19
+ }`:" interface DevupResponseComponentStruct {}",m=Object.entries(F).map(([Q,z])=>{let w=k(z,2);return` ${i(Q)}: ${w}`}).join(`;
20
+ `),n=m.length>0?` interface DevupErrorComponentStruct {
21
+ ${m};
22
+ }`:" interface DevupErrorComponentStruct {}";return`import "@devup-api/fetch";
23
+
24
+ declare module "@devup-api/fetch" {
25
+ ${G?`${G}
26
+
27
+ ${g}
28
+
29
+ ${N}
30
+
31
+ ${n}`:`${g}
32
+
33
+ ${N}
34
+
35
+ ${n}`}
36
+ }`}export{M$ as generateInterface,Z$ as createUrlMap};
@@ -0,0 +1,2 @@
1
+ export declare function wrapInterfaceKeyGuard(key: string): string;
2
+ //# sourceMappingURL=wrap-interface-key-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-interface-key-guard.d.ts","sourceRoot":"","sources":["../src/wrap-interface-key-guard.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKzD"}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@devup-api/generator",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "import": "./dist/index.js",
8
+ "require": "./dist/index.cjs",
9
+ "types": "./dist/index.d.ts"
10
+ }
11
+ },
12
+ "scripts": {
13
+ "build": "tsc && bun build --target node --outfile=dist/index.js src/index.ts --production --packages=external && bun build --target node --outfile=dist/index.cjs --format=cjs src/index.ts --production --packages=external"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "dependencies": {
19
+ "@devup-api/core": "0.1.0",
20
+ "@devup-api/utils": "0.1.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^24.10",
24
+ "typescript": "^5.9",
25
+ "openapi-types": "^12.1"
26
+ }
27
+ }
@@ -0,0 +1,125 @@
1
+ import { expect, test } from 'bun:test'
2
+ import { convertCase } from '../convert-case'
3
+
4
+ test.each([
5
+ ['hello_world', 'snake', 'hello_world'],
6
+ ['my_variable_name', 'snake', 'my_variable_name'],
7
+ ['snake_case_string', 'snake', 'snake_case_string'],
8
+ ])('converts to snake_case: %s -> %s', (input, caseType, expected) => {
9
+ expect(convertCase(input, caseType as 'snake')).toBe(expected)
10
+ })
11
+
12
+ test.each([
13
+ ['HelloWorld', 'snake', 'hello_world'],
14
+ ['MyVariableName', 'snake', 'my_variable_name'],
15
+ ['PascalCaseString', 'snake', 'pascal_case_string'],
16
+ ])('converts PascalCase to snake_case: %s -> %s', (input, caseType, expected) => {
17
+ expect(convertCase(input, caseType as 'snake')).toBe(expected)
18
+ })
19
+
20
+ test.each([
21
+ ['helloWorld', 'snake', 'hello_world'],
22
+ ['myVariableName', 'snake', 'my_variable_name'],
23
+ ['camelCaseString', 'snake', 'camel_case_string'],
24
+ ])('converts camelCase to snake_case: %s -> %s', (input, caseType, expected) => {
25
+ expect(convertCase(input, caseType as 'snake')).toBe(expected)
26
+ })
27
+
28
+ test.each([
29
+ ['hello_world', 'camel', 'helloWorld'],
30
+ ['my_variable_name', 'camel', 'myVariableName'],
31
+ ['snake_case_string', 'camel', 'snakeCaseString'],
32
+ ])('converts to camelCase: %s -> %s', (input, caseType, expected) => {
33
+ expect(convertCase(input, caseType as 'camel')).toBe(expected)
34
+ })
35
+
36
+ test.each([
37
+ ['HelloWorld', 'camel', 'helloWorld'],
38
+ ['MyVariableName', 'camel', 'myVariableName'],
39
+ ['PascalCaseString', 'camel', 'pascalCaseString'],
40
+ ])('converts PascalCase to camelCase: %s -> %s', (input, caseType, expected) => {
41
+ expect(convertCase(input, caseType as 'camel')).toBe(expected)
42
+ })
43
+
44
+ test.each([
45
+ ['helloWorld', 'camel', 'helloWorld'],
46
+ ['myVariableName', 'camel', 'myVariableName'],
47
+ ['camelCaseString', 'camel', 'camelCaseString'],
48
+ ])('returns camelCase strings unchanged: %s -> %s', (input, caseType, expected) => {
49
+ expect(convertCase(input, caseType as 'camel')).toBe(expected)
50
+ })
51
+
52
+ test.each([
53
+ ['hello_world', 'pascal', 'HelloWorld'],
54
+ ['my_variable_name', 'pascal', 'MyVariableName'],
55
+ ['snake_case_string', 'pascal', 'SnakeCaseString'],
56
+ ])('converts to PascalCase: %s -> %s', (input, caseType, expected) => {
57
+ expect(convertCase(input, caseType as 'pascal')).toBe(expected)
58
+ })
59
+
60
+ test.each([
61
+ ['helloWorld', 'pascal', 'HelloWorld'],
62
+ ['myVariableName', 'pascal', 'MyVariableName'],
63
+ ['camelCaseString', 'pascal', 'CamelCaseString'],
64
+ ])('converts camelCase to PascalCase: %s -> %s', (input, caseType, expected) => {
65
+ expect(convertCase(input, caseType as 'pascal')).toBe(expected)
66
+ })
67
+
68
+ test.each([
69
+ ['HelloWorld', 'pascal', 'HelloWorld'],
70
+ ['MyVariableName', 'pascal', 'MyVariableName'],
71
+ ['PascalCaseString', 'pascal', 'PascalCaseString'],
72
+ ])('returns PascalCase strings unchanged: %s -> %s', (input, caseType, expected) => {
73
+ expect(convertCase(input, caseType as 'pascal')).toBe(expected)
74
+ })
75
+
76
+ test.each([
77
+ ['hello_world', 'maintain', 'hello_world'],
78
+ ['myVariableName', 'maintain', 'myVariableName'],
79
+ ['HelloWorld', 'maintain', 'HelloWorld'],
80
+ ['any_string-here', 'maintain', 'any_string-here'],
81
+ ])('maintains original case: %s -> %s', (input, caseType, expected) => {
82
+ expect(convertCase(input, caseType as 'maintain')).toBe(expected)
83
+ })
84
+
85
+ test.each([
86
+ ['hello_world', undefined, 'helloWorld'],
87
+ ['my_variable_name', undefined, 'myVariableName'],
88
+ ['snake_case_string', undefined, 'snakeCaseString'],
89
+ ])('defaults to camelCase when caseType is undefined: %s -> %s', (input, caseType, expected) => {
90
+ // biome-ignore lint/suspicious/noExplicitAny: Testing default behavior with undefined caseType
91
+ expect(convertCase(input, caseType as any)).toBe(expected)
92
+ })
93
+
94
+ test.each([
95
+ ['hello_world', 'helloWorld'],
96
+ ['my_variable_name', 'myVariableName'],
97
+ ['snake_case_string', 'snakeCaseString'],
98
+ ])('defaults to camelCase when caseType is not provided: %s -> %s', (input, expected) => {
99
+ expect(convertCase(input)).toBe(expected)
100
+ })
101
+
102
+ test.each([
103
+ ['', 'camel', ''],
104
+ ['a', 'camel', 'a'],
105
+ ['A', 'camel', 'a'],
106
+ ])('handles empty string and single characters: %s -> %s', (input, caseType, expected) => {
107
+ expect(convertCase(input, caseType as 'camel')).toBe(expected)
108
+ })
109
+
110
+ test.each([
111
+ ['hello_world123', 'camel', 'helloWorld123'],
112
+ ['my_variable2_name', 'camel', 'myVariable2Name'],
113
+ ['test123_case', 'camel', 'test123Case'],
114
+ ])('handles strings with numbers: %s -> %s', (input, caseType, expected) => {
115
+ expect(convertCase(input, caseType as 'camel')).toBe(expected)
116
+ })
117
+
118
+ test.each([
119
+ ['hello_world', 'invalid', 'hello_world'],
120
+ ['myVariableName', 'unknown', 'myVariableName'],
121
+ ['HelloWorld', 'wrong', 'HelloWorld'],
122
+ ])('default case returns original string for invalid caseType: %s -> %s', (input, caseType, expected) => {
123
+ // biome-ignore lint/suspicious/noExplicitAny: Testing default case with invalid caseType values
124
+ expect(convertCase(input, caseType as any)).toBe(expected)
125
+ })