Skip to content

Commit

Permalink
delete more code
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity committed Oct 9, 2024
1 parent 897a91a commit 861114f
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 416 deletions.
66 changes: 46 additions & 20 deletions packages/fdr-sdk/src/api-definition/unwrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ type InternalDefaultValue =
| { type: "unknown"; value: unknown }
| { type: "typeReferenceId"; value: Latest.TypeReferenceIdDefault };

/**
* Cache for unwrapped references. Perform the unwrapping only once.
*/
const UnwrapReferenceCache = new WeakMap<TypeShapeOrReference, UnwrappedReference>();

/**
* A TypeShape or TypeReference might be an alias or reference to another type.
* This function unwraps the reference, including any optional wrappers, to get the actual shape.
Expand Down Expand Up @@ -55,39 +60,45 @@ export function unwrapReference(
return undefined;
}

const cached = UnwrapReferenceCache.get(typeRef);
if (cached != null) {
return cached;
}

let isOptional = false;
const defaults: InternalDefaultValue[] = [];
const descriptions: FernDocs.MarkdownText[] = [];
const availabilities: Latest.Availability[] = [];

let internalTypeRef: TypeShapeOrReference | undefined = typeRef;
let loop = 0;
while (typeRef != null) {
while (internalTypeRef != null) {
if (loop > LOOP_TOLERANCE) {
// eslint-disable-next-line no-console
console.error("Infinite loop detected while unwrapping type reference. Falling back to unknown type.");
typeRef = undefined;
internalTypeRef = undefined;
break;
}

if (typeRef.type === "optional") {
if (internalTypeRef.type === "optional") {
isOptional = true;
if (typeRef.default != null) {
defaults.push({ type: "unknown", value: typeRef.default });
if (internalTypeRef.default != null) {
defaults.push({ type: "unknown", value: internalTypeRef.default });
}
typeRef = typeRef.shape;
} else if (typeRef.type === "alias") {
typeRef = typeRef.value;
} else if (typeRef.type === "id") {
if (typeRef.default != null) {
defaults.push({ type: "typeReferenceId", value: typeRef.default });
internalTypeRef = internalTypeRef.shape;
} else if (internalTypeRef.type === "alias") {
internalTypeRef = internalTypeRef.value;
} else if (internalTypeRef.type === "id") {
if (internalTypeRef.default != null) {
defaults.push({ type: "typeReferenceId", value: internalTypeRef.default });
}
const typeDef: Latest.TypeDefinition | undefined = types[typeRef.id];
const typeDef: Latest.TypeDefinition | undefined = types[internalTypeRef.id];
if (typeDef != null) {
if (typeDef.availability) {
availabilities.push(typeDef.availability);
}

typeRef = typeDef.shape;
internalTypeRef = typeDef.shape;
if (typeDef.description != null) {
descriptions.push(typeDef.description);
}
Expand All @@ -99,19 +110,23 @@ export function unwrapReference(
loop++;
}

if (typeRef == null) {
if (internalTypeRef == null) {
// Note: this should be a fatal error, but we're handling it gracefully for now
// eslint-disable-next-line no-console
console.error("Type reference is invalid. Falling back to unknown type.");
}

return {
shape: typeRef ?? { type: "unknown", displayName: undefined },
const toRet = {
shape: internalTypeRef ?? { type: "unknown", displayName: undefined },
availability: coalesceAvailability(availabilities),
isOptional,
default: selectDefaultValue(typeRef, defaults),
default: selectDefaultValue(internalTypeRef, defaults),
descriptions,
};

UnwrapReferenceCache.set(typeRef, toRet);

return toRet;
}

function selectDefaultValue(
Expand Down Expand Up @@ -155,6 +170,8 @@ function selectDefaultValue(
}
}

const UnwrapObjectTypeCache = new WeakMap<Latest.ObjectType, UnwrappedObjectType>();

/**
* Dereferences extended objects and returns all properties of the object.
* If an object extends another object, the properties of the extended object will be sorted alphabetically.
Expand All @@ -168,6 +185,11 @@ export function unwrapObjectType(
object: Latest.ObjectType,
types: Record<string, Latest.TypeDefinition>,
): UnwrappedObjectType {
const cached = UnwrapObjectTypeCache.get(object);
if (cached != null) {
return cached;
}

const directProperties = object.properties;
const descriptions: FernDocs.MarkdownText[] = [];
const extendedProperties = object.extends.flatMap((typeId): Latest.ObjectProperty[] => {
Expand Down Expand Up @@ -230,7 +252,9 @@ export function unwrapObjectType(
(property) => unwrapReference(property.valueShape, types)?.isOptional,
(property) => AvailabilityOrder.indexOf(property.availability ?? Latest.Availability.Stable),
);
return { properties, descriptions };
const toRet = { properties, descriptions };
UnwrapObjectTypeCache.set(object, toRet);
return toRet;
}
const propertyKeys = new Set(object.properties.map((property) => property.key));
const filteredExtendedProperties = extendedProperties.filter(
Expand All @@ -245,7 +269,9 @@ export function unwrapObjectType(
(property) => AvailabilityOrder.indexOf(property.availability ?? Latest.Availability.Stable),
(property) => property.key,
);
return { properties, descriptions };
const toRet = { properties, descriptions };
UnwrapObjectTypeCache.set(object, toRet);
return toRet;
}

/**
Expand All @@ -256,7 +282,7 @@ export function unwrapDiscriminatedUnionVariant(
variant: Latest.DiscriminatedUnionVariant,
types: Record<string, Latest.TypeDefinition>,
): UnwrappedObjectType {
const { properties, descriptions } = unwrapObjectType(variant, types);
const { properties, descriptions } = unwrapObjectType(variant, types); // this is already cached
return {
properties: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export const DiscriminatedUnionVariant: React.FC<DiscriminatedUnionVariant.Props
}) => {
const { isRootTypeDefinition } = useTypeDefinitionContext();

// TODO: render descriptions
const [shape, descriptions] = useMemo((): [ApiDefinition.TypeShape.Object_, FernDocs.MarkdownText[]] => {
const unwrapped = ApiDefinition.unwrapDiscriminatedUnionVariant({ discriminant }, unionVariant, types);
return [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { Empty } from "@fern-ui/components";
import { ReactElement, useEffect, useState } from "react";

export declare namespace TypeDefinitionDetails {
export interface Props {
elements: ReactElement[];
searchInput: string;
}
export interface EnumDefinitionDetailsProps {
elements: ReactElement[];
searchInput: string;
}

export const EnumDefinitionDetails = ({ elements, searchInput }: TypeDefinitionDetails.Props): ReactElement => {
export const EnumDefinitionDetails = ({ elements, searchInput }: EnumDefinitionDetailsProps): ReactElement => {
const [filteredElements, setFilteredElements] = useState<ReactElement[]>([]);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import * as ApiDefinition from "@fern-api/fdr-sdk/api-definition";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
import { FernTooltipProvider } from "@fern-ui/components";
import { useBooleanState, useIsHovering } from "@fern-ui/react-commons";
import cn from "clsx";
import { ReactElement, memo, useCallback, useMemo } from "react";
import { memo, useCallback, useMemo } from "react";
import { useRouteListener } from "../../../atoms";
import { Chip } from "../../../components/Chip";
import { FernErrorBoundary } from "../../../components/FernErrorBoundary";
import { getAnchorId } from "../../../util/anchor";
import {
TypeDefinitionContext,
TypeDefinitionContextValue,
useTypeDefinitionContext,
} from "../context/TypeDefinitionContext";
import { DiscriminatedUnionVariant } from "../discriminated-union/DiscriminatedUnionVariant";
import { ObjectProperty } from "../object/ObjectProperty";
import { UndiscriminatedUnionVariant } from "../undiscriminated-union/UndiscriminatedUnionVariant";
import { EnumTypeDefinition } from "./EnumTypeDefinition";
import { FernCollapseWithButton } from "./FernCollapseWithButton";
import { TypeDefinitionDetails } from "./TypeDefinitionDetails";
import { createCollapsibleContent } from "./createCollapsibleContent";

export declare namespace InternalTypeDefinition {
export interface Props {
Expand All @@ -31,98 +27,17 @@ export declare namespace InternalTypeDefinition {
}
}

interface CollapsibleContent {
elements: ReactElement[];
elementNameSingular: string;
elementNamePlural: string;
separatorText?: string;
}

export const InternalTypeDefinition = memo<InternalTypeDefinition.Props>(function InternalTypeDefinition({
shape,
isCollapsible,
anchorIdParts,
slug,
types,
}) {
const collapsableContent = useMemo(() => {
const unwrapped = ApiDefinition.unwrapReference(shape, types);
return visitDiscriminatedUnion(unwrapped.shape)._visit<CollapsibleContent | undefined>({
object: (object) => {
const { properties } = ApiDefinition.unwrapObjectType(object, types);
return {
elements: properties.map((property) => (
<ObjectProperty
key={property.key}
property={property}
anchorIdParts={[...anchorIdParts, property.key]}
slug={slug}
applyErrorStyles
types={types}
/>
)),
elementNameSingular: "property",
elementNamePlural: "properties",
};
},
undiscriminatedUnion: (union) => ({
elements: union.variants.map((variant, variantIdx) => (
<UndiscriminatedUnionVariant
key={variantIdx}
unionVariant={variant}
anchorIdParts={[...anchorIdParts, variant.displayName ?? variantIdx.toString()]}
applyErrorStyles={false}
slug={slug}
idx={variantIdx}
types={types}
/>
)),
elementNameSingular: "variant",
elementNamePlural: "variants",
separatorText: "OR",
}),
discriminatedUnion: (union) => ({
elements: union.variants.map((variant) => (
<DiscriminatedUnionVariant
key={variant.discriminantValue}
discriminant={union.discriminant}
unionVariant={variant}
anchorIdParts={[...anchorIdParts, variant.discriminantValue]}
slug={slug}
types={types}
/>
)),
elementNameSingular: "variant",
elementNamePlural: "variants",
separatorText: "OR",
}),
enum: (enum_) => ({
elements: enum_.values.map((enumValue) => (
<Chip key={enumValue.value} name={enumValue.value} description={enumValue.description} />
// <EnumValue key={enumValue.value} enumValue={enumValue} />
)),
elementNameSingular: "enum value",
elementNamePlural: "enum values",
}),
literal: (literal) => ({
elements: [
visitDiscriminatedUnion(literal.value, "type")._visit({
stringLiteral: (value) => <Chip key={value.value} name={value.value} />,
booleanLiteral: (value) => <Chip key={value.value.toString()} name={value.value.toString()} />,
_other: () => <span>{"<unknown>"}</span>,
}),
],
elementNameSingular: "literal",
elementNamePlural: "literals",
}),
unknown: () => undefined,
_other: () => undefined,
primitive: () => undefined,
list: () => undefined,
set: () => undefined,
map: () => undefined,
});
}, [shape, types, anchorIdParts, slug]);
const collapsableContent = useMemo(
() => createCollapsibleContent(shape, types, anchorIdParts, slug),
[shape, types, anchorIdParts, slug],
);

const anchorIdSoFar = getAnchorId(anchorIdParts);
const { value: isCollapsed, toggleValue: toggleIsCollapsed, setValue: setCollapsed } = useBooleanState(true);
Expand Down Expand Up @@ -151,9 +66,9 @@ export const InternalTypeDefinition = memo<InternalTypeDefinition.Props>(functio

if (!isCollapsible) {
// TODO: (rohin) Refactor this
if (collapsableContent.elementNameSingular === "literal") {
return null;
}
// if (collapsableContent.elementNameSingular === "literal") {
// return null;
// }
return (
<FernErrorBoundary component="InternalTypeDefinition">
<FernTooltipProvider>
Expand Down

This file was deleted.

Loading

0 comments on commit 861114f

Please sign in to comment.