From 8b4202020710d0149d550f357ca077797494918c Mon Sep 17 00:00:00 2001 From: Andrew Jiang Date: Fri, 19 Jan 2024 17:31:28 -0500 Subject: [PATCH] fix: support recursive property rendering (#371) --- packages/commons/app-utils/src/resolver.ts | 26 ++++++++++++------- .../DiscriminatedUnionVariant.tsx | 2 +- .../InternalTypeDefinition.tsx | 22 +++++++++------- .../InternalTypeDefinitionError.tsx | 20 +++++++------- .../InternalTypeReferenceDefinitions.tsx | 11 ++++++++ .../types/type-shorthand/TypeShorthand.tsx | 1 + .../UndiscriminatedUnionVariant.tsx | 1 + .../PlaygroundTypeReferenceForm.tsx | 11 +++++++- packages/ui/app/src/api-playground/utils.ts | 9 ++++--- 9 files changed, 69 insertions(+), 34 deletions(-) diff --git a/packages/commons/app-utils/src/resolver.ts b/packages/commons/app-utils/src/resolver.ts index 8460322498..02e022563d 100644 --- a/packages/commons/app-utils/src/resolver.ts +++ b/packages/commons/app-utils/src/resolver.ts @@ -222,9 +222,9 @@ function resolveWebhookPayloadShape( return visitDiscriminatedUnion(payloadShape, "type")._visit({ object: (object) => ({ type: "object", - properties: resolveObjectProperties(object, types), + properties: () => resolveObjectProperties(object, types), }), - reference: (reference) => resolveTypeReference(reference.value, types), + reference: (reference) => ({ type: "reference", shape: () => resolveTypeReference(reference.value, types) }), _other: () => ({ type: "unknown" }), }); } @@ -236,10 +236,10 @@ function resolveRequestBodyShape( return visitDiscriminatedUnion(requestBodyShape, "type")._visit({ object: (object) => ({ type: "object", - properties: resolveObjectProperties(object, types), + properties: () => resolveObjectProperties(object, types), }), fileUpload: (fileUpload) => fileUpload, - reference: (reference) => resolveTypeReference(reference.value, types), + reference: (reference) => ({ type: "reference", shape: () => resolveTypeReference(reference.value, types) }), _other: () => ({ type: "unknown" }), }); } @@ -251,12 +251,12 @@ function resolveResponseBodyShape( return visitDiscriminatedUnion(responseBodyShape, "type")._visit({ object: (object) => ({ type: "object", - properties: resolveObjectProperties(object, types), + properties: () => resolveObjectProperties(object, types), }), fileDownload: (fileDownload) => fileDownload, streamingText: (streamingText) => streamingText, streamCondition: (streamCondition) => streamCondition, - reference: (reference) => resolveTypeReference(reference.value, types), + reference: (reference) => ({ type: "reference", shape: () => resolveTypeReference(reference.value, types) }), _other: () => ({ type: "unknown" }), }); } @@ -268,7 +268,7 @@ function resolveTypeShape( return visitDiscriminatedUnion(typeShape, "type")._visit({ object: (object) => ({ type: "object", - properties: resolveObjectProperties(object, types), + properties: () => resolveObjectProperties(object, types), }), enum: (enum_) => enum_, undiscriminatedUnion: (undiscriminatedUnion) => ({ @@ -334,7 +334,7 @@ function resolveObjectProperties( console.error("Object extends non-object", typeId); return []; } - return shape.properties; + return shape.properties(); }); if (extendedProperties.length === 0) { return directProperties; @@ -486,7 +486,7 @@ export interface ResolvedWebhookPayload extends APIV1Read.WithDescription { export interface ResolvedObjectShape { type: "object"; - properties: ResolvedObjectProperty[]; + properties: () => ResolvedObjectProperty[]; } export interface ResolvedUndiscriminatedUnionShapeVariant @@ -547,7 +547,13 @@ export type ResolvedTypeReference = | ResolvedSetShape | ResolvedMapShape | APIV1Read.LiteralType - | APIV1Read.TypeReference.Unknown; + | APIV1Read.TypeReference.Unknown + | ResolvedReferenceShape; + +export interface ResolvedReferenceShape { + type: "reference"; + shape: () => ResolvedTypeReference; +} export type ResolvedHttpRequestBodyShape = APIV1Read.HttpRequestBodyShape.FileUpload | ResolvedTypeReference; diff --git a/packages/ui/app/src/api-page/types/discriminated-union/DiscriminatedUnionVariant.tsx b/packages/ui/app/src/api-page/types/discriminated-union/DiscriminatedUnionVariant.tsx index 4ef345e322..7ca60636d8 100644 --- a/packages/ui/app/src/api-page/types/discriminated-union/DiscriminatedUnionVariant.tsx +++ b/packages/ui/app/src/api-page/types/discriminated-union/DiscriminatedUnionVariant.tsx @@ -34,7 +34,7 @@ export const DiscriminatedUnionVariant: React.FC { return { type: "object", - properties: [ + properties: () => [ { key: discriminant, valueShape: { diff --git a/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinition.tsx b/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinition.tsx index 52ec7c4c1b..6960781650 100644 --- a/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinition.tsx +++ b/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinition.tsx @@ -52,16 +52,18 @@ export const InternalTypeDefinition: React.FC = ({ () => visitDiscriminatedUnion(typeShape, "type")._visit({ object: (object) => ({ - elements: object.properties.map((property) => ( - - )), + elements: object + .properties() + .map((property) => ( + + )), elementNameSingular: "property", elementNamePlural: "properties", }), diff --git a/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinitionError.tsx b/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinitionError.tsx index 5279fdaf1b..b99c88608d 100644 --- a/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinitionError.tsx +++ b/packages/ui/app/src/api-page/types/type-definition/InternalTypeDefinitionError.tsx @@ -51,15 +51,17 @@ export const InternalTypeDefinitionError: React.FC visitDiscriminatedUnion(typeShape, "type")._visit({ object: (object) => ({ - elements: object.properties.map((property) => ( - - )), + elements: object + .properties() + .map((property) => ( + + )), elementNameSingular: "property", elementNamePlural: "properties", }), diff --git a/packages/ui/app/src/api-page/types/type-reference/InternalTypeReferenceDefinitions.tsx b/packages/ui/app/src/api-page/types/type-reference/InternalTypeReferenceDefinitions.tsx index 5cf57d8252..69bb6ac428 100644 --- a/packages/ui/app/src/api-page/types/type-reference/InternalTypeReferenceDefinitions.tsx +++ b/packages/ui/app/src/api-page/types/type-reference/InternalTypeReferenceDefinitions.tsx @@ -138,5 +138,16 @@ export const InternalTypeReferenceDefinitions: React.FC null, unknown: () => null, _other: () => null, + reference: (reference) => ( + + ), }); }; diff --git a/packages/ui/app/src/api-page/types/type-shorthand/TypeShorthand.tsx b/packages/ui/app/src/api-page/types/type-shorthand/TypeShorthand.tsx index add7b087aa..3bf122524b 100644 --- a/packages/ui/app/src/api-page/types/type-shorthand/TypeShorthand.tsx +++ b/packages/ui/app/src/api-page/types/type-shorthand/TypeShorthand.tsx @@ -53,5 +53,6 @@ export function renderTypeShorthand( // other unknown: () => "any", _other: () => "", + reference: (reference) => renderTypeShorthand(reference.shape(), { plural, withArticle }), }); } diff --git a/packages/ui/app/src/api-page/types/undiscriminated-union/UndiscriminatedUnionVariant.tsx b/packages/ui/app/src/api-page/types/undiscriminated-union/UndiscriminatedUnionVariant.tsx index 8c81eaed44..c23712c4f6 100644 --- a/packages/ui/app/src/api-page/types/undiscriminated-union/UndiscriminatedUnionVariant.tsx +++ b/packages/ui/app/src/api-page/types/undiscriminated-union/UndiscriminatedUnionVariant.tsx @@ -40,6 +40,7 @@ function getIconInfoForTypeReference(typeRef: ResolvedTypeReference): IconInfo | stringLiteral: () => ({ content: "!", size: 6 }), unknown: () => ({ content: "{}", size: 6 }), _other: () => null, + reference: (reference) => getIconInfoForTypeReference(reference.shape()), }); } diff --git a/packages/ui/app/src/api-playground/PlaygroundTypeReferenceForm.tsx b/packages/ui/app/src/api-playground/PlaygroundTypeReferenceForm.tsx index 29597fe303..950d3175f0 100644 --- a/packages/ui/app/src/api-playground/PlaygroundTypeReferenceForm.tsx +++ b/packages/ui/app/src/api-playground/PlaygroundTypeReferenceForm.tsx @@ -105,7 +105,7 @@ export const PlaygroundTypeReferenceForm: FC = onOpenStack={onOpenStack} onCloseStack={onCloseStack} > - + ), enum: ({ values }) => , @@ -276,5 +276,14 @@ export const PlaygroundTypeReferenceForm: FC = /> ), _other: () => null, + reference: (reference) => ( + + ), }); }; diff --git a/packages/ui/app/src/api-playground/utils.ts b/packages/ui/app/src/api-playground/utils.ts index 07c1044908..8d3821c421 100644 --- a/packages/ui/app/src/api-playground/utils.ts +++ b/packages/ui/app/src/api-playground/utils.ts @@ -285,7 +285,7 @@ export function matchesTypeReference(shape: ResolvedTypeReference, value: unknow return false; } const propertyMap = new Map(); - object.properties.forEach((property) => propertyMap.set(property.key, property)); + object.properties().forEach((property) => propertyMap.set(property.key, property)); return Object.keys(value).every((key) => { const property = propertyMap.get(key); if (property == null) { @@ -349,6 +349,7 @@ export function matchesTypeReference(shape: ResolvedTypeReference, value: unknow booleanLiteral: (literalType) => value === literalType.value, unknown: () => value == null, _other: () => value == null, + reference: (reference) => matchesTypeReference(reference.shape(), value), }); } @@ -368,7 +369,7 @@ export function getDefaultValuesForBody(requestShape: ResolvedHttpRequestBodySha } else if (requestShape.type === "fileUpload") { return null; } else if (requestShape.type === "object") { - return getDefaultValueForObjectProperties(requestShape.properties); + return getDefaultValueForObjectProperties(requestShape.properties()); } else { return getDefaultValueForType(requestShape); } @@ -376,7 +377,7 @@ export function getDefaultValuesForBody(requestShape: ResolvedHttpRequestBodySha export function getDefaultValueForType(shape: ResolvedTypeReference): unknown { return visitDiscriminatedUnion(shape, "type")._visit({ - object: (object) => getDefaultValueForObjectProperties(object.properties), + object: (object) => getDefaultValueForObjectProperties(object.properties()), discriminatedUnion: (discriminatedUnion) => { const variant = discriminatedUnion.variants[0]; @@ -415,6 +416,7 @@ export function getDefaultValueForType(shape: ResolvedTypeReference): unknown { booleanLiteral: (literal) => literal.value, unknown: () => undefined, _other: () => undefined, + reference: (reference) => getDefaultValueForType(reference.shape()), }); } @@ -441,5 +443,6 @@ export function isExpandable(valueShape: ResolvedTypeReference, currentValue: un date: () => false, booleanLiteral: () => false, stringLiteral: () => false, + reference: (reference) => isExpandable(reference.shape(), currentValue), }); }