Skip to content

Commit

Permalink
make functions abstract, polyfill structuredClone, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity committed Oct 4, 2024
1 parent ea4c20d commit 520edee
Show file tree
Hide file tree
Showing 32 changed files with 834 additions and 449 deletions.
4 changes: 2 additions & 2 deletions packages/commons/search-utils/src/getSlugForSearchRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function createSearchPlaceholder(sidebar: FernNavigation.SidebarRootNode | undef

function checkHasGuides(sidebar: FernNavigation.SidebarRootNode): boolean {
let hasGuides = false;
FernNavigation.traverseNavigation(sidebar, (node) => {
FernNavigation.traverseBF(sidebar, (node) => {
if (node.type === "page") {
hasGuides = true;
return false;
Expand All @@ -113,7 +113,7 @@ function checkHasGuides(sidebar: FernNavigation.SidebarRootNode): boolean {

function checkHasEndpoints(sidebar: FernNavigation.SidebarRootNode): boolean {
let hasEndpoints = false;
FernNavigation.traverseNavigation(sidebar, (node) => {
FernNavigation.traverseBF(sidebar, (node) => {
if (node.type === "apiReference") {
hasEndpoints = true;
return false;
Expand Down
1 change: 1 addition & 0 deletions packages/fdr-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
},
"dependencies": {
"@fern-ui/core-utils": "workspace:*",
"core-js-pure": "^3.38.1",
"dayjs": "^1.11.11",
"fast-deep-equal": "^3.1.3",
"form-data": "4.0.0",
Expand Down
5 changes: 5 additions & 0 deletions packages/fdr-sdk/src/declarations.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module "core-js-pure/actual/structured-clone" {
const structuredClone: <T>(value: T) => T;

export default structuredClone;
}
17 changes: 9 additions & 8 deletions packages/fdr-sdk/src/navigation/NodeCollector.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { EMPTY_ARRAY } from "@fern-ui/core-utils";
import { once } from "../utils";
import { FernNavigation } from "./..";
import { pruneVersionNode } from "./utils/pruneVersionNode";

interface NavigationNodeWithMetadataAndParents {
node: FernNavigation.NavigationNodeWithMetadata;
parents: FernNavigation.NavigationNode[];
parents: readonly FernNavigation.NavigationNodeParent[];
next: FernNavigation.NavigationNodeNeighbor | undefined;
prev: FernNavigation.NavigationNodeNeighbor | undefined;
}
Expand All @@ -14,7 +15,7 @@ const NodeCollectorInstances = new WeakMap<FernNavigation.NavigationNode, NodeCo
export class NodeCollector {
private static readonly EMPTY = new NodeCollector(undefined);
private idToNode = new Map<FernNavigation.NodeId, FernNavigation.NavigationNode>();
private idToNodeParents = new Map<FernNavigation.NodeId, FernNavigation.NavigationNode[]>();
private idToNodeParents = new Map<FernNavigation.NodeId, readonly FernNavigation.NavigationNodeParent[]>();
private slugToNode = new Map<FernNavigation.Slug, NavigationNodeWithMetadataAndParents>();
private orphanedNodes: FernNavigation.NavigationNodeWithMetadata[] = [];

Expand All @@ -36,7 +37,7 @@ export class NodeCollector {
#setNode(
slug: FernNavigation.Slug,
node: FernNavigation.NavigationNodeWithMetadata,
parents: FernNavigation.NavigationNode[],
parents: readonly FernNavigation.NavigationNodeParent[],
) {
const toSet = { node, parents, prev: this.#lastNeighboringNode, next: undefined };
this.slugToNode.set(slug, toSet);
Expand All @@ -56,7 +57,7 @@ export class NodeCollector {
if (rootNode == null) {
return;
}
FernNavigation.traverseNavigation(rootNode, (node, _index, parents) => {
FernNavigation.traverseDF(rootNode, (node, parents) => {
// if the node is the default version, make a copy of it and "prune" the version slug from all children nodes
if (node.type === "version") {
this.versionNodes.push(node);
Expand All @@ -65,7 +66,7 @@ export class NodeCollector {
if (node.type === "version" && node.default && rootNode.type === "root") {
const copy = JSON.parse(JSON.stringify(node)) as FernNavigation.VersionNode;
this.defaultVersion = pruneVersionNode(copy, rootNode.slug, node.slug);
FernNavigation.traverseNavigation(this.defaultVersion, (node, _index, innerParents) => {
FernNavigation.traverseDF(this.defaultVersion, (node, innerParents) => {
this.visitNode(node, [...parents, ...innerParents], true);
});
}
Expand All @@ -76,7 +77,7 @@ export class NodeCollector {

private visitNode(
node: FernNavigation.NavigationNode,
parents: FernNavigation.NavigationNode[],
parents: readonly FernNavigation.NavigationNodeParent[],
isDefaultVersion = false,
): void {
if (!this.idToNode.has(node.id) || isDefaultVersion) {
Expand Down Expand Up @@ -137,8 +138,8 @@ export class NodeCollector {
return this.idToNode.get(id);
}

public getParents(id: FernNavigation.NodeId): FernNavigation.NavigationNode[] {
return this.idToNodeParents.get(id) ?? [];
public getParents(id: FernNavigation.NodeId): readonly FernNavigation.NavigationNodeParent[] {
return this.idToNodeParents.get(id) ?? EMPTY_ARRAY;
}

public getSlugMapWithParents = (): ReadonlyMap<FernNavigation.Slug, NavigationNodeWithMetadataAndParents> => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { FernNavigation } from "../../..";
import { pruneNavigationTree } from "../pruneNavigationTree";

describe("pruneNavigationTree", () => {
it("should not prune the tree if keep returns true for all nodes", () => {
const root: FernNavigation.NavigationNode = {
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
title: "Root",
children: [
{
type: "page",
id: FernNavigation.NodeId("page"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
overviewPageId: undefined,
noindex: undefined,
pointsTo: undefined,
};

const result = pruneNavigationTree(root, () => true);

// structuredClone should duplicate the object
expect(result === root).toBe(false);

expect(result).toStrictEqual({
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
title: "Root",
children: [
{
type: "page",
id: FernNavigation.NodeId("page"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
overviewPageId: undefined,
noindex: undefined,
pointsTo: undefined,
});
});

it("should return undefined if no visitable pages are left", () => {
const root: FernNavigation.NavigationNode = {
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
title: "Root",
children: [
{
type: "page",
id: FernNavigation.NodeId("page"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
overviewPageId: undefined,
noindex: undefined,
pointsTo: undefined,
};

const result = pruneNavigationTree(root, (node) => node.id !== FernNavigation.NodeId("page"));

expect(result).toBeUndefined();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FernNavigation } from "../..";

export function collectApiReferences(nav: FernNavigation.NavigationNode): FernNavigation.ApiReferenceNode[] {
const apiReferences: FernNavigation.ApiReferenceNode[] = [];
FernNavigation.traverseNavigation(nav, (node) => {
FernNavigation.traverseDF(nav, (node) => {
if (node.type === "apiReference") {
apiReferences.push(node);
return "skip";
Expand Down
2 changes: 1 addition & 1 deletion packages/fdr-sdk/src/navigation/utils/collectPageIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getPageId } from "../versions/latest/getPageId";

export function collectPageIds(nav: FernNavigation.NavigationNode): Set<FernNavigation.PageId> {
const pageIds = new Set<FernNavigation.PageId>();
FernNavigation.traverseNavigation(nav, (node) => {
FernNavigation.traverseDF(nav, (node) => {
if (FernNavigation.isPage(node)) {
const pageId = getPageId(node);
if (pageId != null) {
Expand Down
2 changes: 1 addition & 1 deletion packages/fdr-sdk/src/navigation/utils/createBreadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import visitDiscriminatedUnion from "@fern-ui/core-utils/visitDiscriminatedUnion
import { noop } from "ts-essentials";
import { FernNavigation } from "../..";

export function createBreadcrumbs(nodes: FernNavigation.NavigationNode[]): FernNavigation.BreadcrumbItem[] {
export function createBreadcrumbs(nodes: readonly FernNavigation.NavigationNode[]): FernNavigation.BreadcrumbItem[] {
const breadcrumb: FernNavigation.BreadcrumbItem[] = [];
nodes.forEach((node) => {
if (!FernNavigation.hasMetadata(node) || FernNavigation.isLeaf(node)) {
Expand Down
72 changes: 72 additions & 0 deletions packages/fdr-sdk/src/navigation/utils/deleteChild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { UnreachableCaseError } from "ts-essentials";
import { FernNavigation } from "../..";

/**
* @param parent delete node from this parent (mutable)
* @param node node to delete
* @returns the id of the deleted node or null if the node was not deletable from the parent
*/
export function mutableDeleteChild(
parent: FernNavigation.NavigationNodeParent,
node: FernNavigation.NavigationNode,
): FernNavigation.NodeId | null {
switch (parent.type) {
case "apiPackage":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "apiReference":
parent.children = parent.children.filter((child) => child.id !== node.id);
parent.changelog = parent.changelog?.id === node.id ? undefined : parent.changelog;
return node.id;
case "changelog":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "changelogYear":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "changelogMonth":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "endpointPair":
return null;
case "productgroup":
parent.children = parent.children.filter((child) => child.id !== node.id);
parent.landingPage = parent.landingPage?.id === node.id ? undefined : parent.landingPage;
return node.id;
case "product":
return null;
case "root":
return null;
case "unversioned":
if (node.id === parent.landingPage?.id) {
parent.landingPage = undefined;
return node.id;
}
return null;
case "section":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "sidebarGroup":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "tab":
return null;
case "sidebarRoot":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "tabbed":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
case "version":
if (node.id === parent.landingPage?.id) {
parent.landingPage = undefined;
return node.id;
}
return null;
case "versioned":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
default:
throw new UnreachableCaseError(parent);
}
}
8 changes: 4 additions & 4 deletions packages/fdr-sdk/src/navigation/utils/findNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ export declare namespace Node {
interface Found {
type: "found";
node: FernNavigation.NavigationNodePage;
parents: FernNavigation.NavigationNode[];
breadcrumb: FernNavigation.BreadcrumbItem[];
parents: readonly FernNavigation.NavigationNode[];
breadcrumb: readonly FernNavigation.BreadcrumbItem[];
root: FernNavigation.RootNode;
versions: FernNavigation.VersionNode[];
versions: readonly FernNavigation.VersionNode[];
currentVersion: FernNavigation.VersionNode | undefined;
currentTab: FernNavigation.TabNode | FernNavigation.ChangelogNode | undefined;
tabs: FernNavigation.TabChild[];
tabs: readonly FernNavigation.TabChild[];
sidebar: FernNavigation.SidebarRootNode | undefined;
apiReference: FernNavigation.ApiReferenceNode | undefined;
next: FernNavigation.NavigationNodeNeighbor | undefined;
Expand Down
Loading

0 comments on commit 520edee

Please sign in to comment.