-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: split docs content resolver into multiple files (#1606)
- Loading branch information
1 parent
5aec8ab
commit 488e327
Showing
12 changed files
with
571 additions
and
369 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
packages/ui/app/src/resolver/parseMarkdownPageToAnchorTag.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; | ||
} |
Oops, something went wrong.