Skip to content

Commit

Permalink
chore: split docs content resolver into multiple files (#1606)
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored Oct 8, 2024
1 parent 5aec8ab commit 488e327
Show file tree
Hide file tree
Showing 12 changed files with 571 additions and 369 deletions.
2 changes: 1 addition & 1 deletion packages/fdr-sdk/src/navigation/utils/findNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export declare namespace Node {
interface Found {
type: "found";
node: FernNavigation.NavigationNodePage;
parents: readonly FernNavigation.NavigationNode[];
parents: readonly FernNavigation.NavigationNodeParent[];
breadcrumb: readonly FernNavigation.BreadcrumbItem[];
root: FernNavigation.RootNode;
versions: readonly FernNavigation.VersionNode[];
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ export type { ProxyRequest, ProxyResponse, SerializableFile, SerializableFormDat
export { ApiDefinitionResolver, type ApiDefinitionResolverCache } from "./resolver/ApiDefinitionResolver";
export { ApiEndpointResolver } from "./resolver/ApiEndpointResolver";
export { ApiTypeResolver } from "./resolver/ApiTypeResolver";
export { resolveDocsContent } from "./resolver/resolveDocsContent";
export * from "./resolver/types";
export { getBreadcrumbList } from "./seo/getBreadcrumbList";
export { getSeoProps } from "./seo/getSeoProp";
export { getRegistryServiceWithToken, provideRegistryService } from "./services/registry";
export { renderThemeStylesheet } from "./themes/stylesheet/renderThemeStylesheet";
export { getGitHubInfo, getGitHubRepo } from "./util/github";
export { resolveDocsContent } from "./util/resolveDocsContent";
18 changes: 18 additions & 0 deletions packages/ui/app/src/resolver/parseMarkdownPageToAnchorTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import GithubSlugger from "github-slugger";

export function parseMarkdownPageToAnchorTag(markdown: string): string | undefined {
/**
* new slugger instance per page to avoid conflicts between pages
*/
const slugger = new GithubSlugger();

// TODO: This regex match is temporary and will be replaced with a more robust solution
const matches = markdown.match(/^(#{1,6})\s+(.+)$/gm);
let anchorTag = undefined;
if (matches) {
const originalSlug = slugger.slug(matches[0]);
anchorTag = originalSlug.match(/[^$$]+/)?.[0].slice(1);
}

return anchorTag;
}
78 changes: 78 additions & 0 deletions packages/ui/app/src/resolver/resolveApiEndpointPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { APIV1Read } from "@fern-api/fdr-sdk";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { visitDiscriminatedUnion } from "@fern-ui/core-utils";
import type { FeatureFlags } from "../atoms";
import type { MDX_SERIALIZER } from "../mdx/bundler";
import type { FernSerializeMdxOptions } from "../mdx/types";
import { ApiEndpointResolver } from "./ApiEndpointResolver";
import { ApiTypeResolver } from "./ApiTypeResolver";
import type { DocsContent } from "./DocsContent";
import { ResolvedApiEndpoint } from "./types";

interface ResolveApiEndpointPageOpts {
node: FernNavigation.NavigationNodeApiLeaf;
parents: readonly FernNavigation.NavigationNodeParent[];
apis: Record<string, APIV1Read.ApiDefinition>;
mdxOptions: FernSerializeMdxOptions | undefined;
featureFlags: FeatureFlags;
neighbors: DocsContent.Neighbors;
serializeMdx: MDX_SERIALIZER;
collector: FernNavigation.NodeCollector;
showErrors: boolean | undefined;
}

export async function resolveApiEndpointPage({
node,
parents,
apis,
mdxOptions,
featureFlags,
neighbors,
serializeMdx,
collector,
showErrors,
}: ResolveApiEndpointPageOpts): Promise<DocsContent.ApiEndpointPage | undefined> {
let api = apis[node.apiDefinitionId];
if (api == null) {
return;
}
const pruner = new FernNavigation.ApiDefinitionPruner(api);
const parent = parents[parents.length - 1];
api = pruner.prune(parent?.type === "endpointPair" ? parent : node);
const holder = FernNavigation.ApiDefinitionHolder.create(api);
const typeResolver = new ApiTypeResolver(node.apiDefinitionId, api.types, mdxOptions, serializeMdx);
const resolvedTypes = await typeResolver.resolve();
const defResolver = new ApiEndpointResolver(
collector,
holder,
typeResolver,
resolvedTypes,
featureFlags,
mdxOptions,
serializeMdx,
);
return {
type: "api-endpoint-page",
slug: node.slug,
api: node.apiDefinitionId,
auth: api.auth,
types: resolvedTypes,
item: await visitDiscriminatedUnion(node)._visit<Promise<ResolvedApiEndpoint>>({
endpoint: async (endpoint) => {
if (parent?.type === "endpointPair") {
const [stream, nonStream] = await Promise.all([
defResolver.resolveEndpointDefinition(parent.stream),
defResolver.resolveEndpointDefinition(parent.nonStream),
]);
nonStream.stream = stream;
return nonStream;
}
return defResolver.resolveEndpointDefinition(endpoint);
},
webSocket: (webSocket) => defResolver.resolveWebsocketChannel(webSocket),
webhook: (webhook) => defResolver.resolveWebhookDefinition(webhook),
}),
showErrors: showErrors ?? false,
neighbors,
};
}
58 changes: 58 additions & 0 deletions packages/ui/app/src/resolver/resolveApiReferencePage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { APIV1Read, DocsV1Read } from "@fern-api/fdr-sdk";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { FeatureFlags } from "../atoms";
import type { MDX_SERIALIZER } from "../mdx/bundler";
import type { FernSerializeMdxOptions } from "../mdx/types";
import { ApiDefinitionResolver } from "./ApiDefinitionResolver";
import type { DocsContent } from "./DocsContent";

interface ResolveApiReferencePageOpts {
node: FernNavigation.NavigationNodeWithMetadata;
apiReference: FernNavigation.ApiReferenceNode;
parents: readonly FernNavigation.NavigationNodeParent[];
pages: Record<string, DocsV1Read.PageContent>;
apis: Record<string, APIV1Read.ApiDefinition>;
mdxOptions: FernSerializeMdxOptions | undefined;
featureFlags: FeatureFlags;
serializeMdx: MDX_SERIALIZER;
collector: FernNavigation.NodeCollector;
}

export async function resolveApiReferencePage({
node,
apis,
apiReference,
pages,
mdxOptions,
featureFlags,
serializeMdx,
collector,
}: ResolveApiReferencePageOpts): Promise<DocsContent.ApiReferencePage | undefined> {
const api = apis[apiReference.apiDefinitionId];
if (api == null) {
// eslint-disable-next-line no-console
console.error("API not found", apiReference.apiDefinitionId);
return;
}
const holder = FernNavigation.ApiDefinitionHolder.create(api);
const apiDefinition = await ApiDefinitionResolver.resolve(
collector,
apiReference,
holder,
pages,
mdxOptions,
featureFlags,
serializeMdx,
);
return {
type: "api-reference-page",
slug: node.slug,
title: node.title,
api: apiReference.apiDefinitionId,
apiDefinition,
paginated: apiReference.paginated ?? false,
// artifacts: apiSection.artifacts ?? null, // TODO: add artifacts
showErrors: apiReference.showErrors ?? false,
// neighbors,
};
}
59 changes: 59 additions & 0 deletions packages/ui/app/src/resolver/resolveChangelogEntryPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { DocsV1Read } from "@fern-api/fdr-sdk";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { reverse } from "lodash-es";
import type { MDX_SERIALIZER } from "../mdx/bundler";
import { getFrontmatter } from "../mdx/frontmatter";
import type { FernSerializeMdxOptions } from "../mdx/types";
import type { DocsContent } from "./DocsContent";

interface ResolveChangelogEntryPageOptions {
node: FernNavigation.ChangelogEntryNode;
parents: readonly FernNavigation.NavigationNodeParent[];
breadcrumb: readonly FernNavigation.BreadcrumbItem[];
pages: Record<string, DocsV1Read.PageContent>;
serializeMdx: MDX_SERIALIZER;
mdxOptions: FernSerializeMdxOptions | undefined;
neighbors: DocsContent.Neighbors;
}

export async function resolveChangelogEntryPage({
node,
parents,
breadcrumb,
pages,
serializeMdx,
mdxOptions,
neighbors,
}: ResolveChangelogEntryPageOptions): Promise<DocsContent.ChangelogEntryPage | undefined> {
const changelogNode = reverse(parents).find((n): n is FernNavigation.ChangelogNode => n.type === "changelog");
if (changelogNode == null) {
throw new Error("Changelog node not found");
}
const changelogMarkdown =
changelogNode.overviewPageId != null ? pages[changelogNode.overviewPageId]?.markdown : undefined;
const changelogTitle =
(changelogMarkdown != null ? getFrontmatter(changelogMarkdown).data.title : undefined) ?? changelogNode.title;

const markdown = pages[node.pageId]?.markdown;
if (markdown == null) {
// TODO: sentry
// eslint-disable-next-line no-console
console.error("Markdown content not found", node.pageId);
return;
}

const page = await serializeMdx(markdown, {
...mdxOptions,
filename: node.pageId,
});

return {
...node,
type: "changelog-entry",
changelogTitle,
changelogSlug: changelogNode.slug,
breadcrumb,
page,
neighbors,
};
}
89 changes: 89 additions & 0 deletions packages/ui/app/src/resolver/resolveChangelogPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { DocsV1Read } from "@fern-api/fdr-sdk";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { isNonNullish } from "@fern-ui/core-utils";
import type { MDX_SERIALIZER } from "../mdx/bundler";
import type { FernSerializeMdxOptions } from "../mdx/types";
import type { DocsContent } from "./DocsContent";
import { parseMarkdownPageToAnchorTag } from "./parseMarkdownPageToAnchorTag";

interface ResolveChangelogPageOptions {
node: FernNavigation.ChangelogNode;
breadcrumb: readonly FernNavigation.BreadcrumbItem[];
pages: Record<string, DocsV1Read.PageContent>;
serializeMdx: MDX_SERIALIZER;
mdxOptions: FernSerializeMdxOptions | undefined;
}

export async function resolveChangelogPage({
node,
breadcrumb,
pages,
serializeMdx,
mdxOptions,
}: ResolveChangelogPageOptions): Promise<DocsContent.ChangelogPage> {
const pageIds = new Set<FernNavigation.PageId>();
FernNavigation.traverseDF(node, (n) => {
if (FernNavigation.hasMarkdown(n)) {
const pageId = FernNavigation.getPageId(n);
if (pageId != null) {
pageIds.add(pageId);
}
}
});
const allPages = Object.fromEntries(
Object.entries(pages).map(([key, value]) => {
return [key, value.markdown];
}),
);
const pageRecords = (
await Promise.all(
[...pageIds].map(async (pageId) => {
const pageContent = pages[pageId];
if (pageContent == null) {
return;
}
return {
pageId,
markdown: await serializeMdx(pageContent.markdown, {
...mdxOptions,
filename: pageId,
files: { ...(mdxOptions?.files ?? {}), ...allPages },
}),
anchorTag: parseMarkdownPageToAnchorTag(pageContent.markdown),
};
}),
)
).filter(isNonNullish);

const markdown = node.overviewPageId != null ? pages[node.overviewPageId]?.markdown : undefined;

const page =
markdown != null
? await serializeMdx(markdown, {
...mdxOptions,
filename: node.overviewPageId,
})
: undefined;

/**
* if there are duplicate anchor tags, the anchor from the first page where it appears will be used
*/
const anchorIds: Record<string, FernNavigation.PageId> = {};
pageRecords.forEach((record) => {
if (record.anchorTag != null && anchorIds[record.anchorTag] == null) {
anchorIds[record.anchorTag] = record.pageId;
}
});

return {
type: "changelog",
breadcrumb,
title: (page != null && typeof page !== "string" ? page.frontmatter.title : undefined) ?? node.title,
node,
pages: Object.fromEntries(pageRecords.map((record) => [record.pageId, record.markdown])),
// items: await Promise.all(itemsPromise),
// neighbors,
slug: node.slug,
anchorIds,
};
}
Loading

0 comments on commit 488e327

Please sign in to comment.