Skip to content

Commit

Permalink
add undiscriminated union wrapper to various responses (#2173)
Browse files Browse the repository at this point in the history
  • Loading branch information
RohinBhargava authored Feb 17, 2025
1 parent 3abfe99 commit c4c2988
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,27 @@ import { renderTypeShorthand } from "../../type-shorthand";
import { JsonPropertyPath } from "../examples/JsonPropertyPath";
import { TypeComponentSeparator } from "../types/TypeComponentSeparator";
import { TypeReferenceDefinitions } from "../types/type-reference/TypeReferenceDefinitions";
import { maybeWrapTypeWithUndiscriminatedUnion } from "../utils/maybeWrapTypeWithUndiscriminatedUnion";
import {
EndpointParameter,
EndpointParameterContent,
} from "./EndpointParameter";

const FORM_DATA_BYTES_SHAPE: ApiDefinition.TypeShape = {
type: "alias",
value: {
type: "primitive",
value: {
type: "string",
format: "binary",
regex: undefined,
minLength: undefined,
maxLength: undefined,
default: undefined,
},
},
};

export declare namespace EndpointRequestSection {
export interface Props {
request: ApiDefinition.HttpRequest;
Expand Down Expand Up @@ -108,7 +124,21 @@ export const EndpointRequestSection: React.FC<EndpointRequestSection.Props> = ({
})}
</Fragment>
)),
bytes: () => null,
bytes: () => (
<TypeReferenceDefinitions
shape={maybeWrapTypeWithUndiscriminatedUnion(
FORM_DATA_BYTES_SHAPE,
types,
"Binary"
)}
isCollapsible={false}
onHoverProperty={onHoverProperty}
anchorIdParts={anchorIdParts}
slug={slug}
applyErrorStyles={false}
types={types}
/>
),
object: (obj) => (
<TypeReferenceDefinitions
shape={obj}
Expand All @@ -122,7 +152,7 @@ export const EndpointRequestSection: React.FC<EndpointRequestSection.Props> = ({
),
alias: (alias) => (
<TypeReferenceDefinitions
shape={alias}
shape={maybeWrapTypeWithUndiscriminatedUnion(alias, types)}
isCollapsible={false}
onHoverProperty={onHoverProperty}
anchorIdParts={anchorIdParts}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,34 @@ import { Markdown } from "../../mdx/Markdown";
import { renderTypeShorthand } from "../../type-shorthand";
import { JsonPropertyPath } from "../examples/JsonPropertyPath";
import { TypeReferenceDefinitions } from "../types/type-reference/TypeReferenceDefinitions";
import { maybeWrapTypeWithUndiscriminatedUnion } from "../utils/maybeWrapTypeWithUndiscriminatedUnion";

const STREAMING_TEXT_SHAPE: ApiDefinition.TypeShape = {
type: "alias",
value: {
type: "primitive",
value: {
type: "string",
format: "text",
default: undefined,
regex: undefined,
minLength: undefined,
maxLength: undefined,
},
},
};

const FILE_DOWNLOAD_SHAPE: ApiDefinition.TypeShape = {
type: "alias",
value: {
type: "primitive",
value: {
type: "base64",
default: undefined,
mimeType: undefined,
},
},
};

export declare namespace EndpointResponseSection {
export interface Props {
Expand Down Expand Up @@ -75,9 +103,45 @@ function EndpointResponseSectionContent({
}: EndpointResponseSectionContentProps) {
switch (body.type) {
case "empty":
return (
<span className="t-muted my-4 inline-flex items-baseline gap-2 text-xs">
No content
</span>
);
case "fileDownload":
return (
<TypeReferenceDefinitions
shape={maybeWrapTypeWithUndiscriminatedUnion(
FILE_DOWNLOAD_SHAPE,
types,
"File Download"
)}
isCollapsible={false}
onHoverProperty={onHoverProperty}
anchorIdParts={anchorIdParts}
slug={slug}
applyErrorStyles={false}
types={types}
isResponse={true}
/>
);
case "streamingText":
return null;
return (
<TypeReferenceDefinitions
shape={maybeWrapTypeWithUndiscriminatedUnion(
STREAMING_TEXT_SHAPE,
types,
"Streaming Text"
)}
isCollapsible={false}
onHoverProperty={onHoverProperty}
anchorIdParts={anchorIdParts}
slug={slug}
applyErrorStyles={false}
types={types}
isResponse={true}
/>
);
case "stream":
return (
<TypeReferenceDefinitions
Expand All @@ -91,10 +155,10 @@ function EndpointResponseSectionContent({
isResponse={true}
/>
);
default:
default: {
return (
<TypeReferenceDefinitions
shape={body}
shape={maybeWrapTypeWithUndiscriminatedUnion(body, types)}
isCollapsible={false}
onHoverProperty={onHoverProperty}
anchorIdParts={anchorIdParts}
Expand All @@ -104,6 +168,7 @@ function EndpointResponseSectionContent({
isResponse={true}
/>
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { ApiDefinition } from "@fern-api/fdr-sdk";
import { maybeWrapTypeWithUndiscriminatedUnion } from "../maybeWrapTypeWithUndiscriminatedUnion";

describe("maybeWrapTypeWithUndiscriminatedUnion", () => {
const types: Record<string, ApiDefinition.TypeDefinition> = {};

it("wraps primitive types in undiscriminated union", () => {
const stringShape: ApiDefinition.TypeShape = {
type: "alias",
value: {
type: "primitive",
value: {
type: "string",
format: undefined,
regex: undefined,
minLength: undefined,
maxLength: undefined,
default: undefined,
},
},
};

const result = maybeWrapTypeWithUndiscriminatedUnion(
stringShape,
types,
"String Type"
);

expect(result).toEqual({
type: "undiscriminatedUnion",
variants: [
{
displayName: "String Type",
description: undefined,
shape: stringShape,
availability: undefined,
},
],
});
});

it("does not wrap object types", () => {
const objectShape: ApiDefinition.TypeShape = {
type: "object",
properties: [],
extends: [],
extraProperties: undefined,
};

const result = maybeWrapTypeWithUndiscriminatedUnion(objectShape, types);

expect(result).toBe(objectShape);
});

it("does not wrap enum types", () => {
const enumShape: ApiDefinition.TypeShape = {
type: "enum",
values: [],
default: undefined,
};

const result = maybeWrapTypeWithUndiscriminatedUnion(enumShape, types);

expect(result).toBe(enumShape);
});

it("does not wrap discriminated union types", () => {
const unionShape: ApiDefinition.TypeShape = {
type: "discriminatedUnion",
discriminant: ApiDefinition.PropertyKey("type"),
variants: [],
};

const result = maybeWrapTypeWithUndiscriminatedUnion(unionShape, types);

expect(result).toBe(unionShape);
});

it("does not wrap undiscriminated union types", () => {
const unionShape: ApiDefinition.TypeShape = {
type: "undiscriminatedUnion",
variants: [],
};

const result = maybeWrapTypeWithUndiscriminatedUnion(unionShape, types);

expect(result).toBe(unionShape);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ApiDefinition } from "@fern-api/fdr-sdk";

export function maybeWrapTypeWithUndiscriminatedUnion(
shape: ApiDefinition.TypeShape,
types: Record<string, ApiDefinition.TypeDefinition>,
displayName?: string
): ApiDefinition.TypeShapeOrReference {
const unwrapped = ApiDefinition.unwrapReference(shape, types);
if (
unwrapped.shape.type !== "object" &&
unwrapped.shape.type !== "undiscriminatedUnion" &&
unwrapped.shape.type !== "discriminatedUnion" &&
unwrapped.shape.type !== "enum"
) {
return {
type: "undiscriminatedUnion",
variants: [
{
displayName,
description: undefined,
shape,
availability: undefined,
},
],
};
}
return shape;
}

0 comments on commit c4c2988

Please sign in to comment.