@kubb/swagger-ts 2.0.0-alpha.8 → 2.0.0-beta.1

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,18 +1,19 @@
1
1
  import { SchemaGenerator } from '@kubb/core'
2
2
  import { getUniqueName } from '@kubb/core/utils'
3
3
  import * as factory from '@kubb/parser/factory'
4
- import { isReference } from '@kubb/swagger/utils'
4
+ import { getSchemaFactory, isReference } from '@kubb/swagger/utils'
5
5
 
6
6
  import { camelCase } from 'change-case'
7
7
 
8
8
  import type { PluginContext } from '@kubb/core'
9
9
  import type { ts } from '@kubb/parser'
10
- import type { OpenAPIV3, Refs } from '@kubb/swagger'
10
+ import type { Oas, OasTypes, OpenAPIV3, OpenAPIV3_1, Refs } from '@kubb/swagger'
11
11
  import type { Options as CaseOptions } from 'change-case'
12
12
 
13
13
  // based on https://github.com/cellular/oazapfts/blob/7ba226ebb15374e8483cc53e7532f1663179a22c/src/codegen/generate.ts#L398
14
14
 
15
15
  type Options = {
16
+ oas: Oas
16
17
  usedEnumNames: Record<string, number>
17
18
 
18
19
  withJSDocs?: boolean
@@ -21,7 +22,8 @@ type Options = {
21
22
  dateType: 'string' | 'date'
22
23
  optionalType: 'questionToken' | 'undefined' | 'questionTokenAndUndefined'
23
24
  }
24
- export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObject, ts.Node[]> {
25
+
26
+ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObject, ts.Node[]> {
25
27
  refs: Refs = {}
26
28
 
27
29
  extraNodes: ts.Node[] = []
@@ -37,14 +39,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
37
39
  }
38
40
 
39
41
  constructor(
40
- options: Options = {
41
- usedEnumNames: {},
42
- withJSDocs: true,
43
- resolveName: ({ name }) => name,
44
- enumType: 'asConst',
45
- dateType: 'string',
46
- optionalType: 'questionToken',
47
- },
42
+ options: Options,
48
43
  ) {
49
44
  super(options)
50
45
 
@@ -57,7 +52,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
57
52
  description,
58
53
  keysToOmit,
59
54
  }: {
60
- schema: OpenAPIV3.SchemaObject
55
+ schema: OasTypes.SchemaObject
61
56
  baseName: string
62
57
  description?: string
63
58
  keysToOmit?: string[]
@@ -102,7 +97,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
102
97
  * Delegates to getBaseTypeFromSchema internally and
103
98
  * optionally adds a union with null.
104
99
  */
105
- #getTypeFromSchema(schema?: OpenAPIV3.SchemaObject, name?: string): ts.TypeNode | null {
100
+ #getTypeFromSchema(schema?: OasTypes.SchemaObject, name?: string): ts.TypeNode | null {
106
101
  const type = this.#getBaseTypeFromSchema(schema, name)
107
102
 
108
103
  if (!type) {
@@ -119,16 +114,16 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
119
114
  /**
120
115
  * Recursively creates a type literal with the given props.
121
116
  */
122
- #getTypeFromProperties(baseSchema?: OpenAPIV3.SchemaObject, baseName?: string) {
117
+ #getTypeFromProperties(baseSchema?: OasTypes.SchemaObject, baseName?: string) {
123
118
  const { optionalType } = this.options
124
119
  const properties = baseSchema?.properties || {}
125
120
  const required = baseSchema?.required
126
121
  const additionalProperties = baseSchema?.additionalProperties
127
122
 
128
123
  const members: Array<ts.TypeElement | null> = Object.keys(properties).map((name) => {
129
- const schema = properties[name] as OpenAPIV3.SchemaObject
124
+ const schema = properties[name] as OasTypes.SchemaObject
130
125
 
131
- const isRequired = required && required.includes(name)
126
+ const isRequired = Array.isArray(required) ? required.includes(name) : !!required
132
127
  let type = this.#getTypeFromSchema(schema, this.options.resolveName({ name: `${baseName || ''} ${name}` }))
133
128
 
134
129
  if (!type) {
@@ -149,7 +144,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
149
144
  node: propertySignature,
150
145
  comments: [
151
146
  schema.description ? `@description ${schema.description}` : undefined,
152
- schema.type ? `@type ${schema.type}${isRequired ? '' : ' | undefined'} ${schema.format || ''}` : undefined,
147
+ schema.type ? `@type ${schema.type?.toString()}${isRequired ? '' : ' | undefined'} ${schema.format || ''}` : undefined,
153
148
  schema.example ? `@example ${schema.example as string}` : undefined,
154
149
  schema.deprecated ? `@deprecated` : undefined,
155
150
  schema.default !== undefined && typeof schema.default === 'string' ? `@default '${schema.default}'` : undefined,
@@ -161,7 +156,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
161
156
  return propertySignature
162
157
  })
163
158
  if (additionalProperties) {
164
- const type = additionalProperties === true ? factory.keywordTypeNodes.any : this.#getTypeFromSchema(additionalProperties as OpenAPIV3.SchemaObject)
159
+ const type = additionalProperties === true ? factory.keywordTypeNodes.any : this.#getTypeFromSchema(additionalProperties as OasTypes.SchemaObject)
165
160
 
166
161
  if (type) {
167
162
  members.push(factory.createIndexSignature(type))
@@ -192,11 +187,21 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
192
187
  return factory.createTypeReferenceNode(ref.propertyName, undefined)
193
188
  }
194
189
 
190
+ #getParsedSchema(schema?: OasTypes.SchemaObject) {
191
+ const parsedSchema = getSchemaFactory(this.options.oas)(schema)
192
+ return parsedSchema
193
+ }
194
+
195
195
  /**
196
196
  * This is the very core of the OpenAPI to TS conversion - it takes a
197
197
  * schema and returns the appropriate type.
198
198
  */
199
- #getBaseTypeFromSchema(schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined, baseName?: string): ts.TypeNode | null {
199
+ #getBaseTypeFromSchema(
200
+ _schema: OasTypes.SchemaObject | undefined,
201
+ baseName?: string,
202
+ ): ts.TypeNode | null {
203
+ const { schema, version } = this.#getParsedSchema(_schema)
204
+
200
205
  if (!schema) {
201
206
  return factory.keywordTypeNodes.any
202
207
  }
@@ -207,13 +212,13 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
207
212
 
208
213
  if (schema.oneOf) {
209
214
  // union
210
- const schemaWithoutOneOf = { ...schema, oneOf: undefined }
215
+ const schemaWithoutOneOf = { ...schema, oneOf: undefined } as OasTypes.SchemaObject
211
216
 
212
217
  const union = factory.createUnionDeclaration({
213
218
  withParentheses: true,
214
219
  nodes: schema.oneOf
215
- .map((item: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject) => {
216
- return this.#getBaseTypeFromSchema(item)
220
+ .map((item) => {
221
+ return item && this.#getBaseTypeFromSchema(item as OasTypes.SchemaObject)
217
222
  })
218
223
  .filter((item) => {
219
224
  return item && item !== factory.keywordTypeNodes.any
@@ -230,13 +235,13 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
230
235
  }
231
236
 
232
237
  if (schema.anyOf) {
233
- const schemaWithoutAnyOf = { ...schema, anyOf: undefined }
238
+ const schemaWithoutAnyOf = { ...schema, anyOf: undefined } as OasTypes.SchemaObject
234
239
 
235
240
  const union = factory.createUnionDeclaration({
236
241
  withParentheses: true,
237
242
  nodes: schema.anyOf
238
- .map((item: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject) => {
239
- return this.#getBaseTypeFromSchema(item)
243
+ .map((item) => {
244
+ return item && this.#getBaseTypeFromSchema(item as OasTypes.SchemaObject)
240
245
  })
241
246
  .filter((item) => {
242
247
  return item && item !== factory.keywordTypeNodes.any
@@ -253,13 +258,13 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
253
258
  }
254
259
  if (schema.allOf) {
255
260
  // intersection/add
256
- const schemaWithoutAllOf = { ...schema, allOf: undefined }
261
+ const schemaWithoutAllOf = { ...schema, allOf: undefined } as OasTypes.SchemaObject
257
262
 
258
263
  const and = factory.createIntersectionDeclaration({
259
264
  withParentheses: true,
260
265
  nodes: schema.allOf
261
- .map((item: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject) => {
262
- return this.#getBaseTypeFromSchema(item)
266
+ .map((item) => {
267
+ return item && this.#getBaseTypeFromSchema(item as OasTypes.SchemaObject)
263
268
  })
264
269
  .filter((item) => {
265
270
  return item && item !== factory.keywordTypeNodes.any
@@ -285,7 +290,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
285
290
 
286
291
  if ('x-enumNames' in schema) {
287
292
  enums = [...new Set(schema['x-enumNames'] as string[])].map((key: string, index) => {
288
- return [key, schema.enum?.[index]]
293
+ return [key, schema.enum?.[index] as string]
289
294
  })
290
295
  }
291
296
 
@@ -302,7 +307,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
302
307
 
303
308
  if (schema.enum) {
304
309
  return factory.createUnionDeclaration({
305
- nodes: schema.enum.map((name: string) => {
310
+ nodes: schema.enum.map((name) => {
306
311
  return factory.createLiteralTypeNode(typeof name === 'number' ? factory.createNumericLiteral(name) : factory.createStringLiteral(`${name}`))
307
312
  }) as unknown as Array<ts.TypeNode>,
308
313
  })
@@ -310,17 +315,19 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
310
315
 
311
316
  if ('items' in schema) {
312
317
  // items -> array
313
- const node = this.#getTypeFromSchema(schema.items as OpenAPIV3.SchemaObject, baseName)
318
+ const node = this.#getTypeFromSchema(schema.items as OasTypes.SchemaObject, baseName)
314
319
  if (node) {
315
320
  return factory.createArrayTypeNode(node)
316
321
  }
317
322
  }
323
+
318
324
  /**
319
325
  * OpenAPI 3.1
320
326
  * @link https://json-schema.org/understanding-json-schema/reference/array.html#tuple-validation
321
327
  */
328
+
322
329
  if ('prefixItems' in schema) {
323
- const prefixItems = schema.prefixItems as OpenAPIV3.SchemaObject[]
330
+ const prefixItems = schema.prefixItems as OasTypes.SchemaObject[]
324
331
 
325
332
  return factory.createTupleDeclaration({
326
333
  nodes: prefixItems.map((item) => {
@@ -338,7 +345,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
338
345
  if (schema.type) {
339
346
  if (Array.isArray(schema.type)) {
340
347
  // OPENAPI v3.1.0: https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
341
- const [type, nullable] = schema.type as Array<OpenAPIV3.NonArraySchemaObjectType>
348
+ const [type, nullable] = schema.type as Array<OpenAPIV3_1.NonArraySchemaObjectType>
342
349
 
343
350
  return factory.createUnionDeclaration({
344
351
  nodes: [
@@ -369,7 +376,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
369
376
  }
370
377
 
371
378
  // detect assertion "const" and define the type property as a Literal
372
- if ('const' in schema && schema['const'] !== undefined && typeof schema['const'] === 'string') {
379
+ if (version === '3.1' && typeof schema['const'] === 'string') {
373
380
  return factory.createLiteralTypeNode(factory.createStringLiteral(schema['const']))
374
381
  }
375
382
 
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { definePlugin } from './plugin.ts'
2
2
 
3
- export * from './plugin.ts'
4
- export { resolve } from './resolve.ts'
3
+ export { definePlugin, pluginKey, pluginName } from './plugin.ts'
5
4
  export * from './types.ts'
6
5
 
7
6
  export default definePlugin
package/src/plugin.ts CHANGED
@@ -10,7 +10,7 @@ import { TypeBuilder } from './builders/index.ts'
10
10
  import { OperationGenerator } from './generators/index.ts'
11
11
 
12
12
  import type { KubbFile, KubbPlugin } from '@kubb/core'
13
- import type { OpenAPIV3, PluginOptions as SwaggerPluginOptions } from '@kubb/swagger'
13
+ import type { OasTypes, PluginOptions as SwaggerPluginOptions } from '@kubb/swagger'
14
14
  import type { PluginOptions } from './types.ts'
15
15
 
16
16
  export const pluginName = 'swagger-ts' satisfies PluginOptions['name']
@@ -61,10 +61,14 @@ export const definePlugin = createPlugin<PluginOptions>((options) => {
61
61
 
62
62
  return path.resolve(root, output, baseName)
63
63
  },
64
- resolveName(name) {
64
+ resolveName(name, type) {
65
65
  const resolvedName = pascalCase(name, { delimiter: '', stripRegexp: /[^A-Z0-9$]/gi, transform: pascalCaseTransformMerge })
66
66
 
67
- return transformers?.name?.(resolvedName) || resolvedName
67
+ if (type) {
68
+ return transformers?.name?.(resolvedName, type) || resolvedName
69
+ }
70
+
71
+ return resolvedName
68
72
  },
69
73
  async writeFile(source, writePath) {
70
74
  if (!writePath.endsWith('.ts') || !source) {
@@ -102,8 +106,9 @@ export const definePlugin = createPlugin<PluginOptions>((options) => {
102
106
  enumType,
103
107
  dateType,
104
108
  optionalType,
109
+ oas,
105
110
  }).configure()
106
- Object.entries(schemas).forEach(([name, schema]: [string, OpenAPIV3.SchemaObject]) => {
111
+ Object.entries(schemas).forEach(([name, schema]: [string, OasTypes.SchemaObject]) => {
107
112
  // generate and pass through new code back to the core so it can be write to that file
108
113
  return builder.add({
109
114
  schema,
@@ -111,7 +116,7 @@ export const definePlugin = createPlugin<PluginOptions>((options) => {
111
116
  })
112
117
  })
113
118
 
114
- const mapFolderSchema = async ([name]: [string, OpenAPIV3.SchemaObject]) => {
119
+ const mapFolderSchema = async ([name]: [string, OasTypes.SchemaObject]) => {
115
120
  const resolvedPath = this.resolvePath({ baseName: `${this.resolveName({ name, pluginKey: this.plugin.key })}.ts`, pluginKey: this.plugin.key })
116
121
 
117
122
  if (!resolvedPath) {
@@ -142,8 +147,9 @@ export const definePlugin = createPlugin<PluginOptions>((options) => {
142
147
  enumType,
143
148
  dateType,
144
149
  optionalType,
150
+ oas,
145
151
  }).configure()
146
- Object.entries(schemas).forEach(([name, schema]: [string, OpenAPIV3.SchemaObject]) => {
152
+ Object.entries(schemas).forEach(([name, schema]: [string, OasTypes.SchemaObject]) => {
147
153
  // generate and pass through new code back to the core so it can be write to that file
148
154
  return builder.add({
149
155
  schema,
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { KubbPlugin, PluginFactoryOptions } from '@kubb/core'
1
+ import type { KubbPlugin, PluginFactoryOptions, ResolveNameParams } from '@kubb/core'
2
2
  import type { Exclude, Include, Override, ResolvePathOptions } from '@kubb/swagger'
3
3
 
4
4
  export type Options = {
@@ -61,14 +61,15 @@ export type Options = {
61
61
  optionalType?: 'questionToken' | 'undefined' | 'questionTokenAndUndefined'
62
62
  transformers?: {
63
63
  /**
64
- * Override the name of the TypeScript type that is getting generated, this will also override the name of the file.
64
+ * Customize the names based on the type that is provided by the plugin.
65
65
  */
66
- name?: (name: string) => string
66
+ name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string
67
67
  }
68
68
  }
69
69
 
70
70
  export type FileMeta = {
71
71
  pluginKey?: KubbPlugin['key']
72
+ name?: string
72
73
  tag?: string
73
74
  }
74
75