From d5ccbf85d0eeba9a621756651bcc6f4d20a7b01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Belli?= Date: Wed, 5 Feb 2025 17:08:13 +0100 Subject: [PATCH 1/3] fix(enum-values): access optional prop child props Fixes: #2138 --- packages/openapi-typescript/src/lib/ts.ts | 14 ++++++++++++-- .../src/transform/schema-object.ts | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/openapi-typescript/src/lib/ts.ts b/packages/openapi-typescript/src/lib/ts.ts index 3f795c60c..fb7d529e3 100644 --- a/packages/openapi-typescript/src/lib/ts.ts +++ b/packages/openapi-typescript/src/lib/ts.ts @@ -116,13 +116,13 @@ export function addJSDocComment(schemaObject: AnnotatedSchemaObject, node: ts.Pr } /** Convert OpenAPI ref into TS indexed access node (ex: `components["schemas"]["Foo"]`) */ -export function oapiRef(path: string): ts.TypeNode { +export function oapiRef(path: string, deepRequired = false): ts.TypeNode { const { pointer } = parseRef(path); if (pointer.length === 0) { throw new Error(`Error parsing $ref: ${path}. Is this a valid $ref?`); } let t: ts.TypeReferenceNode | ts.IndexedAccessTypeNode = ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier(String(pointer[0])), + ts.factory.createIdentifier(deepRequired ? `DeepRequired<${String(pointer[0])}>` : String(pointer[0])), ); if (pointer.length > 1) { for (let i = 1; i < pointer.length; i++) { @@ -251,6 +251,16 @@ export function tsArrayLiteralExpression( let variableName = sanitizeMemberName(name); variableName = `${variableName[0].toLowerCase()}${variableName.substring(1)}`; + if ( + options?.injectFooter && + !options.injectFooter.some((node) => ts.isTypeAliasDeclaration(node) && node?.name?.escapedText === "DeepRequired") + ) { + const helper = stringToAST( + "type DeepRequired = { [K in keyof T]: Required> };", + )[0] as any; + options.injectFooter.push(helper); + } + const arrayType = options?.readonly ? tsReadonlyArray(elementType, options.injectFooter) : ts.factory.createArrayTypeNode(elementType); diff --git a/packages/openapi-typescript/src/transform/schema-object.ts b/packages/openapi-typescript/src/transform/schema-object.ts index a41ce0e69..e45857702 100644 --- a/packages/openapi-typescript/src/transform/schema-object.ts +++ b/packages/openapi-typescript/src/transform/schema-object.ts @@ -148,7 +148,7 @@ export function transformSchemaObjectWithComposition( const enumValuesArray = tsArrayLiteralExpression( enumValuesVariableName, - oapiRef(options.path ?? ""), + oapiRef(options.path ?? "", true), schemaObject.enum as (string | number)[], { export: true, From 122f53f757e7667fcc19b454b2a8a66fc4db7e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Belli?= Date: Wed, 5 Feb 2025 17:39:03 +0100 Subject: [PATCH 2/3] fix(enum-values): access array props Fixes: #2140 --- packages/openapi-typescript/src/lib/ts.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/openapi-typescript/src/lib/ts.ts b/packages/openapi-typescript/src/lib/ts.ts index fb7d529e3..d07a1cfa3 100644 --- a/packages/openapi-typescript/src/lib/ts.ts +++ b/packages/openapi-typescript/src/lib/ts.ts @@ -116,13 +116,13 @@ export function addJSDocComment(schemaObject: AnnotatedSchemaObject, node: ts.Pr } /** Convert OpenAPI ref into TS indexed access node (ex: `components["schemas"]["Foo"]`) */ -export function oapiRef(path: string, deepRequired = false): ts.TypeNode { +export function oapiRef(path: string, deep = false): ts.TypeNode { const { pointer } = parseRef(path); if (pointer.length === 0) { throw new Error(`Error parsing $ref: ${path}. Is this a valid $ref?`); } let t: ts.TypeReferenceNode | ts.IndexedAccessTypeNode = ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier(deepRequired ? `DeepRequired<${String(pointer[0])}>` : String(pointer[0])), + ts.factory.createIdentifier(deep ? `FlattenedDeepRequired<${String(pointer[0])}>` : String(pointer[0])), ); if (pointer.length > 1) { for (let i = 1; i < pointer.length; i++) { @@ -253,10 +253,10 @@ export function tsArrayLiteralExpression( if ( options?.injectFooter && - !options.injectFooter.some((node) => ts.isTypeAliasDeclaration(node) && node?.name?.escapedText === "DeepRequired") + !options.injectFooter.some((node) => ts.isTypeAliasDeclaration(node) && node?.name?.escapedText === "FlattenedDeepRequired") ) { const helper = stringToAST( - "type DeepRequired = { [K in keyof T]: Required> };", + "type FlattenedDeepRequired = { [K in keyof T]: Required>; };", )[0] as any; options.injectFooter.push(helper); } From b2e45cd18e45e799f356dd2d8d74207a4a0e6d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Belli?= Date: Wed, 5 Feb 2025 18:31:33 +0100 Subject: [PATCH 3/3] fix(enum-values): handle more corner cases --- packages/openapi-typescript/src/lib/ts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/openapi-typescript/src/lib/ts.ts b/packages/openapi-typescript/src/lib/ts.ts index d07a1cfa3..355034614 100644 --- a/packages/openapi-typescript/src/lib/ts.ts +++ b/packages/openapi-typescript/src/lib/ts.ts @@ -256,7 +256,7 @@ export function tsArrayLiteralExpression( !options.injectFooter.some((node) => ts.isTypeAliasDeclaration(node) && node?.name?.escapedText === "FlattenedDeepRequired") ) { const helper = stringToAST( - "type FlattenedDeepRequired = { [K in keyof T]: Required>; };", + "type FlattenedDeepRequired = { [K in keyof T]-?: FlattenedDeepRequired[number] : T[K]>; };", )[0] as any; options.injectFooter.push(helper); }