From 79fad1c4611874e602b43f35544e85b9ef8da104 Mon Sep 17 00:00:00 2001 From: Rohin Bhargava Date: Mon, 29 Jul 2024 11:59:05 -0400 Subject: [PATCH 1/7] notes --- clis/docs-migrator/src/index.ts | 2 ++ packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/clis/docs-migrator/src/index.ts b/clis/docs-migrator/src/index.ts index c5cd6484f9..2007c5647e 100644 --- a/clis/docs-migrator/src/index.ts +++ b/clis/docs-migrator/src/index.ts @@ -128,6 +128,7 @@ export class MigrateFromMintlify { // copy all image files await Promise.all( this.imageFiles.map(async (file) => { + // TODO: (rohin) check here const absoluteFilePath = path.join(this.dir, file); const newFilePath = path.join(fernDir, file); await fs.promises.mkdir(path.dirname(newFilePath), { recursive: true }); @@ -248,6 +249,7 @@ export class MigrateFromMintlify { title: data.title, subtitle: data.description, layout: data.mode != null ? "reference" : undefined, + // TODO: (rohin) check here image: data["og:image"], slug, }, diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts index a81d590689..74170336b9 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts +++ b/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts @@ -115,6 +115,7 @@ function toFeedItem( if (frontmatter.image != null) { image = frontmatter.image; } else if (frontmatter["og:image"] != null) { + // TODO: (rohin) check here image = toUrl(frontmatter["og:image"], files); } From f6dcb97c3acd6fa731b0af49f61460197fe61745 Mon Sep 17 00:00:00 2001 From: Rohin Bhargava Date: Tue, 30 Jul 2024 15:32:38 -0400 Subject: [PATCH 2/7] frontmatter relative to absolute path --- .../utils/convertRelativeToAbsoluteUrl.ts | 18 ++++++++++++++++++ packages/fdr-sdk/src/navigation/utils/index.ts | 1 + .../ui/app/src/next-app/utils/getSeoProp.ts | 5 ++++- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts diff --git a/packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts b/packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts new file mode 100644 index 0000000000..9f379f60f9 --- /dev/null +++ b/packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts @@ -0,0 +1,18 @@ +export function convertRelativeToAbsoluteUrl(domain: string, slug: string, relativeUrl: string) { + const urlParts = relativeUrl.split("/"); + + const dirsAscendingCount = urlParts.reduce((acc, val) => acc + (val === ".." ? 1 : 0), 0); + const usableParts = urlParts.slice(dirsAscendingCount).join("/"); + + const slugParts = slug.split("/"); + + if (dirsAscendingCount <= slugParts.length) { + for (let i = 0; i < dirsAscendingCount; ++i) { + slugParts.pop(); + } + } else { + return `https://${domain}/${usableParts}`; + } + + return `https://${domain}/${slugParts.length > 0 ? `${slugParts.join("/")}/` : ""}${usableParts}`; +} diff --git a/packages/fdr-sdk/src/navigation/utils/index.ts b/packages/fdr-sdk/src/navigation/utils/index.ts index d2bbee9c9c..7a0c1c766f 100644 --- a/packages/fdr-sdk/src/navigation/utils/index.ts +++ b/packages/fdr-sdk/src/navigation/utils/index.ts @@ -2,6 +2,7 @@ export * from "./collectApiReferences"; export * from "./collectPageIds"; export * from "./convertAvailability"; export * from "./convertLoadDocsForUrlResponse"; +export * from "./convertRelativeToAbsoluteUrl"; export * from "./findNode"; export * from "./followRedirect"; export * from "./getApiReferenceId"; diff --git a/packages/ui/app/src/next-app/utils/getSeoProp.ts b/packages/ui/app/src/next-app/utils/getSeoProp.ts index cbb60a1a46..8d91232d1a 100644 --- a/packages/ui/app/src/next-app/utils/getSeoProp.ts +++ b/packages/ui/app/src/next-app/utils/getSeoProp.ts @@ -60,7 +60,10 @@ export function getSeoProps( // retrofit og:image if (frontmatter.image != null) { - ogMetadata["og:image"] ??= { type: "url", value: frontmatter.image }; + ogMetadata["og:image"] ??= { + type: "url", + value: FernNavigation.utils.convertRelativeToAbsoluteUrl(domain, node.slug, frontmatter.image), + }; } seo.title ??= frontmatter.title; From b934089836d5c75d59cb2f3e1fd6ffc4c871861e Mon Sep 17 00:00:00 2001 From: Rohin Bhargava Date: Tue, 30 Jul 2024 15:35:50 -0400 Subject: [PATCH 3/7] remove internal comments --- clis/docs-migrator/src/index.ts | 2 -- packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/clis/docs-migrator/src/index.ts b/clis/docs-migrator/src/index.ts index 2007c5647e..c5cd6484f9 100644 --- a/clis/docs-migrator/src/index.ts +++ b/clis/docs-migrator/src/index.ts @@ -128,7 +128,6 @@ export class MigrateFromMintlify { // copy all image files await Promise.all( this.imageFiles.map(async (file) => { - // TODO: (rohin) check here const absoluteFilePath = path.join(this.dir, file); const newFilePath = path.join(fernDir, file); await fs.promises.mkdir(path.dirname(newFilePath), { recursive: true }); @@ -249,7 +248,6 @@ export class MigrateFromMintlify { title: data.title, subtitle: data.description, layout: data.mode != null ? "reference" : undefined, - // TODO: (rohin) check here image: data["og:image"], slug, }, diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts index 74170336b9..a81d590689 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts +++ b/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts @@ -115,7 +115,6 @@ function toFeedItem( if (frontmatter.image != null) { image = frontmatter.image; } else if (frontmatter["og:image"] != null) { - // TODO: (rohin) check here image = toUrl(frontmatter["og:image"], files); } From 728f1ae44c43d536293bb5dbcec084074e80c597 Mon Sep 17 00:00:00 2001 From: Rohin Bhargava Date: Wed, 31 Jul 2024 16:23:57 -0400 Subject: [PATCH 4/7] frontmatter url injection --- clis/docs-migrator/package.json | 1 + clis/docs-migrator/src/fern.ts | 4 ++- clis/docs-migrator/src/index.ts | 2 ++ packages/ui/app/src/mdx/frontmatter.ts | 2 +- .../ui/app/src/next-app/utils/getSeoProp.ts | 25 ++++++++++++++++--- .../src/pages/api/fern-docs/changelog.ts | 3 ++- pnpm-lock.yaml | 3 +++ 7 files changed, 33 insertions(+), 7 deletions(-) diff --git a/clis/docs-migrator/package.json b/clis/docs-migrator/package.json index bb16358155..82f3517a2a 100644 --- a/clis/docs-migrator/package.json +++ b/clis/docs-migrator/package.json @@ -30,6 +30,7 @@ "dependencies": { "@fern-fern/docs-config": "^0.22.0", "@fern-ui/core-utils": "workspace:*", + "@fern-api/fdr-sdk": "workspace:*", "execa": "^5.1.1", "gray-matter": "^4.0.3", "lodash-es": "^4.17.21", diff --git a/clis/docs-migrator/src/fern.ts b/clis/docs-migrator/src/fern.ts index bcb1d4d67e..9193527ccd 100644 --- a/clis/docs-migrator/src/fern.ts +++ b/clis/docs-migrator/src/fern.ts @@ -1,3 +1,5 @@ +import { DocsV1Read } from "@fern-api/fdr-sdk"; + /** * The layout used for guides. This is the default layout. * Guides are typically long-form content that is meant to be read from start to finish. @@ -47,7 +49,7 @@ export interface FernDocsFrontmatter { /** * The URL to the page's image. This is used for the tag in the HTML. */ - image?: string; + image?: string | DocsV1Read.FileIdOrUrl; /** * Full slug of the page. diff --git a/clis/docs-migrator/src/index.ts b/clis/docs-migrator/src/index.ts index a2fe763fa6..60eb5a2684 100644 --- a/clis/docs-migrator/src/index.ts +++ b/clis/docs-migrator/src/index.ts @@ -243,12 +243,14 @@ export class MigrateFromMintlify { content, }; } + return { path: mintlify.path, data: { title: data.title, subtitle: data.description, layout: data.mode != null ? "reference" : undefined, + // TODO: (rohin) investigate this more; it seems like mintlify isn't reliant on fdr, so not sure if there's a transformation here. image: data["og:image"], slug, }, diff --git a/packages/ui/app/src/mdx/frontmatter.ts b/packages/ui/app/src/mdx/frontmatter.ts index bdee655378..a594acd1f3 100644 --- a/packages/ui/app/src/mdx/frontmatter.ts +++ b/packages/ui/app/src/mdx/frontmatter.ts @@ -72,7 +72,7 @@ export interface FernDocsFrontmatter extends DocsV1Read.MetadataConfig { /** * The URL to the page's image. This is used for the tag in the HTML. */ - image?: string; + image?: string | DocsV1Read.FileIdOrUrl; /** * Renders an "Edit this page" link at the bottom of the page. diff --git a/packages/ui/app/src/next-app/utils/getSeoProp.ts b/packages/ui/app/src/next-app/utils/getSeoProp.ts index f9471a73e5..0eda248be3 100644 --- a/packages/ui/app/src/next-app/utils/getSeoProp.ts +++ b/packages/ui/app/src/next-app/utils/getSeoProp.ts @@ -66,10 +66,27 @@ export function getSeoProps( // retrofit og:image if (frontmatter.image != null) { - ogMetadata["og:image"] ??= { - type: "url", - value: FernNavigation.utils.convertRelativeToAbsoluteUrl(domain, node.slug, frontmatter.image), - }; + // TODO: (rohin) remove string check when fully migrated, but keeping for back compat + if (typeof frontmatter.image === "string") { + ogMetadata["og:image"] = { + type: "url", + value: frontmatter.image, + }; + } else { + visitDiscriminatedUnion(frontmatter.image, "type")._visit({ + fileId: (fileId) => { + const realId = fileId.value.split(":")[1]; + if (realId != null) { + fileId.value = realId; + ogMetadata["og:image"] = fileId; + } + }, + url: (url) => { + ogMetadata["og:image"] = url; + }, + _other: undefined, + }); + } } seo.title ??= frontmatter.title; diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts index beb648917e..e9bac05682 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts +++ b/packages/ui/docs-bundle/src/pages/api/fern-docs/changelog.ts @@ -112,7 +112,8 @@ function toFeedItem( try { let image: string | undefined; - if (frontmatter.image != null) { + // TODO: (rohin) Clean up after safe deploy, but include for back compat + if (frontmatter.image != null && typeof frontmatter.image === "string") { image = frontmatter.image; } else if (frontmatter["og:image"] != null) { image = toUrl(frontmatter["og:image"], files); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4fc108ef56..056f24e617 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -175,6 +175,9 @@ importers: clis/docs-migrator: dependencies: + '@fern-api/fdr-sdk': + specifier: workspace:* + version: link:../../packages/fdr-sdk '@fern-fern/docs-config': specifier: ^0.22.0 version: 0.22.0 From 25437b6d6d63da14c8370a372d8af9a755308b59 Mon Sep 17 00:00:00 2001 From: Rohin Bhargava Date: Wed, 31 Jul 2024 16:25:13 -0400 Subject: [PATCH 5/7] delete useless files --- .../utils/convertRelativeToAbsoluteUrl.ts | 18 ------------------ packages/fdr-sdk/src/navigation/utils/index.ts | 1 - 2 files changed, 19 deletions(-) delete mode 100644 packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts diff --git a/packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts b/packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts deleted file mode 100644 index 9f379f60f9..0000000000 --- a/packages/fdr-sdk/src/navigation/utils/convertRelativeToAbsoluteUrl.ts +++ /dev/null @@ -1,18 +0,0 @@ -export function convertRelativeToAbsoluteUrl(domain: string, slug: string, relativeUrl: string) { - const urlParts = relativeUrl.split("/"); - - const dirsAscendingCount = urlParts.reduce((acc, val) => acc + (val === ".." ? 1 : 0), 0); - const usableParts = urlParts.slice(dirsAscendingCount).join("/"); - - const slugParts = slug.split("/"); - - if (dirsAscendingCount <= slugParts.length) { - for (let i = 0; i < dirsAscendingCount; ++i) { - slugParts.pop(); - } - } else { - return `https://${domain}/${usableParts}`; - } - - return `https://${domain}/${slugParts.length > 0 ? `${slugParts.join("/")}/` : ""}${usableParts}`; -} diff --git a/packages/fdr-sdk/src/navigation/utils/index.ts b/packages/fdr-sdk/src/navigation/utils/index.ts index 7a0c1c766f..d2bbee9c9c 100644 --- a/packages/fdr-sdk/src/navigation/utils/index.ts +++ b/packages/fdr-sdk/src/navigation/utils/index.ts @@ -2,7 +2,6 @@ export * from "./collectApiReferences"; export * from "./collectPageIds"; export * from "./convertAvailability"; export * from "./convertLoadDocsForUrlResponse"; -export * from "./convertRelativeToAbsoluteUrl"; export * from "./findNode"; export * from "./followRedirect"; export * from "./getApiReferenceId"; From b10b70fcafd3f8c29f84bf92f6f7257eb178ce0e Mon Sep 17 00:00:00 2001 From: Rohin Bhargava Date: Wed, 31 Jul 2024 16:47:25 -0400 Subject: [PATCH 6/7] ?? = --- packages/ui/app/src/next-app/utils/getSeoProp.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/app/src/next-app/utils/getSeoProp.ts b/packages/ui/app/src/next-app/utils/getSeoProp.ts index 0eda248be3..19a9ba4bfd 100644 --- a/packages/ui/app/src/next-app/utils/getSeoProp.ts +++ b/packages/ui/app/src/next-app/utils/getSeoProp.ts @@ -78,11 +78,11 @@ export function getSeoProps( const realId = fileId.value.split(":")[1]; if (realId != null) { fileId.value = realId; - ogMetadata["og:image"] = fileId; + ogMetadata["og:image"] ??= fileId; } }, url: (url) => { - ogMetadata["og:image"] = url; + ogMetadata["og:image"] ??= url; }, _other: undefined, }); From 1bb881354c4089121ac9f13c4a82443fb9905be9 Mon Sep 17 00:00:00 2001 From: Rohin Bhargava Date: Wed, 31 Jul 2024 16:54:27 -0400 Subject: [PATCH 7/7] add og:image check as well --- .../ui/app/src/next-app/utils/getSeoProp.ts | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/packages/ui/app/src/next-app/utils/getSeoProp.ts b/packages/ui/app/src/next-app/utils/getSeoProp.ts index 19a9ba4bfd..9824114b95 100644 --- a/packages/ui/app/src/next-app/utils/getSeoProp.ts +++ b/packages/ui/app/src/next-app/utils/getSeoProp.ts @@ -64,28 +64,31 @@ export function getSeoProps( const { data: frontmatter } = getFrontmatter(page.markdown); ogMetadata = { ...ogMetadata, ...frontmatter }; - // retrofit og:image - if (frontmatter.image != null) { - // TODO: (rohin) remove string check when fully migrated, but keeping for back compat - if (typeof frontmatter.image === "string") { - ogMetadata["og:image"] = { - type: "url", - value: frontmatter.image, - }; - } else { - visitDiscriminatedUnion(frontmatter.image, "type")._visit({ - fileId: (fileId) => { - const realId = fileId.value.split(":")[1]; - if (realId != null) { - fileId.value = realId; - ogMetadata["og:image"] ??= fileId; - } - }, - url: (url) => { - ogMetadata["og:image"] ??= url; - }, - _other: undefined, - }); + // retrofit og:image, preferring og:image + // TODO: (rohin) Come back here and support more image transformations (twitter, logo, etc) + for (const frontmatterImageVar of [frontmatter.image, frontmatter["og:image"]]) { + if (frontmatterImageVar != null) { + // TODO: (rohin) remove string check when fully migrated, but keeping for back compat + if (typeof frontmatterImageVar === "string") { + ogMetadata["og:image"] ??= { + type: "url", + value: frontmatterImageVar, + }; + } else { + visitDiscriminatedUnion(frontmatterImageVar, "type")._visit({ + fileId: (fileId) => { + const realId = fileId.value.split(":")[1]; + if (realId != null) { + fileId.value = realId; + ogMetadata["og:image"] = fileId; + } + }, + url: (url) => { + ogMetadata["og:image"] = url; + }, + _other: undefined, + }); + } } }