@effect/openapi-generator 4.0.0-beta.40 → 4.0.0-beta.42
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/dist/HttpApiTransformer.d.ts +6 -0
- package/dist/HttpApiTransformer.d.ts.map +1 -0
- package/dist/HttpApiTransformer.js +354 -0
- package/dist/HttpApiTransformer.js.map +1 -0
- package/dist/JsonSchemaGenerator.d.ts +13 -3
- package/dist/JsonSchemaGenerator.d.ts.map +1 -1
- package/dist/JsonSchemaGenerator.js +146 -47
- package/dist/JsonSchemaGenerator.js.map +1 -1
- package/dist/OpenApiGenerator.d.ts +17 -5
- package/dist/OpenApiGenerator.d.ts.map +1 -1
- package/dist/OpenApiGenerator.js +650 -117
- package/dist/OpenApiGenerator.js.map +1 -1
- package/dist/OpenApiTransformer.d.ts +10 -10
- package/dist/OpenApiTransformer.d.ts.map +1 -1
- package/dist/OpenApiTransformer.js +8 -6
- package/dist/OpenApiTransformer.js.map +1 -1
- package/dist/ParsedOperation.d.ts +80 -1
- package/dist/ParsedOperation.d.ts.map +1 -1
- package/dist/ParsedOperation.js +25 -0
- package/dist/ParsedOperation.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +19 -8
- package/dist/main.js.map +1 -1
- package/package.json +5 -5
- package/src/HttpApiTransformer.ts +497 -0
- package/src/JsonSchemaGenerator.ts +240 -47
- package/src/OpenApiGenerator.ts +907 -171
- package/src/OpenApiTransformer.ts +12 -10
- package/src/ParsedOperation.ts +127 -1
- package/src/main.ts +36 -10
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as Layer from "effect/Layer"
|
|
2
2
|
import * as Predicate from "effect/Predicate"
|
|
3
3
|
import * as ServiceMap from "effect/ServiceMap"
|
|
4
|
-
import type { ParsedOperation } from "./ParsedOperation.ts"
|
|
4
|
+
import type { ParsedOpenApi, ParsedOperation } from "./ParsedOperation.ts"
|
|
5
5
|
import * as Utils from "./Utils.ts"
|
|
6
6
|
|
|
7
7
|
export class OpenApiTransformer extends ServiceMap.Service<
|
|
8
8
|
OpenApiTransformer,
|
|
9
9
|
{
|
|
10
|
-
readonly imports: (importName: string,
|
|
11
|
-
readonly toTypes: (importName: string, name: string,
|
|
12
|
-
readonly toImplementation: (importName: string, name: string,
|
|
10
|
+
readonly imports: (importName: string, parsed: ParsedOpenApi) => string
|
|
11
|
+
readonly toTypes: (importName: string, name: string, parsed: ParsedOpenApi) => string
|
|
12
|
+
readonly toImplementation: (importName: string, name: string, parsed: ParsedOpenApi) => string
|
|
13
13
|
}
|
|
14
14
|
>()("OpenApiTransformer") {}
|
|
15
15
|
|
|
@@ -382,7 +382,8 @@ export const make = (
|
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
return OpenApiTransformer.of({
|
|
385
|
-
imports: (importName,
|
|
385
|
+
imports: (importName, parsed) => {
|
|
386
|
+
const operations = parsed.operations
|
|
386
387
|
const requirements = computeImportRequirements(operations)
|
|
387
388
|
const imports = [
|
|
388
389
|
`import * as Data from "effect/Data"`,
|
|
@@ -409,8 +410,8 @@ export const make = (
|
|
|
409
410
|
)
|
|
410
411
|
return imports.join("\n")
|
|
411
412
|
},
|
|
412
|
-
toTypes: operationsToInterface,
|
|
413
|
-
toImplementation: operationsToImpl
|
|
413
|
+
toTypes: (importName, name, parsed) => operationsToInterface(importName, name, parsed.operations),
|
|
414
|
+
toImplementation: (importName, name, parsed) => operationsToImpl(importName, name, parsed.operations)
|
|
414
415
|
})
|
|
415
416
|
}
|
|
416
417
|
|
|
@@ -777,7 +778,8 @@ export const make = (
|
|
|
777
778
|
}
|
|
778
779
|
|
|
779
780
|
return OpenApiTransformer.of({
|
|
780
|
-
imports: (_importName,
|
|
781
|
+
imports: (_importName, parsed) => {
|
|
782
|
+
const operations = parsed.operations
|
|
781
783
|
const requirements = computeImportRequirements(operations)
|
|
782
784
|
const imports = [
|
|
783
785
|
`import * as Data from "effect/Data"`,
|
|
@@ -794,8 +796,8 @@ export const make = (
|
|
|
794
796
|
)
|
|
795
797
|
return imports.join("\n")
|
|
796
798
|
},
|
|
797
|
-
toTypes: operationsToInterface,
|
|
798
|
-
toImplementation: operationsToImpl
|
|
799
|
+
toTypes: (importName, name, parsed) => operationsToInterface(importName, name, parsed.operations),
|
|
800
|
+
toImplementation: (importName, name, parsed) => operationsToImpl(importName, name, parsed.operations)
|
|
799
801
|
})
|
|
800
802
|
}
|
|
801
803
|
|
package/src/ParsedOperation.ts
CHANGED
|
@@ -1,9 +1,104 @@
|
|
|
1
1
|
import type * as Types from "effect/Types"
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
OpenAPISecurityRequirement,
|
|
4
|
+
OpenAPISpecExternalDocs,
|
|
5
|
+
OpenAPISpecLicense,
|
|
6
|
+
OpenAPISpecMethodName,
|
|
7
|
+
OpenAPISpecServer
|
|
8
|
+
} from "effect/unstable/httpapi/OpenApi"
|
|
9
|
+
|
|
10
|
+
export interface ParsedOpenApiMetadata {
|
|
11
|
+
readonly title: string
|
|
12
|
+
readonly version: string
|
|
13
|
+
readonly summary: string | undefined
|
|
14
|
+
readonly description: string | undefined
|
|
15
|
+
readonly license: OpenAPISpecLicense | undefined
|
|
16
|
+
readonly servers: ReadonlyArray<OpenAPISpecServer> | undefined
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ParsedOpenApiTag {
|
|
20
|
+
readonly name: string
|
|
21
|
+
readonly description: string | undefined
|
|
22
|
+
readonly externalDocs: OpenAPISpecExternalDocs | undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ParsedOpenApiSecurityScheme {
|
|
26
|
+
readonly name: string
|
|
27
|
+
readonly type: "basic" | "bearer" | "apiKey"
|
|
28
|
+
readonly description: string | undefined
|
|
29
|
+
readonly bearerFormat: string | undefined
|
|
30
|
+
readonly key: string | undefined
|
|
31
|
+
readonly in: "header" | "query" | "cookie" | undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ParsedOpenApi {
|
|
35
|
+
readonly metadata: ParsedOpenApiMetadata
|
|
36
|
+
readonly tags: ReadonlyArray<ParsedOpenApiTag>
|
|
37
|
+
readonly securitySchemes: ReadonlyArray<ParsedOpenApiSecurityScheme>
|
|
38
|
+
readonly operations: ReadonlyArray<ParsedOperation>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ParsedOperationMetadata {
|
|
42
|
+
readonly summary: string | undefined
|
|
43
|
+
readonly description: string | undefined
|
|
44
|
+
readonly deprecated: boolean
|
|
45
|
+
readonly externalDocs: OpenAPISpecExternalDocs | undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ParsedOperationParameter {
|
|
49
|
+
readonly name: string
|
|
50
|
+
readonly in: "path" | "query" | "header" | "cookie"
|
|
51
|
+
readonly required: boolean
|
|
52
|
+
readonly description: string | undefined
|
|
53
|
+
readonly schema: {}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ParsedOperationRequestBody {
|
|
57
|
+
readonly required: boolean
|
|
58
|
+
readonly contentTypes: Array<string>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type ParsedOperationMediaTypeEncoding =
|
|
62
|
+
| "json"
|
|
63
|
+
| "multipart"
|
|
64
|
+
| "form-url-encoded"
|
|
65
|
+
| "text"
|
|
66
|
+
| "binary"
|
|
67
|
+
|
|
68
|
+
export interface ParsedOperationMediaTypeSchema {
|
|
69
|
+
readonly contentType: string
|
|
70
|
+
readonly encoding: ParsedOperationMediaTypeEncoding
|
|
71
|
+
readonly schema: string
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface ParsedOperationResponse {
|
|
75
|
+
readonly status: string
|
|
76
|
+
readonly description: string | undefined
|
|
77
|
+
readonly contentTypes: Array<string>
|
|
78
|
+
readonly hasHeaders: boolean
|
|
79
|
+
readonly isEmpty: boolean
|
|
80
|
+
readonly representable: ReadonlyArray<ParsedOperationMediaTypeSchema>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type ParsedOperationSecurityRequirement = Readonly<OpenAPISecurityRequirement>
|
|
3
84
|
|
|
4
85
|
export interface ParsedOperation {
|
|
5
86
|
readonly id: string
|
|
87
|
+
readonly operationId: string | undefined
|
|
88
|
+
readonly path: string
|
|
6
89
|
readonly method: OpenAPISpecMethodName
|
|
90
|
+
readonly tags: ReadonlyArray<string>
|
|
91
|
+
readonly metadata: ParsedOperationMetadata
|
|
92
|
+
readonly parameters: {
|
|
93
|
+
readonly path: ReadonlyArray<ParsedOperationParameter>
|
|
94
|
+
readonly query: ReadonlyArray<ParsedOperationParameter>
|
|
95
|
+
readonly header: ReadonlyArray<ParsedOperationParameter>
|
|
96
|
+
readonly cookie: ReadonlyArray<ParsedOperationParameter>
|
|
97
|
+
}
|
|
98
|
+
readonly requestBody: ParsedOperationRequestBody | undefined
|
|
99
|
+
readonly responses: ReadonlyArray<ParsedOperationResponse>
|
|
100
|
+
readonly defaultResponse: ParsedOperationResponse | undefined
|
|
101
|
+
readonly effectiveSecurity: ReadonlyArray<ParsedOperationSecurityRequirement>
|
|
7
102
|
readonly description: string | undefined
|
|
8
103
|
readonly params?: string
|
|
9
104
|
readonly paramsOptional: boolean
|
|
@@ -12,6 +107,12 @@ export interface ParsedOperation {
|
|
|
12
107
|
readonly cookies: ReadonlyArray<string>
|
|
13
108
|
readonly payload?: string
|
|
14
109
|
readonly payloadFormData: boolean
|
|
110
|
+
readonly pathSchema: string | undefined
|
|
111
|
+
readonly querySchema: string | undefined
|
|
112
|
+
readonly querySchemaOptional: boolean
|
|
113
|
+
readonly headersSchema: string | undefined
|
|
114
|
+
readonly headersSchemaOptional: boolean
|
|
115
|
+
readonly requestBodyRepresentable: ReadonlyArray<ParsedOperationMediaTypeSchema>
|
|
15
116
|
readonly pathIds: ReadonlyArray<string>
|
|
16
117
|
readonly pathTemplate: string
|
|
17
118
|
readonly successSchemas: ReadonlyMap<string, string>
|
|
@@ -31,10 +132,35 @@ export const makeDeepMutable = (options: {
|
|
|
31
132
|
readonly description: string | undefined
|
|
32
133
|
}): Types.DeepMutable<ParsedOperation> => ({
|
|
33
134
|
...options,
|
|
135
|
+
operationId: undefined,
|
|
136
|
+
path: "",
|
|
137
|
+
tags: [],
|
|
138
|
+
metadata: {
|
|
139
|
+
summary: undefined,
|
|
140
|
+
description: options.description,
|
|
141
|
+
deprecated: false,
|
|
142
|
+
externalDocs: undefined
|
|
143
|
+
},
|
|
144
|
+
parameters: {
|
|
145
|
+
path: [],
|
|
146
|
+
query: [],
|
|
147
|
+
header: [],
|
|
148
|
+
cookie: []
|
|
149
|
+
},
|
|
150
|
+
requestBody: undefined,
|
|
151
|
+
responses: [],
|
|
152
|
+
defaultResponse: undefined,
|
|
153
|
+
effectiveSecurity: [],
|
|
34
154
|
urlParams: [],
|
|
35
155
|
headers: [],
|
|
36
156
|
cookies: [],
|
|
37
157
|
payloadFormData: false,
|
|
158
|
+
pathSchema: undefined,
|
|
159
|
+
querySchema: undefined,
|
|
160
|
+
querySchemaOptional: true,
|
|
161
|
+
headersSchema: undefined,
|
|
162
|
+
headersSchemaOptional: true,
|
|
163
|
+
requestBodyRepresentable: [],
|
|
38
164
|
successSchemas: new Map(),
|
|
39
165
|
errorSchemas: new Map(),
|
|
40
166
|
voidSchemas: new Set(),
|
package/src/main.ts
CHANGED
|
@@ -10,18 +10,21 @@ import * as OpenApiPatch from "./OpenApiPatch.ts"
|
|
|
10
10
|
|
|
11
11
|
const spec = Flag.fileParse("spec").pipe(
|
|
12
12
|
Flag.withAlias("s"),
|
|
13
|
-
Flag.withDescription("The OpenAPI spec file to generate
|
|
13
|
+
Flag.withDescription("The OpenAPI spec file to generate output from")
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
const name = Flag.string("name").pipe(
|
|
17
17
|
Flag.withAlias("n"),
|
|
18
|
-
Flag.withDescription("The name of the generated
|
|
18
|
+
Flag.withDescription("The name of the generated output"),
|
|
19
19
|
Flag.withDefault("Client")
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
Flag.withAlias("
|
|
24
|
-
Flag.withDescription(
|
|
22
|
+
const format = Flag.choice("format", ["httpclient", "httpclient-type-only", "httpapi"] as const).pipe(
|
|
23
|
+
Flag.withAlias("f"),
|
|
24
|
+
Flag.withDescription(
|
|
25
|
+
"Output format to generate: httpclient | httpclient-type-only | httpapi (default: httpclient)"
|
|
26
|
+
),
|
|
27
|
+
Flag.withDefault("httpclient")
|
|
25
28
|
)
|
|
26
29
|
|
|
27
30
|
const patch = Flag.string("patch").pipe(
|
|
@@ -34,8 +37,8 @@ const patch = Flag.string("patch").pipe(
|
|
|
34
37
|
Flag.between(0, Infinity)
|
|
35
38
|
)
|
|
36
39
|
|
|
37
|
-
const root = Command.make("openapigen", { spec,
|
|
38
|
-
Command.withHandler(Effect.fnUntraced(function*({ name, spec,
|
|
40
|
+
const root = Command.make("openapigen", { spec, format, name, patch }).pipe(
|
|
41
|
+
Command.withHandler(Effect.fnUntraced(function*({ name, spec, format, patch }) {
|
|
39
42
|
let patchedSpec: Schema.Json = spec as Schema.Json
|
|
40
43
|
|
|
41
44
|
if (patch.length > 0) {
|
|
@@ -53,11 +56,23 @@ const root = Command.make("openapigen", { spec, typeOnly, name, patch }).pipe(
|
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
const generator = yield* OpenApiGenerator.OpenApiGenerator
|
|
56
|
-
const
|
|
59
|
+
const warnings: Array<OpenApiGenerator.OpenApiGeneratorWarning> = []
|
|
60
|
+
const source = yield* generator.generate(patchedSpec as unknown as OpenAPISpec, {
|
|
61
|
+
name,
|
|
62
|
+
format,
|
|
63
|
+
onWarning: (warning) => {
|
|
64
|
+
warnings.push(warning)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
yield* Effect.forEach(
|
|
68
|
+
warnings,
|
|
69
|
+
(warning) => Console.error(formatWarning(warning)),
|
|
70
|
+
{ discard: true }
|
|
71
|
+
)
|
|
57
72
|
return yield* Console.log(source)
|
|
58
73
|
})),
|
|
59
|
-
Command.provide(({
|
|
60
|
-
|
|
74
|
+
Command.provide(({ format }) =>
|
|
75
|
+
format === "httpclient-type-only"
|
|
61
76
|
? OpenApiGenerator.layerTransformerTs
|
|
62
77
|
: OpenApiGenerator.layerTransformerSchema
|
|
63
78
|
)
|
|
@@ -66,3 +81,14 @@ const root = Command.make("openapigen", { spec, typeOnly, name, patch }).pipe(
|
|
|
66
81
|
export const run: Effect.Effect<void, CliError.CliError, Command.Environment> = Command.run(root, {
|
|
67
82
|
version: "0.0.0"
|
|
68
83
|
})
|
|
84
|
+
|
|
85
|
+
const formatWarning = (warning: OpenApiGenerator.OpenApiGeneratorWarning): string => {
|
|
86
|
+
const context = [
|
|
87
|
+
warning.method?.toUpperCase(),
|
|
88
|
+
warning.path,
|
|
89
|
+
warning.operationId ? `(${warning.operationId})` : undefined
|
|
90
|
+
].filter((value): value is string => value !== undefined)
|
|
91
|
+
return context.length > 0
|
|
92
|
+
? `WARNING [${warning.code}] ${context.join(" ")}: ${warning.message}`
|
|
93
|
+
: `WARNING [${warning.code}] ${warning.message}`
|
|
94
|
+
}
|