@kubb/plugin-ts 5.0.0-alpha.24 → 5.0.0-alpha.25
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/index.cjs +468 -473
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.js +472 -477
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/components/Enum.tsx +1 -1
- package/src/constants.ts +10 -0
- package/src/factory.ts +122 -1
- package/src/generators/typeGenerator.tsx +107 -108
- package/src/generators/typeGeneratorLegacy.tsx +85 -80
- package/src/index.ts +0 -5
- package/src/plugin.ts +19 -49
- package/src/printers/functionPrinter.ts +6 -5
- package/src/printers/printerTs.ts +49 -181
- package/src/resolvers/resolverTs.ts +2 -2
- package/src/types.ts +6 -4
- package/src/utils.ts +41 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-ts",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.25",
|
|
4
4
|
"description": "TypeScript code generation plugin for Kubb, transforming OpenAPI schemas into TypeScript interfaces, types, and utility functions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@kubb/fabric-core": "0.15.1",
|
|
53
53
|
"@kubb/react-fabric": "0.15.1",
|
|
54
|
-
"remeda": "^2.33.
|
|
54
|
+
"remeda": "^2.33.7",
|
|
55
55
|
"typescript": "5.9.3",
|
|
56
|
-
"@kubb/ast": "5.0.0-alpha.
|
|
57
|
-
"@kubb/core": "5.0.0-alpha.
|
|
56
|
+
"@kubb/ast": "5.0.0-alpha.25",
|
|
57
|
+
"@kubb/core": "5.0.0-alpha.25"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@kubb/react-fabric": "0.15.1"
|
package/src/components/Enum.tsx
CHANGED
|
@@ -62,7 +62,7 @@ export function Enum({ node, enumType, enumTypeSuffix, enumKeyCasing, resolver }
|
|
|
62
62
|
typeName,
|
|
63
63
|
enums: (node.namedEnumValues?.map((v) => [trimQuotes(v.name.toString()), v.value]) ??
|
|
64
64
|
node.enumValues?.filter((v): v is NonNullable<typeof v> => v !== null && v !== undefined).map((v) => [trimQuotes(v.toString()), v]) ??
|
|
65
|
-
[]) as
|
|
65
|
+
[]) as Array<[string | number, string | number | boolean]>,
|
|
66
66
|
type: enumType,
|
|
67
67
|
enumKeyCasing,
|
|
68
68
|
})
|
package/src/constants.ts
CHANGED
|
@@ -27,3 +27,13 @@ export const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set<EnumType | undefined>(['enu
|
|
|
27
27
|
* `enumType` values whose type declaration is type-only (no runtime value emitted for the type alias).
|
|
28
28
|
*/
|
|
29
29
|
export const ENUM_TYPES_WITH_TYPE_ONLY = new Set<EnumType | undefined>(['asConst', 'asPascalConst', 'literal', undefined] as const)
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Ordering priority for function parameters: lower = sorted earlier.
|
|
33
|
+
*/
|
|
34
|
+
export const PARAM_RANK = {
|
|
35
|
+
required: 0,
|
|
36
|
+
optional: 1,
|
|
37
|
+
withDefault: 2,
|
|
38
|
+
rest: 3,
|
|
39
|
+
} as const
|
package/src/factory.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { camelCase, pascalCase, screamingSnakeCase, snakeCase } from '@internals/utils'
|
|
2
|
+
import { syncSchemaRef } from '@kubb/ast'
|
|
3
|
+
import type { ArraySchemaNode, SchemaNode } from '@kubb/ast/types'
|
|
2
4
|
import { isNumber, sortBy } from 'remeda'
|
|
3
5
|
import ts from 'typescript'
|
|
6
|
+
import { OPTIONAL_ADDS_UNDEFINED } from './constants.ts'
|
|
4
7
|
|
|
5
8
|
const { SyntaxKind, factory } = ts
|
|
6
9
|
|
|
@@ -249,7 +252,7 @@ export function createTypeDeclaration({
|
|
|
249
252
|
}) {
|
|
250
253
|
if (syntax === 'interface' && 'members' in type) {
|
|
251
254
|
const node = createInterfaceDeclaration({
|
|
252
|
-
members: type
|
|
255
|
+
members: [...(type as ts.TypeLiteralNode).members],
|
|
253
256
|
modifiers: isExportable ? [modifiers.export] : [],
|
|
254
257
|
name,
|
|
255
258
|
typeParameters: undefined,
|
|
@@ -692,3 +695,121 @@ export const createTypeOperatorNode = factory.createTypeOperatorNode
|
|
|
692
695
|
export const createPrefixUnaryExpression = factory.createPrefixUnaryExpression
|
|
693
696
|
|
|
694
697
|
export { SyntaxKind }
|
|
698
|
+
|
|
699
|
+
// ─── Printer helpers ──────────────────────────────────────────────────────────
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Converts a primitive const value to a TypeScript literal type node.
|
|
703
|
+
* Handles negative numbers via a prefix unary expression.
|
|
704
|
+
*/
|
|
705
|
+
export function constToTypeNode(value: string | number | boolean, format: 'string' | 'number' | 'boolean'): ts.TypeNode | undefined {
|
|
706
|
+
if (format === 'boolean') {
|
|
707
|
+
return createLiteralTypeNode(value === true ? createTrue() : createFalse())
|
|
708
|
+
}
|
|
709
|
+
if (format === 'number' && typeof value === 'number') {
|
|
710
|
+
if (value < 0) {
|
|
711
|
+
return createLiteralTypeNode(createPrefixUnaryExpression(SyntaxKind.MinusToken, createNumericLiteral(Math.abs(value))))
|
|
712
|
+
}
|
|
713
|
+
return createLiteralTypeNode(createNumericLiteral(value))
|
|
714
|
+
}
|
|
715
|
+
return createLiteralTypeNode(createStringLiteral(String(value)))
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
|
|
720
|
+
*/
|
|
721
|
+
export function dateOrStringNode(node: { representation?: string }): ts.TypeNode {
|
|
722
|
+
return node.representation === 'date' ? createTypeReferenceNode(createIdentifier('Date')) : keywordTypeNodes.string
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
|
|
727
|
+
*/
|
|
728
|
+
export function buildMemberNodes(members: Array<SchemaNode> | undefined, print: (node: SchemaNode) => ts.TypeNode | null | undefined): Array<ts.TypeNode> {
|
|
729
|
+
return (members ?? []).map(print).filter(Boolean)
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Builds a TypeScript tuple type node from an array schema's `items`,
|
|
734
|
+
* applying min/max slice and optional/rest element rules.
|
|
735
|
+
*/
|
|
736
|
+
export function buildTupleNode(node: ArraySchemaNode, print: (node: SchemaNode) => ts.TypeNode | null | undefined): ts.TypeNode | undefined {
|
|
737
|
+
let items = (node.items ?? []).map(print).filter(Boolean)
|
|
738
|
+
|
|
739
|
+
const restNode = node.rest ? (print(node.rest) ?? undefined) : undefined
|
|
740
|
+
const { min, max } = node
|
|
741
|
+
|
|
742
|
+
if (max !== undefined) {
|
|
743
|
+
items = items.slice(0, max)
|
|
744
|
+
if (items.length < max && restNode) {
|
|
745
|
+
items = [...items, ...Array(max - items.length).fill(restNode)]
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (min !== undefined) {
|
|
750
|
+
items = items.map((item, i) => (i >= min ? createOptionalTypeNode(item) : item))
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
if (max === undefined && restNode) {
|
|
754
|
+
items.push(createRestTypeNode(createArrayTypeNode(restNode)))
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
return createTupleTypeNode(items)
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
|
|
762
|
+
*/
|
|
763
|
+
export function buildPropertyType(
|
|
764
|
+
schema: SchemaNode,
|
|
765
|
+
baseType: ts.TypeNode,
|
|
766
|
+
optionalType: 'questionToken' | 'undefined' | 'questionTokenAndUndefined',
|
|
767
|
+
): ts.TypeNode {
|
|
768
|
+
const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType)
|
|
769
|
+
const meta = syncSchemaRef(schema)
|
|
770
|
+
|
|
771
|
+
let type = baseType
|
|
772
|
+
|
|
773
|
+
if (meta.nullable) {
|
|
774
|
+
type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] })
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if ((meta.nullish || meta.optional) && addsUndefined) {
|
|
778
|
+
type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] })
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
return type
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Creates TypeScript index signatures for `additionalProperties` and `patternProperties` on an object schema node.
|
|
786
|
+
*/
|
|
787
|
+
export function buildIndexSignatures(
|
|
788
|
+
node: { additionalProperties?: SchemaNode | boolean; patternProperties?: Record<string, SchemaNode> },
|
|
789
|
+
propertyCount: number,
|
|
790
|
+
print: (node: SchemaNode) => ts.TypeNode | null | undefined,
|
|
791
|
+
): Array<ts.TypeElement> {
|
|
792
|
+
const elements: Array<ts.TypeElement> = []
|
|
793
|
+
|
|
794
|
+
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
795
|
+
const additionalType = print(node.additionalProperties) ?? keywordTypeNodes.unknown
|
|
796
|
+
|
|
797
|
+
elements.push(createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : additionalType))
|
|
798
|
+
} else if (node.additionalProperties === true) {
|
|
799
|
+
elements.push(createIndexSignature(keywordTypeNodes.unknown))
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
if (node.patternProperties) {
|
|
803
|
+
const first = Object.values(node.patternProperties)[0]
|
|
804
|
+
if (first) {
|
|
805
|
+
let patternType = print(first) ?? keywordTypeNodes.unknown
|
|
806
|
+
|
|
807
|
+
if (first.nullable) {
|
|
808
|
+
patternType = createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] })
|
|
809
|
+
}
|
|
810
|
+
elements.push(createIndexSignature(patternType))
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
return elements
|
|
815
|
+
}
|
|
@@ -11,15 +11,86 @@ import { buildData, buildResponses, buildResponseUnion } from '../utils.ts'
|
|
|
11
11
|
export const typeGenerator = defineGenerator<PluginTs>({
|
|
12
12
|
name: 'typescript',
|
|
13
13
|
type: 'react',
|
|
14
|
+
Schema({ node, adapter, options, config, resolver }) {
|
|
15
|
+
const { enumType, enumTypeSuffix, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, transformers = [] } = options
|
|
16
|
+
|
|
17
|
+
const transformedNode = transform(node, composeTransformers(...transformers))
|
|
18
|
+
|
|
19
|
+
if (!transformedNode.name) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const root = path.resolve(config.root, config.output.path)
|
|
24
|
+
const mode = getMode(path.resolve(root, output.path))
|
|
25
|
+
// Build a set of schema names that are enums so the ref handler and getImports
|
|
26
|
+
// callback can use the suffixed type name (e.g. `StatusKey`) for those refs.
|
|
27
|
+
const enumSchemaNames = new Set((adapter.rootNode?.schemas ?? []).filter((s) => narrowSchema(s, schemaTypes.enum) && s.name).map((s) => s.name!))
|
|
28
|
+
|
|
29
|
+
function resolveImportName(schemaName: string): string {
|
|
30
|
+
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) {
|
|
31
|
+
return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix)
|
|
32
|
+
}
|
|
33
|
+
return resolver.default(schemaName, 'type')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const imports = adapter.getImports(transformedNode, (schemaName) => ({
|
|
37
|
+
name: resolveImportName(schemaName),
|
|
38
|
+
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
39
|
+
}))
|
|
40
|
+
|
|
41
|
+
const isEnumSchema = !!narrowSchema(transformedNode, schemaTypes.enum)
|
|
42
|
+
|
|
43
|
+
const meta = {
|
|
44
|
+
name:
|
|
45
|
+
ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema
|
|
46
|
+
? resolver.resolveEnumKeyName(transformedNode, enumTypeSuffix)
|
|
47
|
+
: resolver.resolveName(transformedNode.name),
|
|
48
|
+
file: resolver.resolveFile({ name: transformedNode.name, extname: '.ts' }, { root, output, group }),
|
|
49
|
+
} as const
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<File
|
|
53
|
+
baseName={meta.file.baseName}
|
|
54
|
+
path={meta.file.path}
|
|
55
|
+
meta={meta.file.meta}
|
|
56
|
+
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
57
|
+
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
58
|
+
>
|
|
59
|
+
{mode === 'split' &&
|
|
60
|
+
imports.map((imp) => (
|
|
61
|
+
<File.Import key={[transformedNode.name, imp.path, imp.isTypeOnly].join('-')} root={meta.file.path} path={imp.path} name={imp.name} isTypeOnly />
|
|
62
|
+
))}
|
|
63
|
+
<Type
|
|
64
|
+
name={meta.name}
|
|
65
|
+
node={transformedNode}
|
|
66
|
+
enumType={enumType}
|
|
67
|
+
enumTypeSuffix={enumTypeSuffix}
|
|
68
|
+
enumKeyCasing={enumKeyCasing}
|
|
69
|
+
optionalType={optionalType}
|
|
70
|
+
arrayType={arrayType}
|
|
71
|
+
syntaxType={syntaxType}
|
|
72
|
+
resolver={resolver}
|
|
73
|
+
enumSchemaNames={enumSchemaNames}
|
|
74
|
+
/>
|
|
75
|
+
</File>
|
|
76
|
+
)
|
|
77
|
+
},
|
|
14
78
|
Operation({ node, adapter, options, config, resolver }) {
|
|
15
79
|
const { enumType, enumTypeSuffix, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group, output, transformers = [] } = options
|
|
16
80
|
|
|
81
|
+
const transformedNode = transform(node, composeTransformers(...transformers))
|
|
82
|
+
|
|
17
83
|
const root = path.resolve(config.root, config.output.path)
|
|
18
84
|
const mode = getMode(path.resolve(root, output.path))
|
|
19
85
|
|
|
20
|
-
const
|
|
86
|
+
const params = caseParams(transformedNode.parameters, paramsCasing)
|
|
21
87
|
|
|
22
|
-
const
|
|
88
|
+
const meta = {
|
|
89
|
+
file: resolver.resolveFile(
|
|
90
|
+
{ name: transformedNode.operationId, extname: '.ts', tag: transformedNode.tags[0] ?? 'default', path: transformedNode.path },
|
|
91
|
+
{ root, output, group },
|
|
92
|
+
),
|
|
93
|
+
} as const
|
|
23
94
|
|
|
24
95
|
// Build a set of schema names that are enums so the ref handler and getImports
|
|
25
96
|
// callback can use the suffixed type name (e.g. `StatusKey`) for those refs.
|
|
@@ -27,29 +98,15 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
27
98
|
|
|
28
99
|
function resolveImportName(schemaName: string): string {
|
|
29
100
|
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) {
|
|
30
|
-
return resolver.resolveEnumKeyName({ name: schemaName }
|
|
101
|
+
return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix)
|
|
31
102
|
}
|
|
32
103
|
return resolver.default(schemaName, 'type')
|
|
33
104
|
}
|
|
34
105
|
|
|
35
|
-
function renderSchemaType({
|
|
36
|
-
|
|
37
|
-
name,
|
|
38
|
-
description,
|
|
39
|
-
keysToOmit,
|
|
40
|
-
}: {
|
|
41
|
-
node: SchemaNode | null
|
|
42
|
-
name: string
|
|
43
|
-
description?: string
|
|
44
|
-
keysToOmit?: Array<string>
|
|
45
|
-
}) {
|
|
46
|
-
if (!schemaNode) {
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
106
|
+
function renderSchemaType({ schema, name, keysToOmit }: { schema: SchemaNode | null; name: string; keysToOmit?: Array<string> }) {
|
|
107
|
+
if (!schema) return null
|
|
49
108
|
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const imports = adapter.getImports(transformedNode, (schemaName) => ({
|
|
109
|
+
const imports = adapter.getImports(schema, (schemaName) => ({
|
|
53
110
|
name: resolveImportName(schemaName),
|
|
54
111
|
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
55
112
|
}))
|
|
@@ -57,11 +114,12 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
57
114
|
return (
|
|
58
115
|
<>
|
|
59
116
|
{mode === 'split' &&
|
|
60
|
-
imports.map((imp) =>
|
|
117
|
+
imports.map((imp) => (
|
|
118
|
+
<File.Import key={[name, imp.path, imp.isTypeOnly].join('-')} root={meta.file.path} path={imp.path} name={imp.name} isTypeOnly />
|
|
119
|
+
))}
|
|
61
120
|
<Type
|
|
62
121
|
name={name}
|
|
63
|
-
node={
|
|
64
|
-
description={description}
|
|
122
|
+
node={schema}
|
|
65
123
|
enumType={enumType}
|
|
66
124
|
enumTypeSuffix={enumTypeSuffix}
|
|
67
125
|
enumKeyCasing={enumKeyCasing}
|
|
@@ -78,50 +136,55 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
78
136
|
|
|
79
137
|
const paramTypes = params.map((param) =>
|
|
80
138
|
renderSchemaType({
|
|
81
|
-
|
|
82
|
-
name: resolver.resolveParamName(
|
|
139
|
+
schema: param.schema,
|
|
140
|
+
name: resolver.resolveParamName(transformedNode, param),
|
|
83
141
|
}),
|
|
84
142
|
)
|
|
85
143
|
|
|
86
|
-
const requestType =
|
|
144
|
+
const requestType = transformedNode.requestBody?.schema
|
|
87
145
|
? renderSchemaType({
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
146
|
+
schema: {
|
|
147
|
+
...transformedNode.requestBody.schema,
|
|
148
|
+
description: transformedNode.requestBody.description ?? transformedNode.requestBody.schema.description,
|
|
149
|
+
},
|
|
150
|
+
name: resolver.resolveDataName(transformedNode),
|
|
151
|
+
keysToOmit: transformedNode.requestBody.keysToOmit,
|
|
92
152
|
})
|
|
93
153
|
: null
|
|
94
154
|
|
|
95
|
-
const responseTypes =
|
|
155
|
+
const responseTypes = transformedNode.responses.map((res) =>
|
|
96
156
|
renderSchemaType({
|
|
97
|
-
|
|
98
|
-
name: resolver.resolveResponseStatusName(
|
|
99
|
-
description: res.description,
|
|
157
|
+
schema: res.schema,
|
|
158
|
+
name: resolver.resolveResponseStatusName(transformedNode, res.statusCode),
|
|
100
159
|
keysToOmit: res.keysToOmit,
|
|
101
160
|
}),
|
|
102
161
|
)
|
|
103
162
|
|
|
104
163
|
const dataType = renderSchemaType({
|
|
105
|
-
|
|
106
|
-
name: resolver.resolveRequestConfigName(
|
|
164
|
+
schema: buildData({ ...transformedNode, parameters: params }, { resolver }),
|
|
165
|
+
name: resolver.resolveRequestConfigName(transformedNode),
|
|
107
166
|
})
|
|
108
167
|
|
|
109
168
|
const responsesType = renderSchemaType({
|
|
110
|
-
|
|
111
|
-
name: resolver.resolveResponsesName(
|
|
169
|
+
schema: buildResponses(transformedNode, { resolver }),
|
|
170
|
+
name: resolver.resolveResponsesName(transformedNode),
|
|
112
171
|
})
|
|
113
172
|
|
|
114
173
|
const responseType = renderSchemaType({
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
174
|
+
schema: transformedNode.responses.some((res) => res.schema)
|
|
175
|
+
? {
|
|
176
|
+
...buildResponseUnion(transformedNode, { resolver })!,
|
|
177
|
+
description: 'Union of all possible responses',
|
|
178
|
+
}
|
|
179
|
+
: null,
|
|
180
|
+
name: resolver.resolveResponseName(transformedNode),
|
|
118
181
|
})
|
|
119
182
|
|
|
120
183
|
return (
|
|
121
184
|
<File
|
|
122
|
-
baseName={file.baseName}
|
|
123
|
-
path={file.path}
|
|
124
|
-
meta={file.meta}
|
|
185
|
+
baseName={meta.file.baseName}
|
|
186
|
+
path={meta.file.path}
|
|
187
|
+
meta={meta.file.meta}
|
|
125
188
|
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
126
189
|
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
127
190
|
>
|
|
@@ -134,68 +197,4 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
134
197
|
</File>
|
|
135
198
|
)
|
|
136
199
|
},
|
|
137
|
-
Schema({ node, adapter, options, config, resolver }) {
|
|
138
|
-
const { enumType, enumTypeSuffix, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, transformers = [] } = options
|
|
139
|
-
|
|
140
|
-
const root = path.resolve(config.root, config.output.path)
|
|
141
|
-
const mode = getMode(path.resolve(root, output.path))
|
|
142
|
-
|
|
143
|
-
if (!node.name) {
|
|
144
|
-
return
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const transformedNode = transform(node, composeTransformers(...transformers))
|
|
148
|
-
|
|
149
|
-
// Build a set of schema names that are enums so the ref handler and getImports
|
|
150
|
-
// callback can use the suffixed type name (e.g. `StatusKey`) for those refs.
|
|
151
|
-
const enumSchemaNames = new Set((adapter.rootNode?.schemas ?? []).filter((s) => narrowSchema(s, schemaTypes.enum) && s.name).map((s) => s.name!))
|
|
152
|
-
|
|
153
|
-
function resolveImportName(schemaName: string): string {
|
|
154
|
-
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) {
|
|
155
|
-
return resolver.resolveEnumKeyName({ name: schemaName } as SchemaNode, enumTypeSuffix)
|
|
156
|
-
}
|
|
157
|
-
return resolver.default(schemaName, 'type')
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const imports = adapter.getImports(transformedNode, (schemaName) => ({
|
|
161
|
-
name: resolveImportName(schemaName),
|
|
162
|
-
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
163
|
-
}))
|
|
164
|
-
|
|
165
|
-
const isEnumSchema = !!narrowSchema(node, schemaTypes.enum)
|
|
166
|
-
|
|
167
|
-
const name = ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolver.resolveName(node.name)
|
|
168
|
-
|
|
169
|
-
const type = {
|
|
170
|
-
name,
|
|
171
|
-
file: resolver.resolveFile({ name: node.name, extname: '.ts' }, { root, output, group }),
|
|
172
|
-
} as const
|
|
173
|
-
|
|
174
|
-
return (
|
|
175
|
-
<File
|
|
176
|
-
baseName={type.file.baseName}
|
|
177
|
-
path={type.file.path}
|
|
178
|
-
meta={type.file.meta}
|
|
179
|
-
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
180
|
-
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
181
|
-
>
|
|
182
|
-
{mode === 'split' &&
|
|
183
|
-
imports.map((imp) => (
|
|
184
|
-
<File.Import key={[node.name, imp.path, imp.isTypeOnly].join('-')} root={type.file.path} path={imp.path} name={imp.name} isTypeOnly />
|
|
185
|
-
))}
|
|
186
|
-
<Type
|
|
187
|
-
name={type.name}
|
|
188
|
-
node={transformedNode}
|
|
189
|
-
enumType={enumType}
|
|
190
|
-
enumTypeSuffix={enumTypeSuffix}
|
|
191
|
-
enumKeyCasing={enumKeyCasing}
|
|
192
|
-
optionalType={optionalType}
|
|
193
|
-
arrayType={arrayType}
|
|
194
|
-
syntaxType={syntaxType}
|
|
195
|
-
resolver={resolver}
|
|
196
|
-
enumSchemaNames={enumSchemaNames}
|
|
197
|
-
/>
|
|
198
|
-
</File>
|
|
199
|
-
)
|
|
200
|
-
},
|
|
201
200
|
})
|