@kubb/plugin-ts 5.0.0-beta.4 → 5.0.0-beta.56
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 +39 -22
- package/dist/index.cjs +513 -266
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +168 -144
- package/dist/index.js +506 -263
- package/dist/index.js.map +1 -1
- package/package.json +13 -22
- package/src/components/Enum.tsx +33 -29
- package/src/components/Type.tsx +6 -11
- package/src/constants.ts +7 -7
- package/src/factory.ts +58 -62
- package/src/generators/typeGenerator.tsx +118 -77
- package/src/plugin.ts +30 -28
- package/src/printers/functionPrinter.ts +2 -2
- package/src/printers/printerTs.ts +44 -54
- package/src/resolvers/resolverTs.ts +28 -25
- package/src/types.ts +113 -86
- package/src/utils.ts +24 -14
- package/extension.yaml +0 -632
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
|
@@ -1,66 +1,69 @@
|
|
|
1
|
-
import { pascalCase } from '@internals/utils'
|
|
1
|
+
import { ensureValidVarName, pascalCase, toFilePath } from '@internals/utils'
|
|
2
2
|
import { defineResolver } from '@kubb/core'
|
|
3
3
|
import type { PluginTs } from '../types.ts'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Default resolver used by `@kubb/plugin-ts`. Decides the names and file paths
|
|
7
|
+
* for every generated TypeScript type. Import this in other plugins that need
|
|
8
|
+
* to reference the exact names `plugin-ts` produces without duplicating the
|
|
9
|
+
* casing/file-layout rules.
|
|
9
10
|
*
|
|
10
|
-
* The `default` method is
|
|
11
|
-
*
|
|
11
|
+
* The `default` method is supplied by `defineResolver`. It uses PascalCase for
|
|
12
|
+
* type names and PascalCase file paths (dotted names become `/`-joined) for files.
|
|
12
13
|
*
|
|
13
|
-
* @example
|
|
14
|
+
* @example Resolve a type and file name
|
|
14
15
|
* ```ts
|
|
15
|
-
* import {
|
|
16
|
+
* import { resolverTs } from '@kubb/plugin-ts'
|
|
16
17
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* resolverTs.default('list pets', 'type') // 'ListPets'
|
|
19
|
+
* resolverTs.resolvePathName('list pets', 'file') // 'ListPets'
|
|
20
|
+
* resolverTs.resolveResponseStatusName(node, 200) // 'ListPetsStatus200'
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
|
-
export const resolverTs = defineResolver<PluginTs>((
|
|
23
|
+
export const resolverTs = defineResolver<PluginTs>(() => {
|
|
23
24
|
return {
|
|
24
25
|
name: 'default',
|
|
25
26
|
pluginName: 'plugin-ts',
|
|
26
27
|
default(name, type) {
|
|
27
|
-
|
|
28
|
+
if (type === 'file') return toFilePath(name, pascalCase)
|
|
29
|
+
return ensureValidVarName(pascalCase(name))
|
|
28
30
|
},
|
|
29
31
|
resolveTypeName(name) {
|
|
30
|
-
return pascalCase(name)
|
|
32
|
+
return ensureValidVarName(pascalCase(name))
|
|
31
33
|
},
|
|
32
34
|
resolvePathName(name, type) {
|
|
33
|
-
|
|
35
|
+
if (type === 'file') return toFilePath(name, pascalCase)
|
|
36
|
+
return ensureValidVarName(pascalCase(name))
|
|
34
37
|
},
|
|
35
38
|
resolveParamName(node, param) {
|
|
36
|
-
return
|
|
39
|
+
return this.resolveTypeName(`${node.operationId} ${param.in} ${param.name}`)
|
|
37
40
|
},
|
|
38
41
|
resolveResponseStatusName(node, statusCode) {
|
|
39
|
-
return
|
|
42
|
+
return this.resolveTypeName(`${node.operationId} Status ${statusCode}`)
|
|
40
43
|
},
|
|
41
44
|
resolveDataName(node) {
|
|
42
|
-
return
|
|
45
|
+
return this.resolveTypeName(`${node.operationId} Data`)
|
|
43
46
|
},
|
|
44
47
|
resolveRequestConfigName(node) {
|
|
45
|
-
return
|
|
48
|
+
return this.resolveTypeName(`${node.operationId} RequestConfig`)
|
|
46
49
|
},
|
|
47
50
|
resolveResponsesName(node) {
|
|
48
|
-
return
|
|
51
|
+
return this.resolveTypeName(`${node.operationId} Responses`)
|
|
49
52
|
},
|
|
50
53
|
resolveResponseName(node) {
|
|
51
|
-
return
|
|
54
|
+
return this.resolveTypeName(`${node.operationId} Response`)
|
|
52
55
|
},
|
|
53
56
|
resolveEnumKeyName(node, enumTypeSuffix = 'key') {
|
|
54
|
-
return `${
|
|
57
|
+
return `${this.resolveTypeName(node.name ?? '')}${enumTypeSuffix}`
|
|
55
58
|
},
|
|
56
59
|
resolvePathParamsName(node, param) {
|
|
57
|
-
return
|
|
60
|
+
return this.resolveParamName(node, param)
|
|
58
61
|
},
|
|
59
62
|
resolveQueryParamsName(node, param) {
|
|
60
|
-
return
|
|
63
|
+
return this.resolveParamName(node, param)
|
|
61
64
|
},
|
|
62
65
|
resolveHeaderParamsName(node, param) {
|
|
63
|
-
return
|
|
66
|
+
return this.resolveParamName(node, param)
|
|
64
67
|
},
|
|
65
68
|
}
|
|
66
69
|
})
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
1
|
+
import type { ast, Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
2
2
|
import type { PrinterTsNodes } from './printers/printerTs.ts'
|
|
3
3
|
/**
|
|
4
4
|
* The concrete resolver type for `@kubb/plugin-ts`.
|
|
@@ -93,34 +93,49 @@ export type ResolverTs = Resolver &
|
|
|
93
93
|
|
|
94
94
|
type EnumKeyCasing = 'screamingSnakeCase' | 'snakeCase' | 'pascalCase' | 'camelCase' | 'none'
|
|
95
95
|
|
|
96
|
+
type EnumConstCasing = 'camelCase' | 'pascalCase'
|
|
97
|
+
|
|
96
98
|
/**
|
|
97
|
-
*
|
|
99
|
+
* Grouped enum settings. Each `type` uses only some of the other fields.
|
|
100
|
+
*
|
|
101
|
+
* - `'asConst'` emits a `const` object plus a `typeof` type alias, so `constCasing`, `typeSuffix`, and `keyCasing` all apply.
|
|
102
|
+
* - `'enum'` and `'constEnum'` emit a TypeScript enum, so only `keyCasing` (the member names) applies.
|
|
103
|
+
* - `'literal'` and `'inlineLiteral'` emit union literals and drop the keys, so none of the other fields apply.
|
|
98
104
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
+
* @example Share one name between the const and the type
|
|
106
|
+
* ```ts
|
|
107
|
+
* enum: { type: 'asConst', constCasing: 'pascalCase', typeSuffix: '' }
|
|
108
|
+
* // export const VehicleType = { … } as const
|
|
109
|
+
* // export type VehicleType = (typeof VehicleType)[keyof typeof VehicleType]
|
|
110
|
+
* ```
|
|
105
111
|
*/
|
|
106
|
-
type
|
|
112
|
+
type EnumOptions =
|
|
107
113
|
| {
|
|
108
114
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
115
|
+
* Emit a `const` object asserted with `as const`, paired with a `typeof` type alias.
|
|
116
|
+
* This is tree-shakeable and adds no enum runtime.
|
|
117
|
+
*
|
|
112
118
|
* @default 'asConst'
|
|
113
119
|
*/
|
|
114
|
-
|
|
120
|
+
type?: 'asConst'
|
|
115
121
|
/**
|
|
116
|
-
*
|
|
122
|
+
* Casing of the generated const variable.
|
|
123
|
+
* - 'camelCase' names the const `vehicleType`.
|
|
124
|
+
* - 'pascalCase' names the const `VehicleType`, matching the schema name.
|
|
117
125
|
*
|
|
118
|
-
*
|
|
126
|
+
* @default 'camelCase'
|
|
127
|
+
*/
|
|
128
|
+
constCasing?: EnumConstCasing
|
|
129
|
+
/**
|
|
130
|
+
* Suffix appended to the generated type alias name. Only the type alias is renamed. The const
|
|
131
|
+
* object name stays the same. Set it to `''` together with `constCasing: 'pascalCase'` to merge
|
|
132
|
+
* the const and type under the schema's exact name.
|
|
119
133
|
*
|
|
120
134
|
* @default 'Key'
|
|
121
|
-
* @example
|
|
135
|
+
* @example A custom suffix
|
|
136
|
+
* `typeSuffix: 'Value'` renames the alias to `PetStatusValue`
|
|
122
137
|
*/
|
|
123
|
-
|
|
138
|
+
typeSuffix?: string
|
|
124
139
|
/**
|
|
125
140
|
* Choose the casing for enum key names.
|
|
126
141
|
* - 'screamingSnakeCase' generates keys in SCREAMING_SNAKE_CASE format.
|
|
@@ -130,23 +145,25 @@ type EnumTypeOptions =
|
|
|
130
145
|
* - 'none' uses the enum value as-is without transformation.
|
|
131
146
|
* @default 'none'
|
|
132
147
|
*/
|
|
133
|
-
|
|
148
|
+
keyCasing?: EnumKeyCasing
|
|
134
149
|
}
|
|
135
150
|
| {
|
|
136
151
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* - 'constEnum' generates TypeScript const enum declarations.
|
|
152
|
+
* Emit a TypeScript `enum` (`'enum'`) or `const enum` (`'constEnum'`) declaration.
|
|
153
|
+
*
|
|
140
154
|
* @default 'asConst'
|
|
141
155
|
*/
|
|
142
|
-
|
|
156
|
+
type?: 'enum' | 'constEnum'
|
|
143
157
|
/**
|
|
144
|
-
* `
|
|
145
|
-
* It is only used when `enumType` is `'asConst'` or `'asPascalConst'`.
|
|
158
|
+
* `constCasing` has no effect for this `type`. Only `'asConst'` emits a const object.
|
|
146
159
|
*/
|
|
147
|
-
|
|
160
|
+
constCasing?: never
|
|
148
161
|
/**
|
|
149
|
-
*
|
|
162
|
+
* `typeSuffix` has no effect for this `type`. Only `'asConst'` emits a separate type alias.
|
|
163
|
+
*/
|
|
164
|
+
typeSuffix?: never
|
|
165
|
+
/**
|
|
166
|
+
* Choose the casing for enum member names.
|
|
150
167
|
* - 'screamingSnakeCase' generates keys in SCREAMING_SNAKE_CASE format.
|
|
151
168
|
* - 'snakeCase' generates keys in snake_case format.
|
|
152
169
|
* - 'pascalCase' generates keys in PascalCase format.
|
|
@@ -154,99 +171,101 @@ type EnumTypeOptions =
|
|
|
154
171
|
* - 'none' uses the enum value as-is without transformation.
|
|
155
172
|
* @default 'none'
|
|
156
173
|
*/
|
|
157
|
-
|
|
174
|
+
keyCasing?: EnumKeyCasing
|
|
158
175
|
}
|
|
159
176
|
| {
|
|
160
177
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
178
|
+
* Emit a union of literals as a named alias (`'literal'`) or inline the union at every usage
|
|
179
|
+
* site (`'inlineLiteral'`).
|
|
180
|
+
*
|
|
164
181
|
* @default 'asConst'
|
|
165
182
|
* @note In Kubb v5, 'inlineLiteral' becomes the default.
|
|
166
183
|
*/
|
|
167
|
-
|
|
184
|
+
type?: 'literal' | 'inlineLiteral'
|
|
185
|
+
/**
|
|
186
|
+
* `constCasing` has no effect for this `type`; literal modes emit no const object.
|
|
187
|
+
*/
|
|
188
|
+
constCasing?: never
|
|
168
189
|
/**
|
|
169
|
-
* `
|
|
170
|
-
* It is only used when `enumType` is `'asConst'` or `'asPascalConst'`.
|
|
190
|
+
* `typeSuffix` has no effect for this `type`; literal modes emit no separate type alias.
|
|
171
191
|
*/
|
|
172
|
-
|
|
192
|
+
typeSuffix?: never
|
|
173
193
|
/**
|
|
174
|
-
* `
|
|
175
|
-
*
|
|
194
|
+
* `keyCasing` has no effect for this `type`. Literal and inlineLiteral modes emit only values,
|
|
195
|
+
* so the keys are discarded.
|
|
176
196
|
*/
|
|
177
|
-
|
|
197
|
+
keyCasing?: never
|
|
178
198
|
}
|
|
179
199
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
* Define which contentType should be used.
|
|
188
|
-
* By default, uses the first valid JSON media type.
|
|
189
|
-
*/
|
|
190
|
-
contentType?: 'application/json' | (string & {})
|
|
191
|
-
/**
|
|
192
|
-
* Group the clients based on the provided name.
|
|
193
|
-
*/
|
|
194
|
-
group?: Group
|
|
200
|
+
/**
|
|
201
|
+
* Where the generated `.ts` files are written and how they are exported, plus the optional
|
|
202
|
+
* `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
|
|
203
|
+
*
|
|
204
|
+
* @default { path: 'types', barrel: { type: 'named' } }
|
|
205
|
+
*/
|
|
206
|
+
export type Options = OutputOptions & {
|
|
195
207
|
/**
|
|
196
|
-
*
|
|
208
|
+
* Skip operations matching at least one entry in the list.
|
|
197
209
|
*/
|
|
198
210
|
exclude?: Array<Exclude>
|
|
199
211
|
/**
|
|
200
|
-
*
|
|
212
|
+
* Restrict generation to operations matching at least one entry in the list.
|
|
201
213
|
*/
|
|
202
214
|
include?: Array<Include>
|
|
203
215
|
/**
|
|
204
|
-
*
|
|
216
|
+
* Apply a different options object to operations matching a pattern.
|
|
205
217
|
*/
|
|
206
218
|
override?: Array<Override<ResolvedOptions>>
|
|
207
219
|
/**
|
|
208
|
-
*
|
|
209
|
-
* - 'type'
|
|
210
|
-
* - 'interface'
|
|
220
|
+
* Whether object schemas are emitted as `type` aliases or `interface` declarations.
|
|
221
|
+
* - `'type'` emits closed type aliases. Safer default for generated code.
|
|
222
|
+
* - `'interface'` emits interfaces. Useful when consumers rely on declaration merging.
|
|
223
|
+
*
|
|
211
224
|
* @default 'type'
|
|
225
|
+
* @see https://www.totaltypescript.com/type-vs-interface-which-should-you-use
|
|
212
226
|
*/
|
|
213
227
|
syntaxType?: 'type' | 'interface'
|
|
214
228
|
/**
|
|
215
|
-
*
|
|
216
|
-
* - 'questionToken'
|
|
217
|
-
* - 'undefined'
|
|
218
|
-
* - 'questionTokenAndUndefined'
|
|
229
|
+
* How optional properties are written in generated types.
|
|
230
|
+
* - `'questionToken'` — `type?: string`. The property may be missing.
|
|
231
|
+
* - `'undefined'` — `type: string | undefined`. Required to exist, may be `undefined`.
|
|
232
|
+
* - `'questionTokenAndUndefined'` — `type?: string | undefined`. Strictest.
|
|
233
|
+
*
|
|
219
234
|
* @default 'questionToken'
|
|
235
|
+
* @note Pick `'questionTokenAndUndefined'` when `exactOptionalPropertyTypes` is on in `tsconfig.json`.
|
|
220
236
|
*/
|
|
221
237
|
optionalType?: 'questionToken' | 'undefined' | 'questionTokenAndUndefined'
|
|
222
238
|
/**
|
|
223
|
-
*
|
|
224
|
-
* - '
|
|
225
|
-
* - '
|
|
239
|
+
* Syntax used for array types.
|
|
240
|
+
* - `'array'` — `Type[]`. Shorter.
|
|
241
|
+
* - `'generic'` — `Array<Type>`. More readable for complex element types.
|
|
242
|
+
*
|
|
226
243
|
* @default 'array'
|
|
227
244
|
*/
|
|
228
245
|
arrayType?: 'generic' | 'array'
|
|
229
246
|
/**
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* @note
|
|
247
|
+
* Rename properties inside `PathParams`, `QueryParams`, and `HeaderParams` types.
|
|
248
|
+
* Response and request body types are not affected.
|
|
249
|
+
*
|
|
250
|
+
* @note Every plugin that touches operation parameters must use the same value.
|
|
234
251
|
*/
|
|
235
252
|
paramsCasing?: 'camelcase'
|
|
236
253
|
/**
|
|
237
|
-
*
|
|
254
|
+
* Custom generators that run alongside the built-in TypeScript generators.
|
|
238
255
|
*/
|
|
239
256
|
generators?: Array<Generator<PluginTs>>
|
|
240
257
|
/**
|
|
241
|
-
* Override
|
|
242
|
-
*
|
|
258
|
+
* Override how names and file paths are built for generated symbols.
|
|
259
|
+
* Methods you omit fall back to the default `resolverTs`. `this` is bound to the
|
|
260
|
+
* full resolver, so `this.default(name, 'function')` delegates to the built-in
|
|
261
|
+
* implementation.
|
|
243
262
|
*/
|
|
244
263
|
resolver?: Partial<ResolverTs> & ThisType<ResolverTs>
|
|
245
264
|
/**
|
|
246
|
-
* AST visitor applied to each schema
|
|
247
|
-
*
|
|
265
|
+
* AST visitor applied to each schema or operation node before printing.
|
|
266
|
+
* Methods you omit fall back to the preset transformer.
|
|
248
267
|
*
|
|
249
|
-
* @example
|
|
268
|
+
* @example Drop writeOnly properties from response types
|
|
250
269
|
* ```ts
|
|
251
270
|
* transformer: {
|
|
252
271
|
* property(node) {
|
|
@@ -257,18 +276,17 @@ export type Options = {
|
|
|
257
276
|
*/
|
|
258
277
|
transformer?: ast.Visitor
|
|
259
278
|
/**
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
* built-in handler for that type. Use `this.transform` to recurse into nested schema nodes.
|
|
279
|
+
* Replace the TypeScript handler for a specific schema type (`'integer'`, `'date'`, ...).
|
|
280
|
+
* Each handler returns a TypeScript AST node for that schema type. Use `this.transform`
|
|
281
|
+
* to recurse into nested schema nodes.
|
|
264
282
|
*
|
|
265
|
-
* @example
|
|
283
|
+
* @example Use the JavaScript `Date` object for date schemas
|
|
266
284
|
* ```ts
|
|
267
285
|
* import ts from 'typescript'
|
|
268
286
|
* pluginTs({
|
|
269
287
|
* printer: {
|
|
270
288
|
* nodes: {
|
|
271
|
-
* date(
|
|
289
|
+
* date() {
|
|
272
290
|
* return ts.factory.createTypeReferenceNode('Date', [])
|
|
273
291
|
* },
|
|
274
292
|
* },
|
|
@@ -279,17 +297,26 @@ export type Options = {
|
|
|
279
297
|
printer?: {
|
|
280
298
|
nodes?: PrinterTsNodes
|
|
281
299
|
}
|
|
282
|
-
|
|
300
|
+
/**
|
|
301
|
+
* How OpenAPI enums are represented in the generated TypeScript, and how their names are cased.
|
|
302
|
+
*/
|
|
303
|
+
enum?: EnumOptions
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
type ResolvedEnumOptions = {
|
|
307
|
+
type: NonNullable<EnumOptions['type']>
|
|
308
|
+
constCasing: EnumConstCasing
|
|
309
|
+
typeSuffix: string
|
|
310
|
+
keyCasing: EnumKeyCasing
|
|
311
|
+
}
|
|
283
312
|
|
|
284
313
|
type ResolvedOptions = {
|
|
285
314
|
output: Output
|
|
286
315
|
exclude: Array<Exclude>
|
|
287
316
|
include: Array<Include> | undefined
|
|
288
317
|
override: Array<Override<ResolvedOptions>>
|
|
289
|
-
group: Group |
|
|
290
|
-
|
|
291
|
-
enumTypeSuffix: NonNullable<Options['enumTypeSuffix']>
|
|
292
|
-
enumKeyCasing: EnumKeyCasing
|
|
318
|
+
group: Group | null
|
|
319
|
+
enum: ResolvedEnumOptions
|
|
293
320
|
optionalType: NonNullable<Options['optionalType']>
|
|
294
321
|
arrayType: NonNullable<Options['arrayType']>
|
|
295
322
|
syntaxType: NonNullable<Options['syntaxType']>
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { jsStringEscape, stringify } from '@
|
|
1
|
+
import { jsStringEscape, stringify } from '@kubb/ast/utils'
|
|
2
|
+
import { getOperationParameters } from '@internals/shared'
|
|
2
3
|
import { ast } from '@kubb/core'
|
|
3
4
|
import type { ResolverTs } from './types.ts'
|
|
4
5
|
|
|
@@ -14,20 +15,31 @@ export function buildPropertyJSDocComments(schema: ast.SchemaNode): Array<string
|
|
|
14
15
|
|
|
15
16
|
const isArray = meta?.primitive === 'array'
|
|
16
17
|
|
|
18
|
+
const hasDescription = meta && 'description' in meta && meta.description
|
|
19
|
+
|
|
20
|
+
const formatComment =
|
|
21
|
+
meta && 'format' in meta && meta.format
|
|
22
|
+
? hasDescription
|
|
23
|
+
? // Empty line between description and format
|
|
24
|
+
[' ', `Format: \`${meta.format}\``]
|
|
25
|
+
: ['@description', `Format: \`${meta.format}\``]
|
|
26
|
+
: []
|
|
27
|
+
|
|
17
28
|
return [
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
|
|
30
|
+
...formatComment,
|
|
31
|
+
meta && 'deprecated' in meta && meta.deprecated ? '@deprecated' : null,
|
|
20
32
|
// minItems/maxItems on arrays should not be emitted as @minLength/@maxLength
|
|
21
|
-
!isArray && meta && 'min' in meta && meta.min !== undefined ? `@minLength ${meta.min}` :
|
|
22
|
-
!isArray && meta && 'max' in meta && meta.max !== undefined ? `@maxLength ${meta.max}` :
|
|
23
|
-
meta && 'pattern' in meta && meta.pattern ? `@pattern ${meta.pattern}` :
|
|
33
|
+
!isArray && meta && 'min' in meta && meta.min !== undefined ? `@minLength ${meta.min}` : null,
|
|
34
|
+
!isArray && meta && 'max' in meta && meta.max !== undefined ? `@maxLength ${meta.max}` : null,
|
|
35
|
+
meta && 'pattern' in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
|
|
24
36
|
meta && 'default' in meta && meta.default !== undefined
|
|
25
37
|
? `@default ${'primitive' in meta && meta.primitive === 'string' ? stringify(meta.default as string) : meta.default}`
|
|
26
|
-
:
|
|
27
|
-
meta && 'example' in meta && meta.example !== undefined ? `@example ${meta.example}` :
|
|
38
|
+
: null,
|
|
39
|
+
meta && 'example' in meta && meta.example !== undefined ? `@example ${meta.example}` : null,
|
|
28
40
|
meta && 'primitive' in meta && meta.primitive
|
|
29
|
-
? [`@type ${meta.primitive}`, 'optional' in schema && schema.optional ? ' | undefined' :
|
|
30
|
-
:
|
|
41
|
+
? [`@type ${meta.primitive}`, 'optional' in schema && schema.optional ? ' | undefined' : null].filter(Boolean).join('')
|
|
42
|
+
: null,
|
|
31
43
|
].filter(Boolean)
|
|
32
44
|
}
|
|
33
45
|
|
|
@@ -57,9 +69,7 @@ export function buildParams(node: ast.OperationNode, { params, resolver }: Build
|
|
|
57
69
|
}
|
|
58
70
|
|
|
59
71
|
export function buildData(node: ast.OperationNode, { resolver }: BuildOperationSchemaOptions): ast.SchemaNode {
|
|
60
|
-
const pathParams
|
|
61
|
-
const queryParams = node.parameters.filter((p) => p.in === 'query')
|
|
62
|
-
const headerParams = node.parameters.filter((p) => p.in === 'header')
|
|
72
|
+
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node)
|
|
63
73
|
|
|
64
74
|
return ast.createSchema({
|
|
65
75
|
type: 'object',
|
|
@@ -117,7 +127,7 @@ export function buildResponses(node: ast.OperationNode, { resolver }: BuildOpera
|
|
|
117
127
|
}
|
|
118
128
|
|
|
119
129
|
export function buildResponseUnion(node: ast.OperationNode, { resolver }: BuildOperationSchemaOptions): ast.SchemaNode | null {
|
|
120
|
-
const responsesWithSchema = node.responses.filter((res) => res.schema)
|
|
130
|
+
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema))
|
|
121
131
|
|
|
122
132
|
if (responsesWithSchema.length === 0) {
|
|
123
133
|
return null
|