@kubb/plugin-ts 5.0.0-alpha.3 → 5.0.0-alpha.30

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 (42) hide show
  1. package/dist/index.cjs +1806 -3
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.ts +590 -4
  4. package/dist/index.js +1776 -2
  5. package/dist/index.js.map +1 -0
  6. package/package.json +7 -27
  7. package/src/components/Enum.tsx +82 -0
  8. package/src/components/Type.tsx +29 -162
  9. package/src/constants.ts +39 -0
  10. package/src/factory.ts +134 -49
  11. package/src/generators/typeGenerator.tsx +165 -428
  12. package/src/generators/typeGeneratorLegacy.tsx +349 -0
  13. package/src/index.ts +9 -1
  14. package/src/plugin.ts +98 -176
  15. package/src/presets.ts +28 -0
  16. package/src/printers/functionPrinter.ts +196 -0
  17. package/src/printers/printerTs.ts +310 -0
  18. package/src/resolvers/resolverTs.ts +66 -0
  19. package/src/resolvers/resolverTsLegacy.ts +60 -0
  20. package/src/types.ts +258 -98
  21. package/src/utils.ts +131 -0
  22. package/dist/components-CRjwjdyE.js +0 -725
  23. package/dist/components-CRjwjdyE.js.map +0 -1
  24. package/dist/components-DI0aTIBg.cjs +0 -978
  25. package/dist/components-DI0aTIBg.cjs.map +0 -1
  26. package/dist/components.cjs +0 -3
  27. package/dist/components.d.ts +0 -38
  28. package/dist/components.js +0 -2
  29. package/dist/generators.cjs +0 -4
  30. package/dist/generators.d.ts +0 -503
  31. package/dist/generators.js +0 -2
  32. package/dist/plugin-D5rCK1zO.cjs +0 -992
  33. package/dist/plugin-D5rCK1zO.cjs.map +0 -1
  34. package/dist/plugin-DmwgRHK8.js +0 -944
  35. package/dist/plugin-DmwgRHK8.js.map +0 -1
  36. package/dist/types-BpeKGgCn.d.ts +0 -170
  37. package/src/components/index.ts +0 -1
  38. package/src/components/v2/Type.tsx +0 -165
  39. package/src/generators/index.ts +0 -2
  40. package/src/generators/v2/typeGenerator.tsx +0 -196
  41. package/src/parser.ts +0 -396
  42. package/src/printer.ts +0 -244
@@ -1,196 +0,0 @@
1
- import type { SchemaNode } from '@kubb/ast/types'
2
- import { useKubb } from '@kubb/core/hooks'
3
- import { createReactGenerator } from '@kubb/plugin-oas/generators'
4
- import { File } from '@kubb/react-fabric'
5
- import { Type } from '../../components/v2/Type.tsx'
6
- import type { PluginTs } from '../../types'
7
-
8
- export const typeGenerator = createReactGenerator<PluginTs, '2'>({
9
- name: 'typescript',
10
- version: '2',
11
- Operation({ node, adapter, options }) {
12
- const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType } = options
13
-
14
- const { plugin, mode, getFile, resolveName } = useKubb<PluginTs>()
15
-
16
- const file = getFile({
17
- name: node.operationId,
18
- pluginName: plugin.name,
19
- extname: '.ts',
20
- mode,
21
- })
22
-
23
- function renderSchemaType({ node: schemaNode, name, typedName, description }: { node: SchemaNode; name: string; typedName: string; description?: string }) {
24
- const imports = adapter.getImports(schemaNode, (schemaName) => ({
25
- name: resolveName({
26
- name: schemaName,
27
- pluginName: plugin.name,
28
- type: 'type',
29
- }),
30
- path: getFile({
31
- name: schemaName,
32
- pluginName: plugin.name,
33
- extname: '.ts',
34
- mode,
35
- }).path,
36
- }))
37
-
38
- return (
39
- <>
40
- {mode === 'split' &&
41
- imports.map((imp) => <File.Import key={[name, imp.path, imp.isTypeOnly].join('-')} root={file.path} path={imp.path} name={imp.name} isTypeOnly />)}
42
-
43
- <Type
44
- name={name}
45
- typedName={typedName}
46
- node={schemaNode}
47
- description={description}
48
- enumType={enumType}
49
- enumKeyCasing={enumKeyCasing}
50
- optionalType={optionalType}
51
- arrayType={arrayType}
52
- syntaxType={syntaxType}
53
- />
54
- </>
55
- )
56
- }
57
-
58
- // Parameter types — each parameter rendered as its own type
59
- const paramTypes = node.parameters.map((param) => {
60
- const name = resolveName({
61
- name: `${node.operationId} ${param.name}`,
62
- pluginName: plugin.name,
63
- type: 'function',
64
- })
65
- const typedName = resolveName({
66
- name: `${node.operationId} ${param.name}`,
67
- pluginName: plugin.name,
68
- type: 'type',
69
- })
70
-
71
- return renderSchemaType({ node: param.schema, name, typedName })
72
- })
73
-
74
- // Response types
75
- const responseTypes = node.responses
76
- .filter((res) => res.schema)
77
- .map((res) => {
78
- const schemaNode = res.schema!
79
- const responseName = `${node.operationId} ${res.statusCode}`
80
- const resolvedName = resolveName({
81
- name: responseName,
82
- pluginName: plugin.name,
83
- type: 'function',
84
- })
85
- const typedName = resolveName({
86
- name: responseName,
87
- pluginName: plugin.name,
88
- type: 'type',
89
- })
90
-
91
- return renderSchemaType({ node: schemaNode, name: resolvedName, typedName, description: res.description })
92
- })
93
-
94
- // Request body type
95
- const requestType = node.requestBody
96
- ? (() => {
97
- const requestName = `${node.operationId} MutationRequest`
98
- const resolvedName = resolveName({
99
- name: requestName,
100
- pluginName: plugin.name,
101
- type: 'function',
102
- })
103
- const typedName = resolveName({
104
- name: requestName,
105
- pluginName: plugin.name,
106
- type: 'type',
107
- })
108
-
109
- return renderSchemaType({ node: node.requestBody, name: resolvedName, typedName, description: node.requestBody.description })
110
- })()
111
- : null
112
-
113
- return (
114
- <File baseName={file.baseName} path={file.path} meta={file.meta}>
115
- {paramTypes}
116
- {responseTypes}
117
- {requestType}
118
- </File>
119
- )
120
- },
121
- Schema({ node, adapter, options }) {
122
- const { enumType, enumKeyCasing, syntaxType, optionalType, arrayType } = options
123
- const { plugin, mode, resolveName, getFile } = useKubb<PluginTs>()
124
-
125
- if (!node.name) {
126
- return
127
- }
128
-
129
- const imports = adapter.getImports(node, (schemaName) => ({
130
- name: resolveName({
131
- name: schemaName,
132
- pluginName: plugin.name,
133
- type: 'type',
134
- }),
135
- path: getFile({
136
- name: schemaName,
137
- pluginName: plugin.name,
138
- extname: '.ts',
139
- mode,
140
- // options: {
141
- // group
142
- // },
143
- }).path,
144
- }))
145
-
146
- const isEnumSchema = node.type === 'enum'
147
-
148
- let typedName = resolveName({
149
- name: node.name,
150
- pluginName: plugin.name,
151
- type: 'type',
152
- })
153
-
154
- if (['asConst', 'asPascalConst'].includes(enumType) && isEnumSchema) {
155
- typedName = typedName += 'Key'
156
- }
157
-
158
- const type = {
159
- name: resolveName({
160
- name: node.name,
161
- pluginName: plugin.name,
162
- type: 'function',
163
- }),
164
- typedName,
165
- file: getFile({
166
- name: node.name,
167
- pluginName: plugin.name,
168
- extname: '.ts',
169
- mode,
170
- // options: {
171
- // group
172
- // },
173
- }),
174
- } as const
175
-
176
- return (
177
- <File baseName={type.file.baseName} path={type.file.path} meta={type.file.meta}>
178
- {mode === 'split' &&
179
- imports.map((imp) => (
180
- <File.Import key={[node.name, imp.path, imp.isTypeOnly].join('-')} root={type.file.path} path={imp.path} name={imp.name} isTypeOnly />
181
- ))}
182
-
183
- <Type
184
- name={type.name}
185
- typedName={type.typedName}
186
- node={node}
187
- enumType={enumType}
188
- enumKeyCasing={enumKeyCasing}
189
- optionalType={optionalType}
190
- arrayType={arrayType}
191
- syntaxType={syntaxType}
192
- />
193
- </File>
194
- )
195
- },
196
- })
package/src/parser.ts DELETED
@@ -1,396 +0,0 @@
1
- import { jsStringEscape } from '@internals/utils'
2
- import type { SchemaKeywordMapper, SchemaMapper } from '@kubb/plugin-oas'
3
- import { createParser, isKeyword, schemaKeywords } from '@kubb/plugin-oas'
4
- import type ts from 'typescript'
5
- import * as factory from './factory.ts'
6
-
7
- export const typeKeywordMapper = {
8
- any: () => factory.keywordTypeNodes.any,
9
- unknown: () => factory.keywordTypeNodes.unknown,
10
- void: () => factory.keywordTypeNodes.void,
11
- number: () => factory.keywordTypeNodes.number,
12
- integer: () => factory.keywordTypeNodes.number,
13
- bigint: () => factory.keywordTypeNodes.bigint,
14
- object: (nodes?: ts.TypeElement[]) => {
15
- if (!nodes || !nodes.length) {
16
- return factory.keywordTypeNodes.object
17
- }
18
-
19
- return factory.createTypeLiteralNode(nodes)
20
- },
21
- string: () => factory.keywordTypeNodes.string,
22
- boolean: () => factory.keywordTypeNodes.boolean,
23
- undefined: () => factory.keywordTypeNodes.undefined,
24
- nullable: undefined,
25
- null: () => factory.keywordTypeNodes.null,
26
- nullish: undefined,
27
- array: (nodes?: ts.TypeNode[], arrayType?: 'array' | 'generic') => {
28
- if (!nodes) {
29
- return undefined
30
- }
31
-
32
- return factory.createArrayDeclaration({ nodes, arrayType })
33
- },
34
- tuple: (nodes?: ts.TypeNode[], rest?: ts.TypeNode, min?: number, max?: number) => {
35
- if (!nodes) {
36
- return undefined
37
- }
38
-
39
- if (max) {
40
- nodes = nodes.slice(0, max)
41
-
42
- if (nodes.length < max && rest) {
43
- nodes = [...nodes, ...Array(max - nodes.length).fill(rest)]
44
- }
45
- }
46
-
47
- if (min) {
48
- nodes = nodes.map((node, index) => (index >= min ? factory.createOptionalTypeNode(node) : node))
49
- }
50
-
51
- if (typeof max === 'undefined' && rest) {
52
- nodes.push(factory.createRestTypeNode(factory.createArrayTypeNode(rest)))
53
- }
54
-
55
- return factory.createTupleTypeNode(nodes)
56
- },
57
- enum: (name?: string) => {
58
- if (!name) {
59
- return undefined
60
- }
61
-
62
- return factory.createTypeReferenceNode(name, undefined)
63
- },
64
- union: (nodes?: ts.TypeNode[]) => {
65
- if (!nodes) {
66
- return undefined
67
- }
68
-
69
- return factory.createUnionDeclaration({
70
- withParentheses: true,
71
- nodes,
72
- })
73
- },
74
- const: (name?: string | number | boolean, format?: 'string' | 'number' | 'boolean') => {
75
- if (name === null || name === undefined || name === '') {
76
- return undefined
77
- }
78
-
79
- if (format === 'boolean') {
80
- if (name === true) {
81
- return factory.createLiteralTypeNode(factory.createTrue())
82
- }
83
-
84
- return factory.createLiteralTypeNode(factory.createFalse())
85
- }
86
-
87
- if (format === 'number' && typeof name === 'number') {
88
- return factory.createLiteralTypeNode(factory.createNumericLiteral(name))
89
- }
90
-
91
- return factory.createLiteralTypeNode(factory.createStringLiteral(name.toString()))
92
- },
93
- datetime: () => factory.keywordTypeNodes.string,
94
- date: (type: 'date' | 'string' = 'string') =>
95
- type === 'string' ? factory.keywordTypeNodes.string : factory.createTypeReferenceNode(factory.createIdentifier('Date')),
96
- time: (type: 'date' | 'string' = 'string') =>
97
- type === 'string' ? factory.keywordTypeNodes.string : factory.createTypeReferenceNode(factory.createIdentifier('Date')),
98
- uuid: () => factory.keywordTypeNodes.string,
99
- url: () => factory.keywordTypeNodes.string,
100
- default: undefined,
101
- and: (nodes?: ts.TypeNode[]) => {
102
- if (!nodes) {
103
- return undefined
104
- }
105
-
106
- return factory.createIntersectionDeclaration({
107
- withParentheses: true,
108
- nodes,
109
- })
110
- },
111
- describe: undefined,
112
- min: undefined,
113
- max: undefined,
114
- optional: undefined,
115
- matches: () => factory.keywordTypeNodes.string,
116
- email: () => factory.keywordTypeNodes.string,
117
- firstName: undefined,
118
- lastName: undefined,
119
- password: undefined,
120
- phone: undefined,
121
- readOnly: undefined,
122
- writeOnly: undefined,
123
- ref: (propertyName?: string) => {
124
- if (!propertyName) {
125
- return undefined
126
- }
127
-
128
- return factory.createTypeReferenceNode(propertyName, undefined)
129
- },
130
- blob: () => factory.createTypeReferenceNode('Blob', []),
131
- deprecated: undefined,
132
- example: undefined,
133
- schema: undefined,
134
- catchall: undefined,
135
- name: undefined,
136
- interface: undefined,
137
- exclusiveMaximum: undefined,
138
- exclusiveMinimum: undefined,
139
- } satisfies SchemaMapper<ts.TypeNode | null | undefined>
140
-
141
- type ParserOptions = {
142
- /**
143
- * @default `'questionToken'`
144
- */
145
- optionalType: 'questionToken' | 'undefined' | 'questionTokenAndUndefined'
146
- /**
147
- * @default `'array'`
148
- */
149
- arrayType: 'array' | 'generic'
150
- /**
151
- * Choose to use `enum`, `asConst`, `asPascalConst`, `constEnum`, `literal`, or `inlineLiteral` for enums.
152
- * - `enum`: TypeScript enum
153
- * - `asConst`: const with camelCase name (e.g., `petType`)
154
- * - `asPascalConst`: const with PascalCase name (e.g., `PetType`)
155
- * - `constEnum`: const enum
156
- * - `literal`: literal union type
157
- * - `inlineLiteral`: inline enum values directly into the type (default in v5)
158
- * @default `'asConst'`
159
- * @note In Kubb v5, `inlineLiteral` becomes the default.
160
- */
161
- enumType: 'enum' | 'asConst' | 'asPascalConst' | 'constEnum' | 'literal' | 'inlineLiteral'
162
- mapper?: Record<string, ts.PropertySignature>
163
- }
164
-
165
- /**
166
- * Recursively parses a schema tree node into a corresponding TypeScript AST node.
167
- *
168
- * Maps OpenAPI schema keywords to TypeScript AST nodes using the `typeKeywordMapper`, handling complex types such as unions, intersections, arrays, tuples (with optional/rest elements and length constraints), enums, constants, references, and objects with property modifiers and documentation annotations.
169
- *
170
- * @param current - The schema node to parse.
171
- * @param siblings - Sibling schema nodes, used for context in certain mappings.
172
- * @param name - The name of the schema or property being parsed.
173
- * @param options - Parsing options controlling output style, property handling, and custom mappers.
174
- * @returns The generated TypeScript AST node, or `undefined` if the schema keyword is not mapped.
175
- */
176
- export const parse = createParser<ts.Node | null, ParserOptions>({
177
- mapper: typeKeywordMapper,
178
- handlers: {
179
- union(tree, options) {
180
- const { current, schema, name } = tree
181
-
182
- return typeKeywordMapper.union(
183
- current.args.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
184
- )
185
- },
186
- and(tree, options) {
187
- const { current, schema, name } = tree
188
-
189
- return typeKeywordMapper.and(
190
- current.args.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
191
- )
192
- },
193
- array(tree, options) {
194
- const { current, schema, name } = tree
195
-
196
- return typeKeywordMapper.array(
197
- current.args.items.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
198
- options.arrayType,
199
- )
200
- },
201
- enum(tree, options) {
202
- const { current } = tree
203
-
204
- // If enumType is 'inlineLiteral', generate the literal union inline instead of a type reference
205
- if (options.enumType === 'inlineLiteral') {
206
- const enumValues = current.args.items
207
- .map((item) => item.value)
208
- .filter((value): value is string | number | boolean => value !== undefined && value !== null)
209
- .map((value) => {
210
- const format = typeof value === 'number' ? 'number' : typeof value === 'boolean' ? 'boolean' : 'string'
211
- return typeKeywordMapper.const(value, format)
212
- })
213
- .filter(Boolean) as ts.TypeNode[]
214
-
215
- return typeKeywordMapper.union(enumValues)
216
- }
217
-
218
- // Adding suffix to enum (see https://github.com/kubb-labs/kubb/issues/1873)
219
- return typeKeywordMapper.enum(['asConst', 'asPascalConst'].includes(options.enumType) ? `${current.args.typeName}Key` : current.args.typeName)
220
- },
221
- ref(tree, _options) {
222
- const { current } = tree
223
-
224
- return typeKeywordMapper.ref(current.args.name)
225
- },
226
- blob() {
227
- return typeKeywordMapper.blob()
228
- },
229
- tuple(tree, options) {
230
- const { current, schema, name } = tree
231
-
232
- return typeKeywordMapper.tuple(
233
- current.args.items.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
234
- current.args.rest &&
235
- ((this.parse({ schema, parent: current, name, current: current.args.rest, siblings: [] }, options) ?? undefined) as ts.TypeNode | undefined),
236
- current.args.min,
237
- current.args.max,
238
- )
239
- },
240
- const(tree, _options) {
241
- const { current } = tree
242
-
243
- return typeKeywordMapper.const(current.args.name, current.args.format)
244
- },
245
- object(tree, options) {
246
- const { current, schema, name } = tree
247
-
248
- const properties = Object.entries(current.args?.properties || {})
249
- .filter((item) => {
250
- const schemas = item[1]
251
- return schemas && typeof schemas.map === 'function'
252
- })
253
- .map(([name, schemas]) => {
254
- const nameSchema = schemas.find((schema) => schema.keyword === schemaKeywords.name) as SchemaKeywordMapper['name']
255
- const mappedName = nameSchema?.args || name
256
-
257
- // custom mapper(pluginOptions)
258
- // Use Object.hasOwn to avoid matching inherited properties like 'toString', 'valueOf', etc.
259
- if (options.mapper && Object.hasOwn(options.mapper, mappedName)) {
260
- return options.mapper[mappedName]
261
- }
262
-
263
- const isNullish = schemas.some((schema) => schema.keyword === schemaKeywords.nullish)
264
- const isNullable = schemas.some((schema) => schema.keyword === schemaKeywords.nullable)
265
- const isOptional = schemas.some((schema) => schema.keyword === schemaKeywords.optional)
266
- const isReadonly = schemas.some((schema) => schema.keyword === schemaKeywords.readOnly)
267
- const describeSchema = schemas.find((schema) => schema.keyword === schemaKeywords.describe) as SchemaKeywordMapper['describe'] | undefined
268
- const deprecatedSchema = schemas.find((schema) => schema.keyword === schemaKeywords.deprecated) as SchemaKeywordMapper['deprecated'] | undefined
269
- const defaultSchema = schemas.find((schema) => schema.keyword === schemaKeywords.default) as SchemaKeywordMapper['default'] | undefined
270
- const exampleSchema = schemas.find((schema) => schema.keyword === schemaKeywords.example) as SchemaKeywordMapper['example'] | undefined
271
- const schemaSchema = schemas.find((schema) => schema.keyword === schemaKeywords.schema) as SchemaKeywordMapper['schema'] | undefined
272
- const minSchema = schemas.find((schema) => schema.keyword === schemaKeywords.min) as SchemaKeywordMapper['min'] | undefined
273
- const maxSchema = schemas.find((schema) => schema.keyword === schemaKeywords.max) as SchemaKeywordMapper['max'] | undefined
274
- const matchesSchema = schemas.find((schema) => schema.keyword === schemaKeywords.matches) as SchemaKeywordMapper['matches'] | undefined
275
-
276
- let type = schemas
277
- .map((it) =>
278
- this.parse(
279
- {
280
- schema,
281
- parent: current,
282
- name,
283
- current: it,
284
- siblings: schemas,
285
- },
286
- options,
287
- ),
288
- )
289
- .filter(Boolean)[0] as ts.TypeNode
290
-
291
- if (isNullable) {
292
- type = factory.createUnionDeclaration({
293
- nodes: [type, factory.keywordTypeNodes.null],
294
- }) as ts.TypeNode
295
- }
296
-
297
- if (isNullish && ['undefined', 'questionTokenAndUndefined'].includes(options.optionalType as string)) {
298
- type = factory.createUnionDeclaration({
299
- nodes: [type, factory.keywordTypeNodes.undefined],
300
- }) as ts.TypeNode
301
- }
302
-
303
- if (isOptional && ['undefined', 'questionTokenAndUndefined'].includes(options.optionalType as string)) {
304
- type = factory.createUnionDeclaration({
305
- nodes: [type, factory.keywordTypeNodes.undefined],
306
- }) as ts.TypeNode
307
- }
308
-
309
- const propertyNode = factory.createPropertySignature({
310
- questionToken: isOptional || isNullish ? ['questionToken', 'questionTokenAndUndefined'].includes(options.optionalType as string) : false,
311
- name: mappedName,
312
- type,
313
- readOnly: isReadonly,
314
- })
315
-
316
- return factory.appendJSDocToNode({
317
- node: propertyNode,
318
- comments: [
319
- describeSchema ? `@description ${jsStringEscape(describeSchema.args)}` : undefined,
320
- deprecatedSchema ? '@deprecated' : undefined,
321
- minSchema ? `@minLength ${minSchema.args}` : undefined,
322
- maxSchema ? `@maxLength ${maxSchema.args}` : undefined,
323
- matchesSchema ? `@pattern ${matchesSchema.args}` : undefined,
324
- defaultSchema ? `@default ${defaultSchema.args}` : undefined,
325
- exampleSchema ? `@example ${exampleSchema.args}` : undefined,
326
- schemaSchema?.args?.type || schemaSchema?.args?.format
327
- ? [`@type ${schemaSchema?.args?.type || 'unknown'}${!isOptional ? '' : ' | undefined'}`, schemaSchema?.args?.format].filter(Boolean).join(', ')
328
- : undefined,
329
- ].filter(Boolean),
330
- })
331
- })
332
-
333
- let additionalProperties: any
334
-
335
- if (current.args?.additionalProperties?.length) {
336
- let additionalPropertiesType = current.args.additionalProperties
337
- .map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options))
338
- .filter(Boolean)
339
- .at(0) as ts.TypeNode
340
-
341
- const isNullable = current.args?.additionalProperties.some((schema) => isKeyword(schema, schemaKeywords.nullable))
342
- if (isNullable) {
343
- additionalPropertiesType = factory.createUnionDeclaration({
344
- nodes: [additionalPropertiesType, factory.keywordTypeNodes.null],
345
- }) as ts.TypeNode
346
- }
347
-
348
- // When there are typed properties alongside additionalProperties, use 'unknown' type
349
- // for the index signature to avoid TS2411 errors (index signature type conflicts with property types).
350
- // This occurs commonly in QueryParams where some params are typed (enums, objects) and
351
- // others are dynamic (additionalProperties with explode=true).
352
- const hasTypedProperties = properties.length > 0
353
- const indexSignatureType = hasTypedProperties ? factory.keywordTypeNodes.unknown : additionalPropertiesType
354
-
355
- additionalProperties = factory.createIndexSignature(indexSignatureType)
356
- }
357
-
358
- let patternProperties: ts.TypeNode | ts.IndexSignatureDeclaration | undefined
359
-
360
- if (current.args?.patternProperties) {
361
- const allPatternSchemas = Object.values(current.args.patternProperties).flat()
362
-
363
- if (allPatternSchemas.length > 0) {
364
- patternProperties = allPatternSchemas
365
- .map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options))
366
- .filter(Boolean)
367
- .at(0) as ts.TypeNode
368
-
369
- const isNullable = allPatternSchemas.some((schema) => isKeyword(schema, schemaKeywords.nullable))
370
- if (isNullable) {
371
- patternProperties = factory.createUnionDeclaration({
372
- nodes: [patternProperties, factory.keywordTypeNodes.null],
373
- }) as ts.TypeNode
374
- }
375
-
376
- patternProperties = factory.createIndexSignature(patternProperties)
377
- }
378
- }
379
-
380
- return typeKeywordMapper.object([...properties, additionalProperties, patternProperties].filter(Boolean))
381
- },
382
- datetime() {
383
- return typeKeywordMapper.datetime()
384
- },
385
- date(tree) {
386
- const { current } = tree
387
-
388
- return typeKeywordMapper.date(current.args.type)
389
- },
390
- time(tree) {
391
- const { current } = tree
392
-
393
- return typeKeywordMapper.time(current.args.type)
394
- },
395
- },
396
- })