@kubb/plugin-ts 5.0.0-alpha.9 → 5.0.0-beta.3
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/LICENSE +17 -10
- package/README.md +1 -3
- package/dist/index.cjs +1452 -5
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +558 -27
- package/dist/index.js +1418 -2
- package/dist/index.js.map +1 -0
- package/package.json +44 -64
- package/src/components/{v2/Enum.tsx → Enum.tsx} +33 -17
- package/src/components/Type.tsx +31 -161
- package/src/constants.ts +10 -0
- package/src/factory.ts +283 -35
- package/src/generators/typeGenerator.tsx +189 -424
- package/src/index.ts +9 -3
- package/src/plugin.ts +66 -205
- package/src/printers/functionPrinter.ts +197 -0
- package/src/printers/printerTs.ts +325 -0
- package/src/resolvers/resolverTs.ts +66 -0
- package/src/types.ts +233 -221
- package/src/utils.ts +130 -0
- package/dist/components-CRu8IKY3.js +0 -729
- package/dist/components-CRu8IKY3.js.map +0 -1
- package/dist/components-DeNDKlzf.cjs +0 -982
- package/dist/components-DeNDKlzf.cjs.map +0 -1
- package/dist/components.cjs +0 -3
- package/dist/components.d.ts +0 -36
- package/dist/components.js +0 -2
- package/dist/generators.cjs +0 -4
- package/dist/generators.d.ts +0 -509
- package/dist/generators.js +0 -2
- package/dist/plugin-BZkBwnEA.js +0 -1269
- package/dist/plugin-BZkBwnEA.js.map +0 -1
- package/dist/plugin-Bunz1oGa.cjs +0 -1322
- package/dist/plugin-Bunz1oGa.cjs.map +0 -1
- package/dist/types-mSXmB8WU.d.ts +0 -298
- package/src/components/index.ts +0 -1
- package/src/components/v2/Type.tsx +0 -59
- package/src/generators/index.ts +0 -2
- package/src/generators/v2/typeGenerator.tsx +0 -167
- package/src/generators/v2/utils.ts +0 -140
- package/src/parser.ts +0 -389
- package/src/printer.ts +0 -368
- package/src/resolverTs.ts +0 -77
package/src/factory.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { camelCase, pascalCase, screamingSnakeCase, snakeCase } from '@internals/utils'
|
|
2
|
+
import { ast } from '@kubb/core'
|
|
2
3
|
import { isNumber, sortBy } from 'remeda'
|
|
3
4
|
import ts from 'typescript'
|
|
5
|
+
import { OPTIONAL_ADDS_UNDEFINED } from './constants.ts'
|
|
4
6
|
|
|
5
7
|
const { SyntaxKind, factory } = ts
|
|
6
8
|
|
|
7
9
|
// https://ts-ast-viewer.com/
|
|
8
10
|
|
|
11
|
+
/**
|
|
12
|
+
* TypeScript AST modifiers for common keywords (async, export, const, static).
|
|
13
|
+
*/
|
|
9
14
|
export const modifiers = {
|
|
10
15
|
async: factory.createModifier(ts.SyntaxKind.AsyncKeyword),
|
|
11
16
|
export: factory.createModifier(ts.SyntaxKind.ExportKeyword),
|
|
@@ -13,22 +18,15 @@ export const modifiers = {
|
|
|
13
18
|
static: factory.createModifier(ts.SyntaxKind.StaticKeyword),
|
|
14
19
|
} as const
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* TypeScript syntax kind constants for union, literal, and string types.
|
|
23
|
+
*/
|
|
16
24
|
export const syntaxKind = {
|
|
17
25
|
union: SyntaxKind.UnionType as 192,
|
|
18
26
|
literalType: SyntaxKind.LiteralType,
|
|
19
27
|
stringLiteral: SyntaxKind.StringLiteral,
|
|
20
28
|
} as const
|
|
21
29
|
|
|
22
|
-
export function getUnknownType(unknownType: 'any' | 'unknown' | 'void' | undefined) {
|
|
23
|
-
if (unknownType === 'any') {
|
|
24
|
-
return keywordTypeNodes.any
|
|
25
|
-
}
|
|
26
|
-
if (unknownType === 'void') {
|
|
27
|
-
return keywordTypeNodes.void
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return keywordTypeNodes.unknown
|
|
31
|
-
}
|
|
32
30
|
function isValidIdentifier(str: string): boolean {
|
|
33
31
|
if (!str.length || str.trim() !== str) {
|
|
34
32
|
return false
|
|
@@ -48,6 +46,10 @@ function propertyName(name: string | ts.PropertyName): ts.PropertyName {
|
|
|
48
46
|
|
|
49
47
|
const questionToken = factory.createToken(ts.SyntaxKind.QuestionToken)
|
|
50
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Creates a question token for optional type annotations.
|
|
51
|
+
* Pass `true` to use the cached token, or provide a pre-created token.
|
|
52
|
+
*/
|
|
51
53
|
export function createQuestionToken(token?: boolean | ts.QuestionToken) {
|
|
52
54
|
if (!token) {
|
|
53
55
|
return undefined
|
|
@@ -58,6 +60,10 @@ export function createQuestionToken(token?: boolean | ts.QuestionToken) {
|
|
|
58
60
|
return token
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Creates a TypeScript intersection type node from multiple type nodes.
|
|
65
|
+
* Returns the single node if only one is provided, or wraps in parentheses if requested.
|
|
66
|
+
*/
|
|
61
67
|
export function createIntersectionDeclaration({ nodes, withParentheses }: { nodes: Array<ts.TypeNode>; withParentheses?: boolean }): ts.TypeNode | null {
|
|
62
68
|
if (!nodes.length) {
|
|
63
69
|
return null
|
|
@@ -77,27 +83,15 @@ export function createIntersectionDeclaration({ nodes, withParentheses }: { node
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
86
|
+
* Creates a TypeScript array type node.
|
|
87
|
+
* Use `arrayType: 'array'` for bracket syntax (`T[]`), or `'generic'` for `Array<T>`.
|
|
88
|
+
*
|
|
89
|
+
* @example Array bracket syntax
|
|
90
|
+
* `createArrayDeclaration({ nodes: [stringType], arrayType: 'array' }) // → string[]`
|
|
91
|
+
*
|
|
92
|
+
* @example Generic Array syntax
|
|
93
|
+
* `createArrayDeclaration({ nodes: [stringType], arrayType: 'generic' }) // → Array<string>`
|
|
82
94
|
*/
|
|
83
|
-
export function createTupleDeclaration({ nodes, withParentheses }: { nodes: Array<ts.TypeNode>; withParentheses?: boolean }): ts.TypeNode | null {
|
|
84
|
-
if (!nodes.length) {
|
|
85
|
-
return null
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (nodes.length === 1) {
|
|
89
|
-
return nodes[0] || null
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const node = factory.createTupleTypeNode(nodes)
|
|
93
|
-
|
|
94
|
-
if (withParentheses) {
|
|
95
|
-
return factory.createParenthesizedType(node)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return node
|
|
99
|
-
}
|
|
100
|
-
|
|
101
95
|
export function createArrayDeclaration({ nodes, arrayType = 'array' }: { nodes: Array<ts.TypeNode>; arrayType?: 'array' | 'generic' }): ts.TypeNode | null {
|
|
102
96
|
if (!nodes.length) {
|
|
103
97
|
return factory.createTupleTypeNode([])
|
|
@@ -125,7 +119,8 @@ export function createArrayDeclaration({ nodes, arrayType = 'array' }: { nodes:
|
|
|
125
119
|
|
|
126
120
|
/**
|
|
127
121
|
* Minimum nodes length of 2
|
|
128
|
-
* @example
|
|
122
|
+
* @example Union type example
|
|
123
|
+
* `string | number`
|
|
129
124
|
*/
|
|
130
125
|
export function createUnionDeclaration({ nodes, withParentheses }: { nodes: Array<ts.TypeNode>; withParentheses?: boolean }): ts.TypeNode {
|
|
131
126
|
if (!nodes.length) {
|
|
@@ -145,6 +140,10 @@ export function createUnionDeclaration({ nodes, withParentheses }: { nodes: Arra
|
|
|
145
140
|
return node
|
|
146
141
|
}
|
|
147
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Creates a TypeScript property signature for object/interface members.
|
|
145
|
+
* Supports optional markers, readonly modifiers, and type annotations.
|
|
146
|
+
*/
|
|
148
147
|
export function createPropertySignature({
|
|
149
148
|
readOnly,
|
|
150
149
|
modifiers = [],
|
|
@@ -166,6 +165,9 @@ export function createPropertySignature({
|
|
|
166
165
|
)
|
|
167
166
|
}
|
|
168
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Creates a function parameter declaration with optional markers, rest parameters, and type annotations.
|
|
170
|
+
*/
|
|
169
171
|
export function createParameterSignature(
|
|
170
172
|
name: string | ts.BindingName,
|
|
171
173
|
{
|
|
@@ -186,6 +188,10 @@ export function createParameterSignature(
|
|
|
186
188
|
return factory.createParameterDeclaration(modifiers, dotDotDotToken, name, createQuestionToken(questionToken), type, initializer)
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Creates a JSDoc comment node from an array of comment strings.
|
|
193
|
+
* Returns null if no comments are provided.
|
|
194
|
+
*/
|
|
189
195
|
export function createJSDoc({ comments }: { comments: string[] }) {
|
|
190
196
|
if (!comments.length) {
|
|
191
197
|
return null
|
|
@@ -204,7 +210,10 @@ export function createJSDoc({ comments }: { comments: string[] }) {
|
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
/**
|
|
207
|
-
*
|
|
213
|
+
* Attaches JSDoc comments to an AST node as synthetic leading comments.
|
|
214
|
+
* Filters out undefined comments before attaching.
|
|
215
|
+
*
|
|
216
|
+
* @see https://github.com/microsoft/TypeScript/issues/44151
|
|
208
217
|
*/
|
|
209
218
|
export function appendJSDocToNode<TNode extends ts.Node>({ node, comments }: { node: TNode; comments: Array<string | undefined> }) {
|
|
210
219
|
const filteredComments = comments.filter(Boolean)
|
|
@@ -222,6 +231,10 @@ export function appendJSDocToNode<TNode extends ts.Node>({ node, comments }: { n
|
|
|
222
231
|
return ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, `${text || '*'}\n`, true)
|
|
223
232
|
}
|
|
224
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Creates a TypeScript index signature for dynamic property access.
|
|
236
|
+
* Defines the key type (default: `string`) and value type on an object.
|
|
237
|
+
*/
|
|
225
238
|
export function createIndexSignature(
|
|
226
239
|
type: ts.TypeNode,
|
|
227
240
|
{
|
|
@@ -238,6 +251,9 @@ export function createIndexSignature(
|
|
|
238
251
|
return factory.createIndexSignature(modifiers, [createParameterSignature(indexName, { type: indexType })], type)
|
|
239
252
|
}
|
|
240
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Creates a TypeScript type alias declaration with optional modifiers and type parameters.
|
|
256
|
+
*/
|
|
241
257
|
export function createTypeAliasDeclaration({
|
|
242
258
|
modifiers,
|
|
243
259
|
name,
|
|
@@ -252,6 +268,9 @@ export function createTypeAliasDeclaration({
|
|
|
252
268
|
return factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type)
|
|
253
269
|
}
|
|
254
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Creates a TypeScript interface declaration with optional modifiers, type parameters, and members.
|
|
273
|
+
*/
|
|
255
274
|
export function createInterfaceDeclaration({
|
|
256
275
|
modifiers,
|
|
257
276
|
name,
|
|
@@ -266,6 +285,10 @@ export function createInterfaceDeclaration({
|
|
|
266
285
|
return factory.createInterfaceDeclaration(modifiers, name, typeParameters, undefined, members)
|
|
267
286
|
}
|
|
268
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Creates a TypeScript type declaration as either a type alias or interface.
|
|
290
|
+
* Intelligently selects the syntax based on the type structure and attaches JSDoc comments.
|
|
291
|
+
*/
|
|
269
292
|
export function createTypeDeclaration({
|
|
270
293
|
syntax,
|
|
271
294
|
isExportable,
|
|
@@ -281,7 +304,7 @@ export function createTypeDeclaration({
|
|
|
281
304
|
}) {
|
|
282
305
|
if (syntax === 'interface' && 'members' in type) {
|
|
283
306
|
const node = createInterfaceDeclaration({
|
|
284
|
-
members: type
|
|
307
|
+
members: [...(type as ts.TypeLiteralNode).members],
|
|
285
308
|
modifiers: isExportable ? [modifiers.export] : [],
|
|
286
309
|
name,
|
|
287
310
|
typeParameters: undefined,
|
|
@@ -306,6 +329,9 @@ export function createTypeDeclaration({
|
|
|
306
329
|
})
|
|
307
330
|
}
|
|
308
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Creates a TypeScript namespace declaration (exported module).
|
|
334
|
+
*/
|
|
309
335
|
export function createNamespaceDeclaration({ statements, name }: { name: string; statements: ts.Statement[] }) {
|
|
310
336
|
return factory.createModuleDeclaration(
|
|
311
337
|
[factory.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
@@ -316,8 +342,17 @@ export function createNamespaceDeclaration({ statements, name }: { name: string;
|
|
|
316
342
|
}
|
|
317
343
|
|
|
318
344
|
/**
|
|
319
|
-
*
|
|
320
|
-
*
|
|
345
|
+
* Creates an import declaration with support for default imports, named imports, namespace imports, and type-only imports.
|
|
346
|
+
* Optionally rename imported members with `propertyName` and `name` pairs.
|
|
347
|
+
*
|
|
348
|
+
* @example Default import
|
|
349
|
+
* `import Pet from './Pet'`
|
|
350
|
+
*
|
|
351
|
+
* @example Named imports with rename
|
|
352
|
+
* `import { Pet as Cat } from './Pet'`
|
|
353
|
+
*
|
|
354
|
+
* @example Namespace import
|
|
355
|
+
* `import * as Pet from './Pet'`
|
|
321
356
|
*/
|
|
322
357
|
export function createImportDeclaration({
|
|
323
358
|
name,
|
|
@@ -375,6 +410,10 @@ export function createImportDeclaration({
|
|
|
375
410
|
)
|
|
376
411
|
}
|
|
377
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Creates an export declaration with support for named exports, namespace exports, and type-only exports.
|
|
415
|
+
* Sorts export names alphabetically for consistent output across platforms.
|
|
416
|
+
*/
|
|
378
417
|
export function createExportDeclaration({
|
|
379
418
|
path,
|
|
380
419
|
asAlias,
|
|
@@ -440,6 +479,20 @@ function applyEnumKeyCasing(key: string, casing: 'screamingSnakeCase' | 'snakeCa
|
|
|
440
479
|
return key
|
|
441
480
|
}
|
|
442
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Creates a TypeScript enum declaration or equivalent construct in various formats.
|
|
484
|
+
* Returns a tuple of [name node, type node] - name node may be undefined for certain types.
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
* ```ts
|
|
488
|
+
* const [name, type] = createEnumDeclaration({
|
|
489
|
+
* type: 'enum',
|
|
490
|
+
* name: 'petType',
|
|
491
|
+
* typeName: 'PetType',
|
|
492
|
+
* enums: [['cat', 'cat'], ['dog', 'dog']],
|
|
493
|
+
* })
|
|
494
|
+
* ```
|
|
495
|
+
*/
|
|
443
496
|
export function createEnumDeclaration({
|
|
444
497
|
type = 'enum',
|
|
445
498
|
name,
|
|
@@ -626,6 +679,10 @@ export function createEnumDeclaration({
|
|
|
626
679
|
]
|
|
627
680
|
}
|
|
628
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Creates a TypeScript `Omit<T, Keys>` type reference node.
|
|
684
|
+
* Optionally wraps the type in `NonNullable<T>` if `nonNullable` is true.
|
|
685
|
+
*/
|
|
629
686
|
export function createOmitDeclaration({ keys, type, nonNullable }: { keys: Array<string> | string; type: ts.TypeNode; nonNullable?: boolean }) {
|
|
630
687
|
const node = nonNullable ? factory.createTypeReferenceNode(factory.createIdentifier('NonNullable'), [type]) : type
|
|
631
688
|
|
|
@@ -643,6 +700,10 @@ export function createOmitDeclaration({ keys, type, nonNullable }: { keys: Array
|
|
|
643
700
|
return factory.createTypeReferenceNode(factory.createIdentifier('Omit'), [node, factory.createLiteralTypeNode(factory.createStringLiteral(keys))])
|
|
644
701
|
}
|
|
645
702
|
|
|
703
|
+
/**
|
|
704
|
+
* Pre-built TypeScript keyword type nodes for common primitive types.
|
|
705
|
+
* Use these to avoid repeatedly creating the same type nodes.
|
|
706
|
+
*/
|
|
646
707
|
export const keywordTypeNodes = {
|
|
647
708
|
any: factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
|
|
648
709
|
unknown: factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
|
|
@@ -701,26 +762,213 @@ export function createUrlTemplateType(path: string): ts.TypeNode {
|
|
|
701
762
|
return ts.factory.createTemplateLiteralType(head, templateSpans)
|
|
702
763
|
}
|
|
703
764
|
|
|
765
|
+
/**
|
|
766
|
+
* Creates a TypeScript type literal node (anonymous object type).
|
|
767
|
+
*/
|
|
704
768
|
export const createTypeLiteralNode = factory.createTypeLiteralNode
|
|
705
769
|
|
|
770
|
+
/**
|
|
771
|
+
* Creates a TypeScript type reference node (e.g., `Array<string>`, `Record<K, V>`).
|
|
772
|
+
*/
|
|
706
773
|
export const createTypeReferenceNode = factory.createTypeReferenceNode
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Creates a numeric literal type node.
|
|
777
|
+
*/
|
|
707
778
|
export const createNumericLiteral = factory.createNumericLiteral
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Creates a string literal type node.
|
|
782
|
+
*/
|
|
708
783
|
export const createStringLiteral = factory.createStringLiteral
|
|
709
784
|
|
|
785
|
+
/**
|
|
786
|
+
* Creates an array type node (e.g., `T[]`).
|
|
787
|
+
*/
|
|
710
788
|
export const createArrayTypeNode = factory.createArrayTypeNode
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Creates a parenthesized type node to control operator precedence.
|
|
792
|
+
*/
|
|
711
793
|
export const createParenthesizedType = factory.createParenthesizedType
|
|
712
794
|
|
|
795
|
+
/**
|
|
796
|
+
* Creates a literal type node (e.g., `'hello'`, `42`, `true`).
|
|
797
|
+
*/
|
|
713
798
|
export const createLiteralTypeNode = factory.createLiteralTypeNode
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Creates a null literal type node.
|
|
802
|
+
*/
|
|
714
803
|
export const createNull = factory.createNull
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Creates an identifier node.
|
|
807
|
+
*/
|
|
715
808
|
export const createIdentifier = factory.createIdentifier
|
|
716
809
|
|
|
810
|
+
/**
|
|
811
|
+
* Creates an optional type node (e.g., `T | undefined`).
|
|
812
|
+
*/
|
|
717
813
|
export const createOptionalTypeNode = factory.createOptionalTypeNode
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Creates a tuple type node (e.g., `[string, number]`).
|
|
817
|
+
*/
|
|
718
818
|
export const createTupleTypeNode = factory.createTupleTypeNode
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Creates a rest type node for variadic tuple elements (e.g., `...T[]`).
|
|
822
|
+
*/
|
|
719
823
|
export const createRestTypeNode = factory.createRestTypeNode
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Creates a boolean true literal type node.
|
|
827
|
+
*/
|
|
720
828
|
export const createTrue = factory.createTrue
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Creates a boolean false literal type node.
|
|
832
|
+
*/
|
|
721
833
|
export const createFalse = factory.createFalse
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Creates an indexed access type node (e.g., `T[K]`).
|
|
837
|
+
*/
|
|
722
838
|
export const createIndexedAccessTypeNode = factory.createIndexedAccessTypeNode
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Creates a type operator node (e.g., `keyof T`, `readonly T[]`).
|
|
842
|
+
*/
|
|
723
843
|
export const createTypeOperatorNode = factory.createTypeOperatorNode
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Creates a prefix unary expression (e.g., negative numbers, logical not).
|
|
847
|
+
*/
|
|
724
848
|
export const createPrefixUnaryExpression = factory.createPrefixUnaryExpression
|
|
725
849
|
|
|
850
|
+
/**
|
|
851
|
+
* Exports TypeScript SyntaxKind enum for AST node type checking.
|
|
852
|
+
*/
|
|
726
853
|
export { SyntaxKind }
|
|
854
|
+
|
|
855
|
+
// ─── Printer helpers ──────────────────────────────────────────────────────────
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Converts a primitive const value to a TypeScript literal type node.
|
|
859
|
+
* Handles negative numbers via a prefix unary expression.
|
|
860
|
+
*/
|
|
861
|
+
export function constToTypeNode(value: string | number | boolean, format: 'string' | 'number' | 'boolean'): ts.TypeNode | undefined {
|
|
862
|
+
if (format === 'boolean') {
|
|
863
|
+
return createLiteralTypeNode(value === true ? createTrue() : createFalse())
|
|
864
|
+
}
|
|
865
|
+
if (format === 'number' && typeof value === 'number') {
|
|
866
|
+
if (value < 0) {
|
|
867
|
+
return createLiteralTypeNode(createPrefixUnaryExpression(SyntaxKind.MinusToken, createNumericLiteral(Math.abs(value))))
|
|
868
|
+
}
|
|
869
|
+
return createLiteralTypeNode(createNumericLiteral(value))
|
|
870
|
+
}
|
|
871
|
+
return createLiteralTypeNode(createStringLiteral(String(value)))
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
|
|
876
|
+
*/
|
|
877
|
+
export function dateOrStringNode(node: { representation?: string }): ts.TypeNode {
|
|
878
|
+
return node.representation === 'date' ? createTypeReferenceNode(createIdentifier('Date')) : keywordTypeNodes.string
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
|
|
883
|
+
*/
|
|
884
|
+
export function buildMemberNodes(
|
|
885
|
+
members: Array<ast.SchemaNode> | undefined,
|
|
886
|
+
print: (node: ast.SchemaNode) => ts.TypeNode | null | undefined,
|
|
887
|
+
): Array<ts.TypeNode> {
|
|
888
|
+
return (members ?? []).map(print).filter(Boolean)
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Builds a TypeScript tuple type node from an array schema's `items`,
|
|
893
|
+
* applying min/max slice and optional/rest element rules.
|
|
894
|
+
*/
|
|
895
|
+
export function buildTupleNode(node: ast.ArraySchemaNode, print: (node: ast.SchemaNode) => ts.TypeNode | null | undefined): ts.TypeNode | undefined {
|
|
896
|
+
let items = (node.items ?? []).map(print).filter(Boolean)
|
|
897
|
+
|
|
898
|
+
const restNode = node.rest ? (print(node.rest) ?? undefined) : undefined
|
|
899
|
+
const { min, max } = node
|
|
900
|
+
|
|
901
|
+
if (max !== undefined) {
|
|
902
|
+
items = items.slice(0, max)
|
|
903
|
+
if (items.length < max && restNode) {
|
|
904
|
+
items = [...items, ...Array(max - items.length).fill(restNode)]
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
if (min !== undefined) {
|
|
909
|
+
items = items.map((item, i) => (i >= min ? createOptionalTypeNode(item) : item))
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (max === undefined && restNode) {
|
|
913
|
+
items.push(createRestTypeNode(createArrayTypeNode(restNode)))
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
return createTupleTypeNode(items)
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
|
|
921
|
+
*/
|
|
922
|
+
export function buildPropertyType(
|
|
923
|
+
schema: ast.SchemaNode,
|
|
924
|
+
baseType: ts.TypeNode,
|
|
925
|
+
optionalType: 'questionToken' | 'undefined' | 'questionTokenAndUndefined',
|
|
926
|
+
): ts.TypeNode {
|
|
927
|
+
const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType)
|
|
928
|
+
const meta = ast.syncSchemaRef(schema)
|
|
929
|
+
|
|
930
|
+
let type = baseType
|
|
931
|
+
|
|
932
|
+
if (meta.nullable) {
|
|
933
|
+
type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] })
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if ((meta.nullish || meta.optional) && addsUndefined) {
|
|
937
|
+
type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] })
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
return type
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Creates TypeScript index signatures for `additionalProperties` and `patternProperties` on an object schema node.
|
|
945
|
+
*/
|
|
946
|
+
export function buildIndexSignatures(
|
|
947
|
+
node: { additionalProperties?: ast.SchemaNode | boolean; patternProperties?: Record<string, ast.SchemaNode> },
|
|
948
|
+
propertyCount: number,
|
|
949
|
+
print: (node: ast.SchemaNode) => ts.TypeNode | null | undefined,
|
|
950
|
+
): Array<ts.TypeElement> {
|
|
951
|
+
const elements: Array<ts.TypeElement> = []
|
|
952
|
+
|
|
953
|
+
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
954
|
+
const additionalType = print(node.additionalProperties) ?? keywordTypeNodes.unknown
|
|
955
|
+
|
|
956
|
+
elements.push(createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : additionalType))
|
|
957
|
+
} else if (node.additionalProperties === true) {
|
|
958
|
+
elements.push(createIndexSignature(keywordTypeNodes.unknown))
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if (node.patternProperties) {
|
|
962
|
+
const first = Object.values(node.patternProperties)[0]
|
|
963
|
+
if (first) {
|
|
964
|
+
let patternType = print(first) ?? keywordTypeNodes.unknown
|
|
965
|
+
|
|
966
|
+
if (first.nullable) {
|
|
967
|
+
patternType = createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] })
|
|
968
|
+
}
|
|
969
|
+
elements.push(createIndexSignature(patternType))
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
return elements
|
|
974
|
+
}
|