From b01c770c365378bc4bedf0814faebaa1b6dd8cec Mon Sep 17 00:00:00 2001 From: Andrew Jiang Date: Mon, 7 Oct 2024 15:18:45 -0400 Subject: [PATCH] fix: filter out childless sections (#1602) --- .../withBasicTokenViewAllowed.test.ts | 53 ++++++++++++++++++- .../src/server/withBasicTokenPublic.ts | 21 ++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/packages/ui/docs-bundle/src/server/__test__/withBasicTokenViewAllowed.test.ts b/packages/ui/docs-bundle/src/server/__test__/withBasicTokenViewAllowed.test.ts index b555406d9e..c98108b22d 100644 --- a/packages/ui/docs-bundle/src/server/__test__/withBasicTokenViewAllowed.test.ts +++ b/packages/ui/docs-bundle/src/server/__test__/withBasicTokenViewAllowed.test.ts @@ -1,4 +1,5 @@ -import { withBasicTokenPublic } from "../withBasicTokenPublic"; +import { NodeId, PageId, Slug, Url } from "@fern-api/fdr-sdk/navigation"; +import { withBasicTokenPublic, withBasicTokenPublicCheck } from "../withBasicTokenPublic"; describe("withBasicTokenPublic", () => { it("should deny the request if the allowlist is empty", () => { @@ -26,4 +27,54 @@ describe("withBasicTokenPublic", () => { it("shouuld respect denylist before allowlist", () => { expect(withBasicTokenPublic({ allowlist: ["/public"], denylist: ["/public"] }, "/public")).toBe(false); }); + + it("should never deny external links", () => { + expect( + withBasicTokenPublicCheck({ denylist: ["/(.*)"] })({ + type: "link", + url: Url("https://example.com"), + title: "External url", + icon: undefined, + id: NodeId("1"), + }), + ).toBe(true); + }); + + it("should prune childless non-leaf nodes", () => { + expect( + withBasicTokenPublicCheck({ allowlist: ["/public"] })({ + type: "section", + title: "Public", + children: [], + id: NodeId("1"), + slug: Slug("public"), + collapsed: false, + canonicalSlug: undefined, + icon: undefined, + hidden: undefined, + overviewPageId: undefined, + noindex: undefined, + pointsTo: undefined, + }), + ).toBe(false); + }); + + it("should not prune childless non-leaf nodes that have content", () => { + expect( + withBasicTokenPublicCheck({ allowlist: ["/public"] })({ + type: "section", + title: "Public", + children: [], + id: NodeId("1"), + slug: Slug("public"), + collapsed: false, + canonicalSlug: undefined, + icon: undefined, + hidden: undefined, + overviewPageId: PageId("1.mdx"), + noindex: undefined, + pointsTo: undefined, + }), + ).toBe(true); + }); }); diff --git a/packages/ui/docs-bundle/src/server/withBasicTokenPublic.ts b/packages/ui/docs-bundle/src/server/withBasicTokenPublic.ts index 68b3d616a6..b51d2bb5ed 100644 --- a/packages/ui/docs-bundle/src/server/withBasicTokenPublic.ts +++ b/packages/ui/docs-bundle/src/server/withBasicTokenPublic.ts @@ -1,6 +1,6 @@ -import { RootNode, isPage, utils } from "@fern-api/fdr-sdk/navigation"; +import { getChildren, isLeaf, isPage, utils, type NavigationNode, type RootNode } from "@fern-api/fdr-sdk/navigation"; import { matchPath } from "@fern-ui/fern-docs-utils"; -import { AuthEdgeConfigBasicTokenVerification } from "@fern-ui/ui/auth"; +import type { AuthEdgeConfigBasicTokenVerification } from "@fern-ui/ui/auth"; import { captureMessage } from "@sentry/nextjs"; /** @@ -26,14 +26,25 @@ export function withBasicTokenPublic( return false; } -export function pruneWithBasicTokenPublic(auth: AuthEdgeConfigBasicTokenVerification, node: RootNode): RootNode { - const result = utils.pruneNavigationTree(node, (node) => { +/** + * @internal visibleForTesting + */ +export function withBasicTokenPublicCheck( + auth: Pick, +): (node: NavigationNode) => boolean { + return (node: NavigationNode) => { if (isPage(node)) { return withBasicTokenPublic(auth, `/${node.slug}`); + } else if (!isLeaf(node) && getChildren(node).length === 0) { + return false; } return true; - }); + }; +} + +export function pruneWithBasicTokenPublic(auth: AuthEdgeConfigBasicTokenVerification, node: RootNode): RootNode { + const result = utils.pruneNavigationTree(node, withBasicTokenPublicCheck(auth)); // TODO: handle this more gracefully if (result == null) {