@effect/openapi-generator 4.0.0-beta.6 → 4.0.0-beta.60

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ParsedOperation.d.ts","sourceRoot":"","sources":["../src/ParsedOperation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAE5E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACzC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpD,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClD,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAEzC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAE3B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;CACjC;AAED,eAAO,MAAM,eAAe,GAAI,SAAS;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;CACzC,KAAG,KAAK,CAAC,WAAW,CAAC,eAAe,CAWnC,CAAA"}
1
+ {"version":3,"file":"ParsedOperation.d.ts","sourceRoot":"","sources":["../src/ParsedOperation.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,35 @@
1
1
  export const makeDeepMutable = options => ({
2
2
  ...options,
3
+ operationId: undefined,
4
+ path: "",
5
+ tags: [],
6
+ metadata: {
7
+ summary: undefined,
8
+ description: options.description,
9
+ deprecated: false,
10
+ externalDocs: undefined
11
+ },
12
+ parameters: {
13
+ path: [],
14
+ query: [],
15
+ header: [],
16
+ cookie: []
17
+ },
18
+ requestBody: undefined,
19
+ responses: [],
20
+ defaultResponse: undefined,
21
+ effectiveSecurity: [],
3
22
  urlParams: [],
4
23
  headers: [],
5
24
  cookies: [],
6
25
  payloadFormData: false,
26
+ payloadFormUrlEncoded: false,
27
+ pathSchema: undefined,
28
+ querySchema: undefined,
29
+ querySchemaOptional: true,
30
+ headersSchema: undefined,
31
+ headersSchemaOptional: true,
32
+ requestBodyRepresentable: [],
7
33
  successSchemas: new Map(),
8
34
  errorSchemas: new Map(),
9
35
  voidSchemas: new Set(),
@@ -1 +1 @@
1
- {"version":3,"file":"ParsedOperation.js","names":["makeDeepMutable","options","urlParams","headers","cookies","payloadFormData","successSchemas","Map","errorSchemas","voidSchemas","Set","paramsOptional","binaryResponse"],"sources":["../src/ParsedOperation.ts"],"sourcesContent":[null],"mappings":"AAyBA,OAAO,MAAMA,eAAe,GAAIC,OAM/B,KAA0C;EACzC,GAAGA,OAAO;EACVC,SAAS,EAAE,EAAE;EACbC,OAAO,EAAE,EAAE;EACXC,OAAO,EAAE,EAAE;EACXC,eAAe,EAAE,KAAK;EACtBC,cAAc,EAAE,IAAIC,GAAG,EAAE;EACzBC,YAAY,EAAE,IAAID,GAAG,EAAE;EACvBE,WAAW,EAAE,IAAIC,GAAG,EAAE;EACtBC,cAAc,EAAE,IAAI;EACpBC,cAAc,EAAE;CACjB,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"ParsedOperation.js","names":["makeDeepMutable","options","operationId","undefined","path","tags","metadata","summary","description","deprecated","externalDocs","parameters","query","header","cookie","requestBody","responses","defaultResponse","effectiveSecurity","urlParams","headers","cookies","payloadFormData","payloadFormUrlEncoded","pathSchema","querySchema","querySchemaOptional","headersSchema","headersSchemaOptional","requestBodyRepresentable","successSchemas","Map","errorSchemas","voidSchemas","Set","paramsOptional","binaryResponse"],"sources":["../src/ParsedOperation.ts"],"sourcesContent":[null],"mappings":"AA+HA,OAAO,MAAMA,eAAe,GAAIC,OAM/B,KAA0C;EACzC,GAAGA,OAAO;EACVC,WAAW,EAAEC,SAAS;EACtBC,IAAI,EAAE,EAAE;EACRC,IAAI,EAAE,EAAE;EACRC,QAAQ,EAAE;IACRC,OAAO,EAAEJ,SAAS;IAClBK,WAAW,EAAEP,OAAO,CAACO,WAAW;IAChCC,UAAU,EAAE,KAAK;IACjBC,YAAY,EAAEP;GACf;EACDQ,UAAU,EAAE;IACVP,IAAI,EAAE,EAAE;IACRQ,KAAK,EAAE,EAAE;IACTC,MAAM,EAAE,EAAE;IACVC,MAAM,EAAE;GACT;EACDC,WAAW,EAAEZ,SAAS;EACtBa,SAAS,EAAE,EAAE;EACbC,eAAe,EAAEd,SAAS;EAC1Be,iBAAiB,EAAE,EAAE;EACrBC,SAAS,EAAE,EAAE;EACbC,OAAO,EAAE,EAAE;EACXC,OAAO,EAAE,EAAE;EACXC,eAAe,EAAE,KAAK;EACtBC,qBAAqB,EAAE,KAAK;EAC5BC,UAAU,EAAErB,SAAS;EACrBsB,WAAW,EAAEtB,SAAS;EACtBuB,mBAAmB,EAAE,IAAI;EACzBC,aAAa,EAAExB,SAAS;EACxByB,qBAAqB,EAAE,IAAI;EAC3BC,wBAAwB,EAAE,EAAE;EAC5BC,cAAc,EAAE,IAAIC,GAAG,EAAE;EACzBC,YAAY,EAAE,IAAID,GAAG,EAAE;EACvBE,WAAW,EAAE,IAAIC,GAAG,EAAE;EACtBC,cAAc,EAAE,IAAI;EACpBC,cAAc,EAAE;CACjB,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,QAAQ,MAAM,8BAA8B,CAAA;AACxD,OAAO,KAAK,OAAO,MAAM,6BAA6B,CAAA;AA6DtD,eAAO,MAAM,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAE1E,CAAA"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,QAAQ,MAAM,8BAA8B,CAAA;AACxD,OAAO,KAAK,OAAO,MAAM,6BAA6B,CAAA;AA4EtD,eAAO,MAAM,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAE1E,CAAA"}
package/dist/main.js CHANGED
@@ -5,19 +5,19 @@ import * as Command from "effect/unstable/cli/Command";
5
5
  import * as Flag from "effect/unstable/cli/Flag";
6
6
  import * as OpenApiGenerator from "./OpenApiGenerator.js";
7
7
  import * as OpenApiPatch from "./OpenApiPatch.js";
8
- const spec = /*#__PURE__*/Flag.fileParse("spec").pipe(/*#__PURE__*/Flag.withAlias("s"), /*#__PURE__*/Flag.withDescription("The OpenAPI spec file to generate the client from"));
9
- const name = /*#__PURE__*/Flag.string("name").pipe(/*#__PURE__*/Flag.withAlias("n"), /*#__PURE__*/Flag.withDescription("The name of the generated client"), /*#__PURE__*/Flag.withDefault("Client"));
10
- const typeOnly = /*#__PURE__*/Flag.boolean("type-only").pipe(/*#__PURE__*/Flag.withAlias("t"), /*#__PURE__*/Flag.withDescription("Generate a type-only client without schemas"));
8
+ const spec = /*#__PURE__*/Flag.fileParse("spec").pipe(/*#__PURE__*/Flag.withAlias("s"), /*#__PURE__*/Flag.withDescription("The OpenAPI spec file to generate output from"));
9
+ const name = /*#__PURE__*/Flag.string("name").pipe(/*#__PURE__*/Flag.withAlias("n"), /*#__PURE__*/Flag.withDescription("The name of the generated output"), /*#__PURE__*/Flag.withDefault("Client"));
10
+ const format = /*#__PURE__*/Flag.choice("format", ["httpclient", "httpclient-type-only", "httpapi"]).pipe(/*#__PURE__*/Flag.withAlias("f"), /*#__PURE__*/Flag.withDescription("Output format to generate: httpclient | httpclient-type-only | httpapi (default: httpclient)"), /*#__PURE__*/Flag.withDefault("httpclient"));
11
11
  const patch = /*#__PURE__*/Flag.string("patch").pipe(/*#__PURE__*/Flag.withAlias("p"), /*#__PURE__*/Flag.withDescription("JSON patch to apply to OpenAPI spec before generation. " + "Can be a file path (.json, .yaml, .yml) or inline JSON array. " + "Multiple patches are applied in order."), /*#__PURE__*/Flag.between(0, Infinity));
12
12
  const root = /*#__PURE__*/Command.make("openapigen", {
13
13
  spec,
14
- typeOnly,
14
+ format,
15
15
  name,
16
16
  patch
17
17
  }).pipe(/*#__PURE__*/Command.withHandler(/*#__PURE__*/Effect.fnUntraced(function* ({
18
18
  name,
19
19
  spec,
20
- typeOnly,
20
+ format,
21
21
  patch
22
22
  }) {
23
23
  let patchedSpec = spec;
@@ -33,15 +33,26 @@ const root = /*#__PURE__*/Command.make("openapigen", {
33
33
  })));
34
34
  }
35
35
  const generator = yield* OpenApiGenerator.OpenApiGenerator;
36
+ const warnings = [];
36
37
  const source = yield* generator.generate(patchedSpec, {
37
38
  name,
38
- typeOnly
39
+ format,
40
+ onWarning: warning => {
41
+ warnings.push(warning);
42
+ }
43
+ });
44
+ yield* Effect.forEach(warnings, warning => Console.error(formatWarning(warning)), {
45
+ discard: true
39
46
  });
40
47
  return yield* Console.log(source);
41
48
  })), /*#__PURE__*/Command.provide(({
42
- typeOnly
43
- }) => typeOnly ? OpenApiGenerator.layerTransformerTs : OpenApiGenerator.layerTransformerSchema));
49
+ format
50
+ }) => format === "httpclient-type-only" ? OpenApiGenerator.layerTransformerTs : OpenApiGenerator.layerTransformerSchema));
44
51
  export const run = /*#__PURE__*/Command.run(root, {
45
52
  version: "0.0.0"
46
53
  });
54
+ const formatWarning = warning => {
55
+ const context = [warning.method?.toUpperCase(), warning.path, warning.operationId ? `(${warning.operationId})` : undefined].filter(value => value !== undefined);
56
+ return context.length > 0 ? `WARNING [${warning.code}] ${context.join(" ")}: ${warning.message}` : `WARNING [${warning.code}] ${warning.message}`;
57
+ };
47
58
  //# sourceMappingURL=main.js.map
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":["Console","Effect","CliError","Command","Flag","OpenApiGenerator","OpenApiPatch","spec","fileParse","pipe","withAlias","withDescription","name","string","withDefault","typeOnly","boolean","patch","between","Infinity","root","make","withHandler","fnUntraced","patchedSpec","length","parsedPatches","forEach","input","parsePatchInput","map","p","source","mapError","error","UserError","cause","applyPatches","generator","generate","log","provide","layerTransformerTs","layerTransformerSchema","run","version"],"sources":["../src/main.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"main.js","names":["Console","Effect","CliError","Command","Flag","OpenApiGenerator","OpenApiPatch","spec","fileParse","pipe","withAlias","withDescription","name","string","withDefault","format","choice","patch","between","Infinity","root","make","withHandler","fnUntraced","patchedSpec","length","parsedPatches","forEach","input","parsePatchInput","map","p","source","mapError","error","UserError","cause","applyPatches","generator","warnings","generate","onWarning","warning","push","formatWarning","discard","log","provide","layerTransformerTs","layerTransformerSchema","run","version","context","method","toUpperCase","path","operationId","undefined","filter","value","code","join","message"],"sources":["../src/main.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@effect/openapi-generator",
3
3
  "type": "module",
4
- "version": "4.0.0-beta.6",
4
+ "version": "4.0.0-beta.60",
5
5
  "license": "MIT",
6
- "description": "Generate Effect Schema types and HTTP clients from OpenAPI specifications",
6
+ "description": "Generate Effect Schema types, HTTP clients, and HttpApi modules from OpenAPI specifications",
7
7
  "homepage": "https://effect.website",
8
8
  "repository": {
9
9
  "type": "git",
@@ -45,16 +45,16 @@
45
45
  "provenance": true
46
46
  },
47
47
  "peerDependencies": {
48
- "@effect/platform-node": "^4.0.0-beta.6",
49
- "effect": "^4.0.0-beta.6"
48
+ "@effect/platform-node": "^4.0.0-beta.60",
49
+ "effect": "^4.0.0-beta.60"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/swagger2openapi": "^7.0.4",
53
53
  "json-schema-typed": "^8.0.2",
54
- "openapi-typescript": "^7.10.1",
54
+ "openapi-typescript": "^7.13.0",
55
55
  "swagger2openapi": "^7.0.8",
56
- "yaml": "^2.8.2",
57
- "effect": "^4.0.0-beta.6"
56
+ "yaml": "^2.8.3",
57
+ "effect": "^4.0.0-beta.60"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsc -b tsconfig.json && pnpm babel",
@@ -0,0 +1,497 @@
1
+ import type {
2
+ ParsedOpenApi,
3
+ ParsedOpenApiSecurityScheme,
4
+ ParsedOpenApiTag,
5
+ ParsedOperation,
6
+ ParsedOperationMediaTypeSchema,
7
+ ParsedOperationResponse
8
+ } from "./ParsedOperation.ts"
9
+ import * as Utils from "./Utils.ts"
10
+
11
+ interface GroupRenderModel {
12
+ readonly identifier: string
13
+ readonly topLevel: boolean
14
+ readonly metadata: ParsedOpenApiTag | undefined
15
+ readonly operations: ReadonlyArray<ParsedOperation>
16
+ readonly constName: string
17
+ }
18
+
19
+ interface SecurityRenderModel {
20
+ readonly securityDeclarations: ReadonlyArray<string>
21
+ readonly middlewareDeclarations: ReadonlyArray<string>
22
+ readonly endpointMiddlewares: ReadonlyMap<string, ReadonlyArray<string>>
23
+ }
24
+
25
+ const fallbackGroupIdentifier = "default"
26
+
27
+ export const imports = (
28
+ importName: string,
29
+ options?: {
30
+ readonly multipart?: boolean | undefined
31
+ }
32
+ ): string =>
33
+ [
34
+ `import * as ${importName} from "effect/Schema"`,
35
+ ...(options?.multipart === true ? [`import { Multipart } from "effect/unstable/http"`] : []),
36
+ `import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, HttpApiSecurity, OpenApi } from "effect/unstable/httpapi"`
37
+ ].join("\n")
38
+
39
+ export const toImplementation = (
40
+ _importName: string,
41
+ name: string,
42
+ parsed: ParsedOpenApi
43
+ ): string => {
44
+ const security = buildSecurityRenderModel(parsed)
45
+ const groups = groupOperations(parsed)
46
+ const groupSources = groups.map((group) => renderGroup(group, security.endpointMiddlewares))
47
+ const metadataAnnotations = renderApiAnnotations(parsed)
48
+
49
+ let apiValue = `export class ${name} extends HttpApi.make(${JSON.stringify(name)})`
50
+ for (const annotation of metadataAnnotations) {
51
+ apiValue += `\n .${annotation}`
52
+ }
53
+ if (groups.length > 0) {
54
+ apiValue += `\n .add(${groups.map((group) => group.constName).join(", ")})`
55
+ }
56
+ apiValue += ` {}`
57
+
58
+ return [
59
+ ...security.securityDeclarations,
60
+ ...security.middlewareDeclarations,
61
+ ...groupSources,
62
+ apiValue
63
+ ].join("\n\n")
64
+ }
65
+
66
+ const groupOperations = (parsed: ParsedOpenApi): ReadonlyArray<GroupRenderModel> => {
67
+ const tagMetadata = new Map(parsed.tags.map((tag) => [tag.name, tag]))
68
+ const byIdentifier = new Map<string, {
69
+ readonly identifier: string
70
+ topLevel: boolean
71
+ readonly metadata: ParsedOpenApiTag | undefined
72
+ readonly operations: Array<ParsedOperation>
73
+ }>()
74
+
75
+ for (const operation of parsed.operations) {
76
+ const identifier = operation.tags[0] ?? fallbackGroupIdentifier
77
+ const topLevel = operation.tags.length === 0
78
+ const existing = byIdentifier.get(identifier)
79
+ if (existing) {
80
+ if (topLevel) {
81
+ existing.topLevel = true
82
+ }
83
+ existing.operations.push(operation)
84
+ continue
85
+ }
86
+ byIdentifier.set(identifier, {
87
+ identifier,
88
+ topLevel,
89
+ metadata: tagMetadata.get(identifier),
90
+ operations: [operation]
91
+ })
92
+ }
93
+
94
+ const allocateName = makeNameAllocator()
95
+ const groups: Array<GroupRenderModel> = []
96
+ for (const group of byIdentifier.values()) {
97
+ const baseName = ensureIdentifier(group.identifier, "Group")
98
+ groups.push({
99
+ ...group,
100
+ constName: allocateName(`${baseName}Group`)
101
+ })
102
+ }
103
+ return groups
104
+ }
105
+
106
+ const renderGroup = (
107
+ group: GroupRenderModel,
108
+ endpointMiddlewares: ReadonlyMap<string, ReadonlyArray<string>>
109
+ ): string => {
110
+ let source = `class ${group.constName} extends HttpApiGroup.make(${JSON.stringify(group.identifier)}${
111
+ group.topLevel ? ", { topLevel: true }" : ""
112
+ })`
113
+
114
+ const allocateEndpointName = makeNameAllocator()
115
+ const endpointSources = group.operations.map((operation) =>
116
+ renderEndpoint(
117
+ operation,
118
+ allocateEndpointName(operation.id),
119
+ endpointMiddlewares.get(toOperationKey(operation)) ?? []
120
+ )
121
+ )
122
+ if (endpointSources.length > 0) {
123
+ source += `\n .add(${endpointSources.join(", \n ")})`
124
+ }
125
+
126
+ if (group.metadata?.description !== undefined) {
127
+ source += `\n .annotate(OpenApi.Description, ${JSON.stringify(group.metadata.description)})`
128
+ }
129
+ if (group.metadata?.externalDocs !== undefined) {
130
+ source += `\n .annotate(OpenApi.ExternalDocs, ${JSON.stringify(group.metadata.externalDocs)})`
131
+ }
132
+
133
+ source += ` {}`
134
+
135
+ return source
136
+ }
137
+
138
+ const renderEndpoint = (
139
+ operation: ParsedOperation,
140
+ endpointName: string,
141
+ endpointMiddlewares: ReadonlyArray<string>
142
+ ): string => {
143
+ const options: Array<string> = []
144
+ if (operation.pathSchema !== undefined) {
145
+ options.push(`params: ${operation.pathSchema}`)
146
+ }
147
+ if (operation.querySchema !== undefined) {
148
+ options.push(`query: ${operation.querySchema}`)
149
+ }
150
+ if (operation.headersSchema !== undefined) {
151
+ options.push(`headers: ${operation.headersSchema}`)
152
+ }
153
+
154
+ const payload = renderPayload(operation)
155
+ if (payload !== undefined) {
156
+ options.push(`payload: ${payload}`)
157
+ }
158
+
159
+ const success = renderResponseSet(operation.responses, "success")
160
+ if (success !== undefined) {
161
+ options.push(`success: ${success}`)
162
+ }
163
+
164
+ const error = renderResponseSet(operation.responses, "error")
165
+ if (error !== undefined) {
166
+ options.push(`error: ${error}`)
167
+ }
168
+
169
+ const endpoint = options.length === 0
170
+ ? `HttpApiEndpoint.${operation.method}(${JSON.stringify(endpointName)}, ${
171
+ JSON.stringify(toHttpApiPath(operation.path))
172
+ })`
173
+ : `HttpApiEndpoint.${operation.method}(${JSON.stringify(endpointName)}, ${
174
+ JSON.stringify(toHttpApiPath(operation.path))
175
+ }, { ${options.join(", ")} })`
176
+
177
+ const annotations: Array<string> = []
178
+ if (operation.operationId !== undefined) {
179
+ annotations.push(`annotate(OpenApi.Identifier, ${JSON.stringify(operation.operationId)})`)
180
+ }
181
+ if (operation.metadata.summary !== undefined) {
182
+ annotations.push(`annotate(OpenApi.Summary, ${JSON.stringify(operation.metadata.summary)})`)
183
+ }
184
+ if (operation.metadata.description !== undefined) {
185
+ annotations.push(`annotate(OpenApi.Description, ${JSON.stringify(operation.metadata.description)})`)
186
+ }
187
+ if (operation.metadata.deprecated) {
188
+ annotations.push(`annotate(OpenApi.Deprecated, true)`)
189
+ }
190
+ if (operation.metadata.externalDocs !== undefined) {
191
+ annotations.push(`annotate(OpenApi.ExternalDocs, ${JSON.stringify(operation.metadata.externalDocs)})`)
192
+ }
193
+
194
+ if (annotations.length === 0 && endpointMiddlewares.length === 0) {
195
+ return endpoint
196
+ }
197
+
198
+ let out = endpoint
199
+ for (const middleware of endpointMiddlewares) {
200
+ out += `\n .middleware(${middleware})`
201
+ }
202
+ for (const annotation of annotations) {
203
+ out += `\n .${annotation}`
204
+ }
205
+ return out
206
+ }
207
+
208
+ const renderPayload = (operation: ParsedOperation): string | undefined => {
209
+ if (!methodSupportsBody(operation.method)) {
210
+ return
211
+ }
212
+ const payloads = operation.requestBodyRepresentable.map((schema) => renderMediaSchema(schema))
213
+ if (payloads.length === 0) {
214
+ return
215
+ }
216
+
217
+ if (operation.requestBody?.required === false) {
218
+ payloads.unshift("HttpApiSchema.NoContent")
219
+ }
220
+
221
+ return joinSchemas(payloads)
222
+ }
223
+
224
+ const renderResponseSet = (
225
+ responses: ReadonlyArray<ParsedOperationResponse>,
226
+ target: "success" | "error"
227
+ ): string | undefined => {
228
+ const rendered: Array<string> = []
229
+
230
+ for (const response of responses) {
231
+ const status = toStatus(response.status)
232
+ if (status === undefined) {
233
+ continue
234
+ }
235
+
236
+ const isSuccess = status < 400
237
+ if ((target === "success") !== isSuccess) {
238
+ continue
239
+ }
240
+
241
+ if (response.isEmpty) {
242
+ rendered.push(`HttpApiSchema.Empty(${status})`)
243
+ continue
244
+ }
245
+
246
+ for (const media of response.representable) {
247
+ rendered.push(applyStatus(renderMediaSchema(media), status, target))
248
+ }
249
+ }
250
+
251
+ if (rendered.length === 0) {
252
+ return
253
+ }
254
+
255
+ return joinSchemas(rendered)
256
+ }
257
+
258
+ const joinSchemas = (schemas: ReadonlyArray<string>): string =>
259
+ schemas.length === 1 ? schemas[0] : `[${schemas.join(", ")}]`
260
+
261
+ const renderMediaSchema = (media: ParsedOperationMediaTypeSchema): string => {
262
+ switch (media.encoding) {
263
+ case "json": {
264
+ if (media.contentType === "application/json") {
265
+ return media.schema
266
+ }
267
+ return `${media.schema}.pipe(HttpApiSchema.asJson({ contentType: ${JSON.stringify(media.contentType)} }))`
268
+ }
269
+ case "multipart": {
270
+ return `${media.schema}.pipe(HttpApiSchema.asMultipart())`
271
+ }
272
+ case "form-url-encoded": {
273
+ if (media.contentType === "application/x-www-form-urlencoded") {
274
+ return `${media.schema}.pipe(HttpApiSchema.asFormUrlEncoded())`
275
+ }
276
+ return `${media.schema}.pipe(HttpApiSchema.asFormUrlEncoded({ contentType: ${
277
+ JSON.stringify(media.contentType)
278
+ } }))`
279
+ }
280
+ case "text": {
281
+ if (media.contentType === "text/plain") {
282
+ return `${media.schema}.pipe(HttpApiSchema.asText())`
283
+ }
284
+ return `${media.schema}.pipe(HttpApiSchema.asText({ contentType: ${JSON.stringify(media.contentType)} }))`
285
+ }
286
+ case "binary": {
287
+ if (media.contentType === "application/octet-stream") {
288
+ return `${media.schema}.pipe(HttpApiSchema.asUint8Array())`
289
+ }
290
+ return `${media.schema}.pipe(HttpApiSchema.asUint8Array({ contentType: ${JSON.stringify(media.contentType)} }))`
291
+ }
292
+ }
293
+ }
294
+
295
+ const renderApiAnnotations = (parsed: ParsedOpenApi): ReadonlyArray<string> => {
296
+ const annotations: Array<string> = [
297
+ `annotate(OpenApi.Title, ${JSON.stringify(parsed.metadata.title)})`,
298
+ `annotate(OpenApi.Version, ${JSON.stringify(parsed.metadata.version)})`
299
+ ]
300
+
301
+ if (parsed.metadata.summary !== undefined) {
302
+ annotations.push(`annotate(OpenApi.Summary, ${JSON.stringify(parsed.metadata.summary)})`)
303
+ }
304
+ if (parsed.metadata.description !== undefined) {
305
+ annotations.push(`annotate(OpenApi.Description, ${JSON.stringify(parsed.metadata.description)})`)
306
+ }
307
+ if (parsed.metadata.license !== undefined) {
308
+ annotations.push(`annotate(OpenApi.License, ${JSON.stringify(parsed.metadata.license)})`)
309
+ }
310
+ if (parsed.metadata.servers !== undefined) {
311
+ annotations.push(`annotate(OpenApi.Servers, ${JSON.stringify(parsed.metadata.servers)})`)
312
+ }
313
+
314
+ return annotations
315
+ }
316
+
317
+ const buildSecurityRenderModel = (parsed: ParsedOpenApi): SecurityRenderModel => {
318
+ const allocateName = makeNameAllocator()
319
+ const securityDeclarations: Array<string> = []
320
+ const middlewareDeclarations: Array<string> = []
321
+ const endpointMiddlewares = new Map<string, ReadonlyArray<string>>()
322
+ const schemeDeclarations = new Map<string, string>()
323
+ const middlewareNames = new Map<string, string>()
324
+
325
+ for (const securityScheme of parsed.securitySchemes) {
326
+ const baseName = ensureIdentifier(securityScheme.name, "Security")
327
+ const declarationName = allocateName(`${baseName}Security`)
328
+ schemeDeclarations.set(securityScheme.name, declarationName)
329
+ securityDeclarations.push(`export const ${declarationName} = ${renderSecurityScheme(securityScheme)}`)
330
+ }
331
+
332
+ for (const operation of parsed.operations) {
333
+ if (operation.effectiveSecurity.length === 0) {
334
+ continue
335
+ }
336
+ if (operation.effectiveSecurity.some((requirement) => Object.keys(requirement).length === 0)) {
337
+ continue
338
+ }
339
+
340
+ const operationMiddlewareNames: Array<string> = []
341
+ const seenOrSchemes = new Set<string>()
342
+ const andRequirements: Array<ReadonlyArray<string>> = []
343
+
344
+ for (const requirement of operation.effectiveSecurity) {
345
+ const schemes = Object.keys(requirement)
346
+ if (schemes.length === 1) {
347
+ const schemeName = schemes[0]
348
+ if (schemeDeclarations.has(schemeName) && !seenOrSchemes.has(schemeName)) {
349
+ seenOrSchemes.add(schemeName)
350
+ }
351
+ } else if (schemes.length > 1) {
352
+ andRequirements.push([...schemes].sort())
353
+ }
354
+ }
355
+
356
+ const orSchemeNames = Array.from(seenOrSchemes).sort()
357
+ if (orSchemeNames.length > 0) {
358
+ const className = getOrSecurityMiddlewareName(orSchemeNames)
359
+ operationMiddlewareNames.push(className)
360
+ }
361
+
362
+ const seenAndRequirements = new Set<string>()
363
+ for (const requirement of andRequirements) {
364
+ const key = requirement.join("\u0000")
365
+ if (seenAndRequirements.has(key)) {
366
+ continue
367
+ }
368
+ seenAndRequirements.add(key)
369
+ const className = getAndSecurityMiddlewareName(requirement)
370
+ operationMiddlewareNames.push(className)
371
+ }
372
+
373
+ if (operationMiddlewareNames.length > 0) {
374
+ endpointMiddlewares.set(toOperationKey(operation), operationMiddlewareNames)
375
+ }
376
+ }
377
+
378
+ return {
379
+ securityDeclarations,
380
+ middlewareDeclarations,
381
+ endpointMiddlewares
382
+ }
383
+
384
+ function getOrSecurityMiddlewareName(schemes: ReadonlyArray<string>): string {
385
+ const key = `or:${schemes.join("\u0000")}`
386
+ const existing = middlewareNames.get(key)
387
+ if (existing !== undefined) {
388
+ return existing
389
+ }
390
+
391
+ const className = allocateName(`${getSecurityMiddlewareBaseName(schemes, "Or")}SecurityMiddleware`)
392
+ const securityEntries = schemes.map((name) => `${JSON.stringify(name)}: ${schemeDeclarations.get(name)!}`).join(
393
+ ", "
394
+ )
395
+ middlewareDeclarations.push(
396
+ `export class ${className} extends HttpApiMiddleware.Service<${className}>()(${
397
+ JSON.stringify(`${schemes.join(" | ")} security`)
398
+ }, { security: { ${securityEntries} } }) {}`
399
+ )
400
+ middlewareNames.set(key, className)
401
+ return className
402
+ }
403
+
404
+ function getAndSecurityMiddlewareName(schemes: ReadonlyArray<string>): string {
405
+ const key = `and:${schemes.join("\u0000")}`
406
+ const existing = middlewareNames.get(key)
407
+ if (existing !== undefined) {
408
+ return existing
409
+ }
410
+
411
+ const className = allocateName(`${getSecurityMiddlewareBaseName(schemes, "And")}SecurityMiddleware`)
412
+ middlewareDeclarations.push(
413
+ `class ${className} extends HttpApiMiddleware.Service<${className}>()(${
414
+ JSON.stringify(`${schemes.join(" & ")} security`)
415
+ }) {}`
416
+ )
417
+ middlewareNames.set(key, className)
418
+ return className
419
+ }
420
+ }
421
+
422
+ const getSecurityMiddlewareBaseName = (
423
+ schemes: ReadonlyArray<string>,
424
+ joiner: "And" | "Or"
425
+ ): string => {
426
+ const [head, ...tail] = schemes.map((scheme) => ensureIdentifier(scheme, "Security"))
427
+ return tail.length === 0 ? head : [head, ...tail.map((scheme) => `${joiner}${scheme}`)].join("")
428
+ }
429
+
430
+ const renderSecurityScheme = (securityScheme: ParsedOpenApiSecurityScheme): string => {
431
+ let source: string
432
+ switch (securityScheme.type) {
433
+ case "basic": {
434
+ source = "HttpApiSecurity.basic"
435
+ break
436
+ }
437
+ case "bearer": {
438
+ source = "HttpApiSecurity.bearer"
439
+ break
440
+ }
441
+ case "apiKey": {
442
+ source = `HttpApiSecurity.apiKey({ key: ${JSON.stringify(securityScheme.key!)}, in: ${
443
+ JSON.stringify(securityScheme.in!)
444
+ } })`
445
+ break
446
+ }
447
+ }
448
+
449
+ if (securityScheme.description !== undefined) {
450
+ source += `.pipe(HttpApiSecurity.annotate(OpenApi.Description, ${JSON.stringify(securityScheme.description)}))`
451
+ }
452
+ if (securityScheme.type === "bearer" && securityScheme.bearerFormat !== undefined) {
453
+ source += `.pipe(HttpApiSecurity.annotate(OpenApi.Format, ${JSON.stringify(securityScheme.bearerFormat)}))`
454
+ }
455
+
456
+ return source
457
+ }
458
+
459
+ const toOperationKey = (operation: ParsedOperation): string => `${operation.method}:${operation.path}`
460
+
461
+ const toHttpApiPath = (path: string): string => path.replace(/{([^}]+)}/g, ":$1")
462
+
463
+ const toStatus = (status: string): number | undefined => {
464
+ if (!/^\d{3}$/.test(status)) {
465
+ return
466
+ }
467
+ return Number(status)
468
+ }
469
+
470
+ const applyStatus = (schema: string, status: number, target: "success" | "error"): string => {
471
+ if ((target === "success" && status === 200) || (target === "error" && status === 500)) {
472
+ return schema
473
+ }
474
+ return `${schema}.pipe(HttpApiSchema.status(${status}))`
475
+ }
476
+
477
+ const methodSupportsBody = (method: ParsedOperation["method"]): boolean =>
478
+ method !== "get" && method !== "head" && method !== "options" && method !== "trace"
479
+
480
+ const ensureIdentifier = (value: string, fallback: string): string => {
481
+ const sanitized = Utils.identifier(value)
482
+ return sanitized.length > 0 ? sanitized : fallback
483
+ }
484
+
485
+ const makeNameAllocator = () => {
486
+ const used = new Set<string>()
487
+ return (base: string) => {
488
+ let candidate = base
489
+ let index = 2
490
+ while (used.has(candidate)) {
491
+ candidate = `${base}${index}`
492
+ index += 1
493
+ }
494
+ used.add(candidate)
495
+ return candidate
496
+ }
497
+ }