From f539a2df8f3d459f7755a7f1309e59c0f9c09d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87elik?= Date: Wed, 18 Sep 2024 03:24:01 +0300 Subject: [PATCH 1/3] Fix circular ref array of recursive objects --- packages/fets/src/types.ts | 16 ++--- .../fets/tests/client/circular-ref-test.ts | 65 +++++++++++++++++-- .../fixtures/example-circular-ref-oas.ts | 39 +++++++++++ 3 files changed, 105 insertions(+), 15 deletions(-) diff --git a/packages/fets/src/types.ts b/packages/fets/src/types.ts index afd7e3fcd..8a680c3a9 100644 --- a/packages/fets/src/types.ts +++ b/packages/fets/src/types.ts @@ -159,13 +159,13 @@ type RangedJSONSchema = T extend } ? MIN extends number ? MAX extends number ? IntRange : never : never : never; */ -export type Circular = TJSONSchema extends { - properties: { [key: string]: JSONSchema }; -} - ? TJSONSchema extends PropertyValue> - ? true - : Circular>> - : false; +type Circular = T extends { $ref: infer R } + ? { $ref: R } + : T extends { properties: Record } + ? { + [K in keyof T]: Circular; + } + : T; export type Property = keyof TJSONSchema['properties']; export type PropertyValue< @@ -182,7 +182,7 @@ export type FromSchema = ? FromSchemaOriginal< T, { - deserialize: Circular extends false + deserialize: Circular extends { $ref: any } ? [ { pattern: { diff --git a/packages/fets/tests/client/circular-ref-test.ts b/packages/fets/tests/client/circular-ref-test.ts index aa21ce40c..4d6ccdf17 100644 --- a/packages/fets/tests/client/circular-ref-test.ts +++ b/packages/fets/tests/client/circular-ref-test.ts @@ -12,12 +12,12 @@ import type treeOAS from './fixtures/example-circular-ref-oas'; type NormalizedOAS = NormalizeOAS; // So it does handle circular reference actually -type SchemaInOAS = +type TreeSchemaInOAS = NormalizedOAS['paths']['/tree']['get']['responses']['200']['content']['application/json']['schema']; -type Test = FromSchema; +type TreeTest = FromSchema; -const a: Test = { +const a: TreeTest = { number: 1, child: { number: 2, @@ -33,9 +33,9 @@ if (a.child?.child?.child) { a.child.child.child.number = 1; } -type Test2 = FromSchema>; +type TreeTest2 = FromSchema>; -const b: Test2 = { +const b: TreeTest2 = { number: 1, child: { number: 2, @@ -45,9 +45,9 @@ const b: Test2 = { }, }; -type Test3 = OASOutput; +type TreeTest3 = OASOutput; -const c: Test3 = { +const c: TreeTest3 = { number: 1, child: { number: 2, @@ -57,6 +57,57 @@ const c: Test3 = { }, }; +type TreeListSchemaInOAS = + NormalizedOAS['paths']['/tree-list']['get']['responses']['200']['content']['application/json']['schema']; + +type TreeListTest = FromSchema; + +const d: TreeListTest = { + number: 1, + children: [ + { + number: 2, + get children() { + return [d]; + }, + }, + ], +}; + +if (d.children?.[0].children?.[0]?.children?.[0].number) { + // @ts-expect-error number is a number + d.children[0].children[0].children[0].number = 'a'; + d.children[0].children[0].children[0].number = 1; +} + +type TreeListTest2 = FromSchema>; + +const e: TreeListTest2 = { + number: 1, + children: [ + { + number: 2, + get children() { + return [e]; + }, + }, + ], +}; + +type TreeListTest3 = OASOutput; + +const f: TreeListTest3 = { + number: 1, + children: [ + { + number: 2, + get children() { + return [f]; + }, + }, + ], +}; + const client = createClient({}); // Somehow here is a problem diff --git a/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts b/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts index e8be4c2a9..d092bd0cc 100644 --- a/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts +++ b/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts @@ -30,9 +30,48 @@ export default { }, }, }, + "/tree-list": { + get: { + tags: ["tree-list"], + summary: "Get tree list", + description: "", + operationId: "getTreeList", + responses: { + "200": { + description: "successful operation", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/TreeNode", + }, + }, + }, + }, + "404": { + description: "Tree not found", + }, + }, + }, + }, }, components: { schemas: { + TreeNode: { + type: "object", + properties: { + number: { + type: 'integer', + format: 'int64', + example: 10, + }, + children: { + type: "array", + items: { + $ref: "#/components/schemas/TreeNode", + }, + }, + }, + }, Node: { type: 'object', properties: { From 86a5a2ea32cf942179ff8071ac7e80f8058c32a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87elik?= Date: Wed, 18 Sep 2024 03:44:00 +0300 Subject: [PATCH 2/3] Update example-circular-ref-oas.ts --- .../fixtures/example-circular-ref-oas.ts | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts b/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts index d092bd0cc..6049abb7b 100644 --- a/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts +++ b/packages/fets/tests/client/fixtures/example-circular-ref-oas.ts @@ -30,48 +30,48 @@ export default { }, }, }, - "/tree-list": { - get: { - tags: ["tree-list"], - summary: "Get tree list", - description: "", - operationId: "getTreeList", - responses: { - "200": { - description: "successful operation", - content: { - "application/json": { - schema: { - $ref: "#/components/schemas/TreeNode", - }, - }, - }, - }, - "404": { - description: "Tree not found", - }, - }, - }, - }, + '/tree-list': { + get: { + tags: ['tree-list'], + summary: 'Get tree list', + description: '', + operationId: 'getTreeList', + responses: { + '200': { + description: 'successful operation', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/TreeNode', + }, + }, + }, + }, + '404': { + description: 'Tree not found', + }, + }, + }, + }, }, components: { schemas: { - TreeNode: { - type: "object", - properties: { - number: { + TreeNode: { + type: 'object', + properties: { + number: { type: 'integer', format: 'int64', example: 10, - }, - children: { - type: "array", - items: { - $ref: "#/components/schemas/TreeNode", - }, - }, - }, - }, + }, + children: { + type: 'array', + items: { + $ref: '#/components/schemas/TreeNode', + }, + }, + }, + }, Node: { type: 'object', properties: { From a15508c8283b3263c07d5fc97d39cf46f53438fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87elik?= Date: Wed, 18 Sep 2024 10:56:59 +0300 Subject: [PATCH 3/3] Update types.ts --- packages/fets/src/types.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/fets/src/types.ts b/packages/fets/src/types.ts index 8a680c3a9..49d5ecca7 100644 --- a/packages/fets/src/types.ts +++ b/packages/fets/src/types.ts @@ -159,13 +159,15 @@ type RangedJSONSchema = T extend } ? MIN extends number ? MAX extends number ? IntRange : never : never : never; */ -type Circular = T extends { $ref: infer R } - ? { $ref: R } - : T extends { properties: Record } - ? { - [K in keyof T]: Circular; - } - : T; +export type Circular = TJSONSchema extends { + properties: { [key: string]: JSONSchema }; +} + ? TJSONSchema extends PropertyValue> + ? true + : Circular>> + : TJSONSchema extends { items: JSONSchema } + ? true + : false; export type Property = keyof TJSONSchema['properties']; export type PropertyValue< @@ -182,7 +184,7 @@ export type FromSchema = ? FromSchemaOriginal< T, { - deserialize: Circular extends { $ref: any } + deserialize: Circular extends false ? [ { pattern: {