From 845ff68946a96636e40968ed0afebfec154730b7 Mon Sep 17 00:00:00 2001 From: Armano Date: Thu, 11 Mar 2021 08:47:16 +0100 Subject: [PATCH 1/4] refactor(v2): merge linkify function used in blog and docs --- .../src/blogUtils.ts | 75 +++++----------- .../src/markdown/linkify.ts | 87 +++++-------------- .../docusaurus-utils/src/markdownLinks.ts | 85 ++++++++++++++++++ 3 files changed, 129 insertions(+), 118 deletions(-) create mode 100644 packages/docusaurus-utils/src/markdownLinks.ts diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index d0f8e67f85b0..5f8d16f6f063 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -9,7 +9,6 @@ import fs from 'fs-extra'; import globby from 'globby'; import chalk from 'chalk'; import path from 'path'; -import {resolve} from 'url'; import readingTime from 'reading-time'; import {Feed} from 'feed'; import {keyBy} from 'lodash'; @@ -18,7 +17,6 @@ import { BlogPost, DateLink, BlogContentPaths, - BlogBrokenMarkdownLink, BlogMarkdownLoaderOptions, } from './types'; import { @@ -31,6 +29,7 @@ import { getDateTimeFormat, } from '@docusaurus/utils'; import {LoadContext} from '@docusaurus/types'; +import {replaceMarkdownLinks} from '@docusaurus/utils/lib/markdownLinks'; export function truncate(fileString: string, truncateMarker: RegExp): string { return fileString.split(truncateMarker, 1).shift()!; @@ -264,59 +263,25 @@ export function linkify({ blogPostsBySource, onBrokenMarkdownLink, }: LinkifyParams): string { - // TODO temporary, should consider the file being in localized folder! - const folderPath = contentPaths.contentPath; - - let fencedBlock = false; - const lines = fileContent.split('\n').map((line) => { - if (line.trim().startsWith('```')) { - fencedBlock = !fencedBlock; - } - - if (fencedBlock) { - return line; - } - - let modifiedLine = line; - const mdRegex = /(?:(?:\]\()|(?:\]:\s?))(?!https)([^'")\]\s>]+\.mdx?)/g; - let mdMatch = mdRegex.exec(modifiedLine); - - while (mdMatch !== null) { - const mdLink = mdMatch[1]; - - const aliasedSource = (source: string) => - aliasedSitePath(source, siteDir); - - const blogPost: BlogPost | undefined = - blogPostsBySource[aliasedSource(resolve(filePath, mdLink))] || - blogPostsBySource[ - aliasedSource(`${contentPaths.contentPathLocalized}/${mdLink}`) - ] || - blogPostsBySource[ - aliasedSource(`${contentPaths.contentPath}/${mdLink}`) - ]; - - if (blogPost) { - modifiedLine = modifiedLine.replace( - mdLink, - blogPost.metadata.permalink, - ); - } else { - const brokenMarkdownLink: BlogBrokenMarkdownLink = { - folderPath, - filePath, - link: mdLink, - }; - onBrokenMarkdownLink(brokenMarkdownLink); - } - - mdMatch = mdRegex.exec(modifiedLine); - } - - return modifiedLine; - }); - - return lines.join('\n'); + return replaceMarkdownLinks( + fileContent, + filePath, + contentPaths, + { + siteDir, + sourceToPermalink: blogPostsBySource, + onBrokenMarkdownLink(data) { + onBrokenMarkdownLink({ + // TODO: we should return here all contentPaths as we are checking them anyway + // TODO temporary, should consider the file being in localized folder! + folderPath: data.contentPaths.contentPath, + filePath: data.filePath, + link: data.link, + }); + }, + }, + (blogPost) => blogPost.metadata.permalink, + ); } // Order matters: we look in priority in localized folder diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts index 2697be19f953..835a1337bb6f 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts @@ -5,14 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -import {resolve} from 'url'; -import { - DocsMarkdownOption, - VersionMetadata, - BrokenMarkdownLink, -} from '../types'; +import {DocsMarkdownOption} from '../types'; import {getDocsDirPaths} from '../versions'; -import {aliasedSitePath} from '@docusaurus/utils'; +import {replaceMarkdownLinks} from '@docusaurus/utils/lib/markdownLinks'; function getVersion(filePath: string, options: DocsMarkdownOption) { const versionFound = options.versionsMetadata.find((version) => @@ -28,66 +23,32 @@ function getVersion(filePath: string, options: DocsMarkdownOption) { return versionFound; } -function replaceMarkdownLinks( - fileString: string, - filePath: string, - version: VersionMetadata, - options: DocsMarkdownOption, -) { - const {siteDir, sourceToPermalink, onBrokenMarkdownLink} = options; - const {docsDirPath, docsDirPathLocalized} = version; - - // Replace internal markdown linking (except in fenced blocks). - let fencedBlock = false; - const lines = fileString.split('\n').map((line) => { - if (line.trim().startsWith('```')) { - fencedBlock = !fencedBlock; - } - if (fencedBlock) { - return line; - } - - let modifiedLine = line; - // Replace inline-style links or reference-style links e.g: - // This is [Document 1](doc1.md) -> we replace this doc1.md with correct link - // [doc1]: doc1.md -> we replace this doc1.md with correct link - const mdRegex = /(?:(?:\]\()|(?:\]:\s?))(?!https)([^'")\]\s>]+\.mdx?)/g; - let mdMatch = mdRegex.exec(modifiedLine); - while (mdMatch !== null) { - // Replace it to correct html link. - const mdLink = mdMatch[1]; - - const aliasedSource = (source: string) => - aliasedSitePath(source, siteDir); - - const permalink = - sourceToPermalink[aliasedSource(resolve(filePath, mdLink))] || - sourceToPermalink[aliasedSource(`${docsDirPathLocalized}/${mdLink}`)] || - sourceToPermalink[aliasedSource(`${docsDirPath}/${mdLink}`)]; - - if (permalink) { - modifiedLine = modifiedLine.replace(mdLink, permalink); - } else { - const brokenMarkdownLink: BrokenMarkdownLink = { - version, - filePath, - link: mdLink, - }; - onBrokenMarkdownLink(brokenMarkdownLink); - } - mdMatch = mdRegex.exec(modifiedLine); - } - return modifiedLine; - }); - - return lines.join('\n'); -} - export function linkify( fileString: string, filePath: string, options: DocsMarkdownOption, ): string { const version = getVersion(filePath, options); - return replaceMarkdownLinks(fileString, filePath, version, options); + return replaceMarkdownLinks( + fileString, + filePath, + { + // TODO: refactor names and we can pass version here + contentPath: version.docsDirPath, + contentPathLocalized: version.docsDirPathLocalized, + }, + { + siteDir: options.siteDir, + sourceToPermalink: options.sourceToPermalink, + onBrokenMarkdownLink(brokenMarkdownLink) { + options.onBrokenMarkdownLink({ + // TODO: refactor version to contentPaths + version, + filePath: brokenMarkdownLink.filePath, + link: brokenMarkdownLink.link, + }); + }, + }, + (permalink) => permalink, + ); } diff --git a/packages/docusaurus-utils/src/markdownLinks.ts b/packages/docusaurus-utils/src/markdownLinks.ts new file mode 100644 index 000000000000..876a5a160650 --- /dev/null +++ b/packages/docusaurus-utils/src/markdownLinks.ts @@ -0,0 +1,85 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {resolve} from 'url'; +import {aliasedSitePath} from './index'; + +export type ContentPaths = { + contentPath: string; + contentPathLocalized: string; +}; + +export type BrokenMarkdownLink = { + filePath: string; + contentPaths: T; + link: string; +}; + +export type ReplaceMarkdownLinksParams< + T extends ContentPaths, + S extends unknown +> = { + siteDir: string; + sourceToPermalink: Record; + onBrokenMarkdownLink: (brokenMarkdownLink: BrokenMarkdownLink) => void; +}; + +export function replaceMarkdownLinks( + fileString: string, + filePath: string, + contentPaths: T, + options: ReplaceMarkdownLinksParams, + getPermalink: (alias: S) => string, +): string { + const {siteDir, sourceToPermalink, onBrokenMarkdownLink} = options; + const {contentPath, contentPathLocalized} = contentPaths; + + // Replace internal markdown linking (except in fenced blocks). + let fencedBlock = false; + const lines = fileString.split('\n').map((line) => { + if (line.trim().startsWith('```')) { + fencedBlock = !fencedBlock; + } + if (fencedBlock) { + return line; + } + + let modifiedLine = line; + // Replace inline-style links or reference-style links e.g: + // This is [Document 1](doc1.md) -> we replace this doc1.md with correct link + // [doc1]: doc1.md -> we replace this doc1.md with correct link + const mdRegex = /(?:(?:\]\()|(?:\]:\s?))(?!https)([^'")\]\s>]+\.mdx?)/g; + let mdMatch = mdRegex.exec(modifiedLine); + while (mdMatch !== null) { + // Replace it to correct html link. + const mdLink = mdMatch[1]; + + const aliasedSource = (source: string) => + aliasedSitePath(source, siteDir); + + const permalink = + sourceToPermalink[aliasedSource(resolve(filePath, mdLink))] || + sourceToPermalink[aliasedSource(`${contentPathLocalized}/${mdLink}`)] || + sourceToPermalink[aliasedSource(`${contentPath}/${mdLink}`)]; + + if (permalink) { + modifiedLine = modifiedLine.replace(mdLink, getPermalink(permalink)); + } else { + const brokenMarkdownLink: BrokenMarkdownLink = { + contentPaths, + filePath, + link: mdLink, + }; + onBrokenMarkdownLink(brokenMarkdownLink); + } + mdMatch = mdRegex.exec(modifiedLine); + } + return modifiedLine; + }); + + return lines.join('\n'); +} From c3721a6a1c4577932a0eddd0b95751ca371771eb Mon Sep 17 00:00:00 2001 From: Armano Date: Thu, 11 Mar 2021 11:48:44 +0100 Subject: [PATCH 2/4] refactor(v2): rename docsDirPath and docsDirPathLocalized ad update types --- .../__snapshots__/translations.test.ts.snap | 12 +++--- .../src/__tests__/docs.test.ts | 4 +- .../src/__tests__/index.test.ts | 14 +++---- .../src/__tests__/translations.test.ts | 4 +- .../src/__tests__/versions.test.ts | 28 ++++++------- .../src/docs.ts | 18 ++++---- .../src/index.ts | 4 +- .../src/markdown/__tests__/linkify.test.ts | 42 +++++++++---------- .../src/markdown/linkify.ts | 19 +-------- .../src/types.ts | 19 +++++---- .../src/versions.ts | 42 +++++++++---------- 11 files changed, 96 insertions(+), 110 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap index 73415461db93..2344d708297b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap @@ -60,6 +60,8 @@ exports[`translateLoadedContent should return translated loaded content matching Object { "loadedVersions": Array [ Object { + "contentPath": "any", + "contentPathLocalized": "any", "docs": Array [ Object { "description": "doc1 description", @@ -147,8 +149,6 @@ Object { "version": "any", }, ], - "docsDirPath": "any", - "docsDirPathLocalized": "any", "isLast": true, "mainDocId": "", "permalinkToSidebar": Object {}, @@ -201,6 +201,8 @@ Object { "versionPath": "/docs/", }, Object { + "contentPath": "any", + "contentPathLocalized": "any", "docs": Array [ Object { "description": "doc1 description", @@ -288,8 +290,6 @@ Object { "version": "any", }, ], - "docsDirPath": "any", - "docsDirPathLocalized": "any", "isLast": true, "mainDocId": "", "permalinkToSidebar": Object {}, @@ -342,6 +342,8 @@ Object { "versionPath": "/docs/", }, Object { + "contentPath": "any", + "contentPathLocalized": "any", "docs": Array [ Object { "description": "doc1 description", @@ -429,8 +431,6 @@ Object { "version": "any", }, ], - "docsDirPath": "any", - "docsDirPathLocalized": "any", "isLast": true, "mainDocId": "", "permalinkToSidebar": Object {}, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index bb8021e61c2f..5c1feb6b157d 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -45,7 +45,7 @@ ${markdown} source, content, lastUpdate: {}, - docsDirPath: 'docs', + contentPath: 'docs', filePath: source, }; }; @@ -93,7 +93,7 @@ function createTestUtils({ editUrl: undefined, source: path.posix.join( '@site', - posixPath(path.relative(siteDir, versionMetadata.docsDirPath)), + posixPath(path.relative(siteDir, versionMetadata.contentPath)), posixPath(docFileSource), ), ...expectedMetadata, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 753b977c7d05..03ad2772c2b6 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -254,7 +254,7 @@ describe('simple website', () => { sidebar: 'docs', source: path.posix.join( '@site', - posixPath(path.relative(siteDir, currentVersion.docsDirPath)), + posixPath(path.relative(siteDir, currentVersion.contentPath)), 'hello.md', ), title: 'Hello, World !', @@ -276,7 +276,7 @@ describe('simple website', () => { sidebar: 'docs', source: path.posix.join( '@site', - posixPath(path.relative(siteDir, currentVersion.docsDirPath)), + posixPath(path.relative(siteDir, currentVersion.contentPath)), 'foo', 'bar.md', ), @@ -424,7 +424,7 @@ describe('versioned website', () => { slug: '/foo/barSlug', source: path.posix.join( '@site', - posixPath(path.relative(siteDir, currentVersion.docsDirPath)), + posixPath(path.relative(siteDir, currentVersion.contentPath)), 'foo', 'bar.md', ), @@ -446,7 +446,7 @@ describe('versioned website', () => { slug: '/', source: path.posix.join( '@site', - posixPath(path.relative(siteDir, currentVersion.docsDirPath)), + posixPath(path.relative(siteDir, currentVersion.contentPath)), 'hello.md', ), title: 'hello', @@ -467,7 +467,7 @@ describe('versioned website', () => { slug: '/', source: path.posix.join( '@site', - posixPath(path.relative(siteDir, version101.docsDirPath)), + posixPath(path.relative(siteDir, version101.contentPath)), 'hello.md', ), title: 'hello', @@ -488,7 +488,7 @@ describe('versioned website', () => { slug: '/foo/baz', source: path.posix.join( '@site', - posixPath(path.relative(siteDir, version100.docsDirPath)), + posixPath(path.relative(siteDir, version100.contentPath)), 'foo', 'baz.md', ), @@ -649,7 +649,7 @@ describe('versioned website (community)', () => { slug: '/team', source: path.posix.join( '@site', - posixPath(path.relative(siteDir, version100.docsDirPath)), + posixPath(path.relative(siteDir, version100.contentPath)), 'team.md', ), title: 'team', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts index a3be1c6c0bf3..21f0d8b55d65 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts @@ -44,8 +44,8 @@ function createSampleVersion( routePriority: undefined, sidebarFilePath: 'any', isLast: true, - docsDirPath: 'any', - docsDirPathLocalized: 'any', + contentPath: 'any', + contentPathLocalized: 'any', docs: [ createSampleDoc({ id: 'doc1', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts index c5108e5fbda7..7191f66cba8b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts @@ -68,8 +68,8 @@ describe('simple site', () => { }; const vCurrent: VersionMetadata = { - docsDirPath: path.join(simpleSiteDir, 'docs'), - docsDirPathLocalized: path.join( + contentPath: path.join(simpleSiteDir, 'docs'), + contentPathLocalized: path.join( simpleSiteDir, 'i18n/en/docusaurus-plugin-content-docs/current', ), @@ -218,8 +218,8 @@ describe('versioned site, pluginId=default', () => { }; const vCurrent: VersionMetadata = { - docsDirPath: path.join(versionedSiteDir, 'docs'), - docsDirPathLocalized: path.join( + contentPath: path.join(versionedSiteDir, 'docs'), + contentPathLocalized: path.join( versionedSiteDir, 'i18n/en/docusaurus-plugin-content-docs/current', ), @@ -232,8 +232,8 @@ describe('versioned site, pluginId=default', () => { }; const v101: VersionMetadata = { - docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.1'), - docsDirPathLocalized: path.join( + contentPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.1'), + contentPathLocalized: path.join( versionedSiteDir, 'i18n/en/docusaurus-plugin-content-docs/version-1.0.1', ), @@ -249,8 +249,8 @@ describe('versioned site, pluginId=default', () => { }; const v100: VersionMetadata = { - docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.0'), - docsDirPathLocalized: path.join( + contentPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.0'), + contentPathLocalized: path.join( versionedSiteDir, 'i18n/en/docusaurus-plugin-content-docs/version-1.0.0', ), @@ -266,11 +266,11 @@ describe('versioned site, pluginId=default', () => { }; const vwithSlugs: VersionMetadata = { - docsDirPath: path.join( + contentPath: path.join( versionedSiteDir, 'versioned_docs/version-withSlugs', ), - docsDirPathLocalized: path.join( + contentPathLocalized: path.join( versionedSiteDir, 'i18n/en/docusaurus-plugin-content-docs/version-withSlugs', ), @@ -615,8 +615,8 @@ describe('versioned site, pluginId=community', () => { }; const vCurrent: VersionMetadata = { - docsDirPath: path.join(versionedSiteDir, 'community'), - docsDirPathLocalized: path.join( + contentPath: path.join(versionedSiteDir, 'community'), + contentPathLocalized: path.join( versionedSiteDir, 'i18n/en/docusaurus-plugin-content-docs-community/current', ), @@ -629,11 +629,11 @@ describe('versioned site, pluginId=community', () => { }; const v100: VersionMetadata = { - docsDirPath: path.join( + contentPath: path.join( versionedSiteDir, 'community_versioned_docs/version-1.0.0', ), - docsDirPathLocalized: path.join( + contentPathLocalized: path.join( versionedSiteDir, 'i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0', ), diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index 0f8d720d178e..3863d8f25ace 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -67,23 +67,23 @@ async function readLastUpdateData( export async function readDocFile( versionMetadata: Pick< VersionMetadata, - 'docsDirPath' | 'docsDirPathLocalized' + 'contentPath' | 'contentPathLocalized' >, source: string, options: LastUpdateOptions, ): Promise { - const docsDirPath = await getFolderContainingFile( + const contentPath = await getFolderContainingFile( getDocsDirPaths(versionMetadata), source, ); - const filePath = path.join(docsDirPath, source); + const filePath = path.join(contentPath, source); const [content, lastUpdate] = await Promise.all([ fs.readFile(filePath, 'utf-8'), readLastUpdateData(filePath, options), ]); - return {source, content, lastUpdate, docsDirPath, filePath}; + return {source, content, lastUpdate, contentPath, filePath}; } export async function readVersionDocs( @@ -94,7 +94,7 @@ export async function readVersionDocs( >, ): Promise { const sources = await globby(options.include, { - cwd: versionMetadata.docsDirPath, + cwd: versionMetadata.contentPath, }); return Promise.all( sources.map((source) => readDocFile(versionMetadata, source, options)), @@ -112,7 +112,7 @@ export function processDocMetadata({ context: LoadContext; options: MetadataOptions; }): DocMetadataBase { - const {source, content, lastUpdate, docsDirPath, filePath} = docFile; + const {source, content, lastUpdate, contentPath, filePath} = docFile; const {homePageId} = options; const {siteDir, i18n} = context; @@ -170,20 +170,20 @@ export function processDocMetadata({ const permalink = normalizeUrl([versionMetadata.versionPath, docSlug]); function getDocEditUrl() { - const relativeFilePath = path.relative(docsDirPath, filePath); + const relativeFilePath = path.relative(contentPath, filePath); if (typeof options.editUrl === 'function') { return options.editUrl({ version: versionMetadata.versionName, versionDocsDirPath: posixPath( - path.relative(siteDir, versionMetadata.docsDirPath), + path.relative(siteDir, versionMetadata.contentPath), ), docPath: posixPath(relativeFilePath), permalink, locale: context.i18n.currentLocale, }); } else if (typeof options.editUrl === 'string') { - const isLocalized = docsDirPath === versionMetadata.docsDirPathLocalized; + const isLocalized = contentPath === versionMetadata.contentPathLocalized; const baseVersionEditUrl = isLocalized && options.editLocalizedFiles ? versionMetadata.versionEditUrlLocalized diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 05e64ba0d99c..2f09210ce70a 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -145,7 +145,7 @@ export default function pluginContentDocs( versionMetadata.versionName } has no docs! At least one doc should exist at path=[${path.relative( siteDir, - versionMetadata.docsDirPath, + versionMetadata.contentPath, )}]`, ); } @@ -337,7 +337,7 @@ export default function pluginContentDocs( return; } reportMessage( - `Docs markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath} for version ${brokenMarkdownLink.version.versionName}`, + `Docs markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath} for version ${brokenMarkdownLink.contentPaths.versionName}`, siteConfig.onBrokenMarkdownLinks, ); }, diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts index 7fe3e179da37..78b47b2b32a6 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts @@ -18,19 +18,19 @@ import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants'; function createFakeVersion({ versionName, - docsDirPath, - docsDirPathLocalized, + contentPath, + contentPathLocalized, }: { versionName: string; - docsDirPath: string; - docsDirPathLocalized: string; + contentPath: string; + contentPathLocalized: string; }): VersionMetadata { return { versionName, versionLabel: 'Any', versionPath: 'any', - docsDirPath, - docsDirPathLocalized, + contentPath, + contentPathLocalized, sidebarFilePath: 'any', routePriority: undefined, isLast: false, @@ -41,8 +41,8 @@ const siteDir = path.join(__dirname, '__fixtures__'); const versionCurrent = createFakeVersion({ versionName: CURRENT_VERSION_NAME, - docsDirPath: path.join(siteDir, 'docs'), - docsDirPathLocalized: path.join( + contentPath: path.join(siteDir, 'docs'), + contentPathLocalized: path.join( siteDir, 'i18n', 'fr', @@ -53,8 +53,8 @@ const versionCurrent = createFakeVersion({ const version100 = createFakeVersion({ versionName: '1.0.0', - docsDirPath: path.join(siteDir, VERSIONED_DOCS_DIR, 'version-1.0.0'), - docsDirPathLocalized: path.join( + contentPath: path.join(siteDir, VERSIONED_DOCS_DIR, 'version-1.0.0'), + contentPathLocalized: path.join( siteDir, 'i18n', 'fr', @@ -97,14 +97,14 @@ const transform = (filepath: string, options?: Partial) => { }; test('transform nothing', () => { - const doc1 = path.join(versionCurrent.docsDirPath, 'doc1.md'); + const doc1 = path.join(versionCurrent.contentPath, 'doc1.md'); const [content, transformedContent] = transform(doc1); expect(transformedContent).toMatchSnapshot(); expect(content).toEqual(transformedContent); }); test('transform to correct links', () => { - const doc2 = path.join(versionCurrent.docsDirPath, 'doc2.md'); + const doc2 = path.join(versionCurrent.contentPath, 'doc2.md'); const [content, transformedContent] = transform(doc2); expect(transformedContent).toMatchSnapshot(); expect(transformedContent).toContain('](/docs/doc1'); @@ -119,7 +119,7 @@ test('transform to correct links', () => { }); test('transform relative links', () => { - const doc3 = path.join(versionCurrent.docsDirPath, 'subdir', 'doc3.md'); + const doc3 = path.join(versionCurrent.contentPath, 'subdir', 'doc3.md'); const [content, transformedContent] = transform(doc3); expect(transformedContent).toMatchSnapshot(); @@ -129,7 +129,7 @@ test('transform relative links', () => { }); test('transforms reference links', () => { - const doc4 = path.join(versionCurrent.docsDirPath, 'doc4.md'); + const doc4 = path.join(versionCurrent.contentPath, 'doc4.md'); const [content, transformedContent] = transform(doc4); expect(transformedContent).toMatchSnapshot(); expect(transformedContent).toContain('[doc1]: /docs/doc1'); @@ -140,7 +140,7 @@ test('transforms reference links', () => { }); test('report broken markdown links', () => { - const doc5 = path.join(versionCurrent.docsDirPath, 'doc5.md'); + const doc5 = path.join(versionCurrent.contentPath, 'doc5.md'); const onBrokenMarkdownLink = jest.fn(); const [content, transformedContent] = transform(doc5, { onBrokenMarkdownLink, @@ -150,27 +150,27 @@ test('report broken markdown links', () => { expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(1, { filePath: doc5, link: 'docNotExist1.md', - version: versionCurrent, + contentPaths: versionCurrent, } as BrokenMarkdownLink); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, { filePath: doc5, link: './docNotExist2.mdx', - version: versionCurrent, + contentPaths: versionCurrent, } as BrokenMarkdownLink); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(3, { filePath: doc5, link: '../docNotExist3.mdx', - version: versionCurrent, + contentPaths: versionCurrent, } as BrokenMarkdownLink); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(4, { filePath: doc5, link: './subdir/docNotExist4.md', - version: versionCurrent, + contentPaths: versionCurrent, } as BrokenMarkdownLink); }); test('transforms absolute links in versioned docs', () => { - const doc2 = path.join(version100.docsDirPath, 'doc2.md'); + const doc2 = path.join(version100.contentPath, 'doc2.md'); const [content, transformedContent] = transform(doc2); expect(transformedContent).toMatchSnapshot(); expect(transformedContent).toContain('](/docs/1.0.0/subdir/doc1'); @@ -181,7 +181,7 @@ test('transforms absolute links in versioned docs', () => { }); test('transforms relative links in versioned docs', () => { - const doc1 = path.join(version100.docsDirPath, 'subdir', 'doc1.md'); + const doc1 = path.join(version100.contentPath, 'subdir', 'doc1.md'); const [content, transformedContent] = transform(doc1); expect(transformedContent).toMatchSnapshot(); expect(transformedContent).toContain('](/docs/1.0.0/doc2'); diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts index 835a1337bb6f..1ddb525b2903 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts @@ -32,23 +32,8 @@ export function linkify( return replaceMarkdownLinks( fileString, filePath, - { - // TODO: refactor names and we can pass version here - contentPath: version.docsDirPath, - contentPathLocalized: version.docsDirPathLocalized, - }, - { - siteDir: options.siteDir, - sourceToPermalink: options.sourceToPermalink, - onBrokenMarkdownLink(brokenMarkdownLink) { - options.onBrokenMarkdownLink({ - // TODO: refactor version to contentPaths - version, - filePath: brokenMarkdownLink.filePath, - link: brokenMarkdownLink.link, - }); - }, - }, + version, + options, (permalink) => permalink, ); } diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index 4a430f2113b9..25261ad0b972 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -8,8 +8,13 @@ // eslint-disable-next-line spaced-comment /// +import { + BrokenMarkdownLink as IBrokenMarkdownLink, + ContentPaths, +} from '@docusaurus/utils/lib/markdownLinks'; + export type DocFile = { - docsDirPath: string; // /!\ may be localized + contentPath: string; // /!\ may be localized filePath: string; // /!\ may be localized source: string; content: string; @@ -18,15 +23,15 @@ export type DocFile = { export type VersionName = string; -export type VersionMetadata = { +export type VersionMetadata = ContentPaths & { versionName: VersionName; // 1.0.0 versionLabel: string; // Version 1.0.0 versionPath: string; // /baseUrl/docs/1.0.0 versionEditUrl?: string | undefined; versionEditUrlLocalized?: string | undefined; isLast: boolean; - docsDirPath: string; // "versioned_docs/version-1.0.0" - docsDirPathLocalized: string; // "i18n/fr/version-1.0.0/default" + // contentPath: string; // "versioned_docs/version-1.0.0" + // contentPathLocalized: string; // "i18n/fr/version-1.0.0/default" sidebarFilePath: string; // versioned_sidebars/1.0.0.json routePriority: number | undefined; // -1 for the latest docs }; @@ -192,11 +197,7 @@ export type GlobalPluginData = { versions: GlobalVersion[]; }; -export type BrokenMarkdownLink = { - filePath: string; - version: VersionMetadata; - link: string; -}; +export type BrokenMarkdownLink = IBrokenMarkdownLink; export type DocsMarkdownOption = { versionsMetadata: VersionMetadata[]; diff --git a/packages/docusaurus-plugin-content-docs/src/versions.ts b/packages/docusaurus-plugin-content-docs/src/versions.ts index 2cc9a13a56c7..2131c3c628bf 100644 --- a/packages/docusaurus-plugin-content-docs/src/versions.ts +++ b/packages/docusaurus-plugin-content-docs/src/versions.ts @@ -165,18 +165,18 @@ function getVersionMetadataPaths({ options: Pick; }): Pick< VersionMetadata, - 'docsDirPath' | 'docsDirPathLocalized' | 'sidebarFilePath' + 'contentPath' | 'contentPathLocalized' | 'sidebarFilePath' > { const isCurrentVersion = versionName === CURRENT_VERSION_NAME; - const docsDirPath = isCurrentVersion + const contentPath = isCurrentVersion ? path.resolve(context.siteDir, options.path) : path.join( getVersionedDocsDirPath(context.siteDir, options.id), `version-${versionName}`, ); - const docsDirPathLocalized = getDocsDirPathLocalized({ + const contentPathLocalized = getDocsDirPathLocalized({ siteDir: context.siteDir, locale: context.i18n.currentLocale, pluginId: options.id, @@ -190,17 +190,17 @@ function getVersionMetadataPaths({ `version-${versionName}-sidebars.json`, ); - return {docsDirPath, docsDirPathLocalized, sidebarFilePath}; + return {contentPath, contentPathLocalized, sidebarFilePath}; } function getVersionEditUrls({ - docsDirPath, - docsDirPathLocalized, + contentPath, + contentPathLocalized, context: {siteDir, i18n}, options: {id, path: currentVersionPath, editUrl, editCurrentVersion}, }: { - docsDirPath: string; - docsDirPathLocalized: string; + contentPath: string; + contentPathLocalized: string; context: Pick; options: Pick< PluginOptions, @@ -217,7 +217,7 @@ function getVersionEditUrls({ return undefined; } - const editDirPath = editCurrentVersion ? currentVersionPath : docsDirPath; + const editDirPath = editCurrentVersion ? currentVersionPath : contentPath; const editDirPathLocalized = editCurrentVersion ? getDocsDirPathLocalized({ siteDir, @@ -225,7 +225,7 @@ function getVersionEditUrls({ versionName: CURRENT_VERSION_NAME, pluginId: id, }) - : docsDirPathLocalized; + : contentPathLocalized; const versionPathSegment = posixPath( path.relative(siteDir, path.resolve(siteDir, editDirPath)), @@ -269,8 +269,8 @@ function createVersionMetadata({ }): VersionMetadata { const { sidebarFilePath, - docsDirPath, - docsDirPathLocalized, + contentPath, + contentPathLocalized, } = getVersionMetadataPaths({ versionName, context, @@ -298,8 +298,8 @@ function createVersionMetadata({ ]); const versionEditUrls = getVersionEditUrls({ - docsDirPath, - docsDirPathLocalized, + contentPath, + contentPathLocalized, context, options, }); @@ -316,8 +316,8 @@ function createVersionMetadata({ isLast, routePriority, sidebarFilePath, - docsDirPath, - docsDirPathLocalized, + contentPath, + contentPathLocalized, }; } @@ -328,14 +328,14 @@ function checkVersionMetadataPaths({ versionMetadata: VersionMetadata; context: Pick; }) { - const {versionName, docsDirPath, sidebarFilePath} = versionMetadata; + const {versionName, contentPath, sidebarFilePath} = versionMetadata; const {siteDir} = context; - if (!fs.existsSync(docsDirPath)) { + if (!fs.existsSync(contentPath)) { throw new Error( `The docs folder does not exist for version [${versionName}]. A docs folder is expected to be found at ${path.relative( siteDir, - docsDirPath, + contentPath, )}`, ); } @@ -483,8 +483,8 @@ export function readVersionsMetadata({ export function getDocsDirPaths( versionMetadata: Pick< VersionMetadata, - 'docsDirPath' | 'docsDirPathLocalized' + 'contentPath' | 'contentPathLocalized' >, ): [string, string] { - return [versionMetadata.docsDirPathLocalized, versionMetadata.docsDirPath]; + return [versionMetadata.contentPathLocalized, versionMetadata.contentPath]; } From c126d807f357cf63c30c5ba0bfda7b96c088de4a Mon Sep 17 00:00:00 2001 From: Armano Date: Thu, 11 Mar 2021 11:49:33 +0100 Subject: [PATCH 3/4] refactor(v2): rename blogPostsBySource and update types --- .../src/__tests__/linkify.test.ts | 6 +++--- .../src/blogUtils.ts | 16 ++++------------ .../src/index.ts | 2 +- .../src/types.ts | 18 ++++++++---------- 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts index 2b54311cb3d0..323af95c8628 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts @@ -46,7 +46,7 @@ const transform = (filePath: string, options?: Partial) => { fileContent, siteDir, contentPaths, - blogPostsBySource: getPostsBySource(blogPosts), + sourceToPermalink: getPostsBySource(blogPosts), onBrokenMarkdownLink: (brokenMarkdownLink) => { throw new Error( `Broken markdown link found: ${JSON.stringify(brokenMarkdownLink)}`, @@ -82,12 +82,12 @@ test('report broken markdown links', () => { expect(onBrokenMarkdownLink).toHaveBeenCalledTimes(2); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(1, { filePath: path.resolve(folderPath, filePath), - folderPath, + contentPaths, link: 'postNotExist1.md', } as BlogBrokenMarkdownLink); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, { filePath: path.resolve(folderPath, filePath), - folderPath, + contentPaths, link: './postNotExist2.mdx', } as BlogBrokenMarkdownLink); }); diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 5f8d16f6f063..2c25b6dfba25 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -252,7 +252,7 @@ export type LinkifyParams = { fileContent: string; } & Pick< BlogMarkdownLoaderOptions, - 'blogPostsBySource' | 'siteDir' | 'contentPaths' | 'onBrokenMarkdownLink' + 'sourceToPermalink' | 'siteDir' | 'contentPaths' | 'onBrokenMarkdownLink' >; export function linkify({ @@ -260,7 +260,7 @@ export function linkify({ contentPaths, fileContent, siteDir, - blogPostsBySource, + sourceToPermalink, onBrokenMarkdownLink, }: LinkifyParams): string { return replaceMarkdownLinks( @@ -269,16 +269,8 @@ export function linkify({ contentPaths, { siteDir, - sourceToPermalink: blogPostsBySource, - onBrokenMarkdownLink(data) { - onBrokenMarkdownLink({ - // TODO: we should return here all contentPaths as we are checking them anyway - // TODO temporary, should consider the file being in localized folder! - folderPath: data.contentPaths.contentPath, - filePath: data.filePath, - link: data.link, - }); - }, + sourceToPermalink, + onBrokenMarkdownLink, }, (blogPost) => blogPost.metadata.permalink, ); diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 81339e64c067..1803120b0d20 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -416,7 +416,7 @@ export default function pluginContentBlog( siteDir, contentPaths, truncateMarker, - blogPostsBySource: getPostsBySource(blogPosts), + sourceToPermalink: getPostsBySource(blogPosts), onBrokenMarkdownLink: (brokenMarkdownLink) => { if (onBrokenMarkdownLinks === 'ignore') { return; diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index cb3ae53e63e9..e2eeaf11cb31 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -5,10 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -export type BlogContentPaths = { - contentPath: string; - contentPathLocalized: string; -}; +import { + BrokenMarkdownLink, + ContentPaths, +} from '@docusaurus/utils/lib/markdownLinks'; + +export type BlogContentPaths = ContentPaths; export interface BlogContent { blogPosts: BlogPost[]; @@ -142,15 +144,11 @@ export interface TagModule { permalink: string; } -export type BlogBrokenMarkdownLink = { - folderPath: string; - filePath: string; - link: string; -}; +export type BlogBrokenMarkdownLink = BrokenMarkdownLink; export type BlogMarkdownLoaderOptions = { siteDir: string; contentPaths: BlogContentPaths; truncateMarker: RegExp; - blogPostsBySource: Record; + sourceToPermalink: Record; onBrokenMarkdownLink: (brokenMarkdownLink: BlogBrokenMarkdownLink) => void; }; From 01a6faeb044602b946689c4d891b4ac902defc30 Mon Sep 17 00:00:00 2001 From: slorber Date: Fri, 12 Mar 2021 14:49:28 +0100 Subject: [PATCH 4/4] improve replaceMarkdownLinks api --- .../src/__tests__/linkify.test.ts | 6 +-- .../src/blogUtils.ts | 33 +++++++------- .../src/index.ts | 4 +- .../src/markdownLoader.ts | 4 +- .../src/types.ts | 2 +- .../src/markdown/linkify.ts | 17 ++++--- .../docusaurus-utils/src/markdownLinks.ts | 44 +++++++++++-------- 7 files changed, 63 insertions(+), 47 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts index 323af95c8628..c1b1a550c723 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts @@ -7,7 +7,7 @@ import fs from 'fs-extra'; import path from 'path'; -import {linkify, LinkifyParams, getPostsBySource} from '../blogUtils'; +import {linkify, LinkifyParams, getSourceToPermalink} from '../blogUtils'; import {BlogBrokenMarkdownLink, BlogContentPaths, BlogPost} from '../types'; const siteDir = path.join(__dirname, '__fixtures__', 'website'); @@ -43,10 +43,10 @@ const transform = (filePath: string, options?: Partial) => { const fileContent = fs.readFileSync(filePath, 'utf-8'); const transformedContent = linkify({ filePath, - fileContent, + fileString: fileContent, siteDir, contentPaths, - sourceToPermalink: getPostsBySource(blogPosts), + sourceToPermalink: getSourceToPermalink(blogPosts), onBrokenMarkdownLink: (brokenMarkdownLink) => { throw new Error( `Broken markdown link found: ${JSON.stringify(brokenMarkdownLink)}`, diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 2c25b6dfba25..439aab7b7d34 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -11,7 +11,7 @@ import chalk from 'chalk'; import path from 'path'; import readingTime from 'reading-time'; import {Feed} from 'feed'; -import {keyBy} from 'lodash'; +import {keyBy, mapValues} from 'lodash'; import { PluginOptions, BlogPost, @@ -35,10 +35,13 @@ export function truncate(fileString: string, truncateMarker: RegExp): string { return fileString.split(truncateMarker, 1).shift()!; } -export function getPostsBySource( +export function getSourceToPermalink( blogPosts: BlogPost[], -): Record { - return keyBy(blogPosts, (item) => item.metadata.source); +): Record { + return mapValues( + keyBy(blogPosts, (item) => item.metadata.source), + (v) => v.metadata.permalink, + ); } // YYYY-MM-DD-{name}.mdx? @@ -249,7 +252,7 @@ export async function generateBlogPosts( export type LinkifyParams = { filePath: string; - fileContent: string; + fileString: string; } & Pick< BlogMarkdownLoaderOptions, 'sourceToPermalink' | 'siteDir' | 'contentPaths' | 'onBrokenMarkdownLink' @@ -258,22 +261,22 @@ export type LinkifyParams = { export function linkify({ filePath, contentPaths, - fileContent, + fileString, siteDir, sourceToPermalink, onBrokenMarkdownLink, }: LinkifyParams): string { - return replaceMarkdownLinks( - fileContent, + const {newContent, brokenMarkdownLinks} = replaceMarkdownLinks({ + siteDir, + fileString, filePath, contentPaths, - { - siteDir, - sourceToPermalink, - onBrokenMarkdownLink, - }, - (blogPost) => blogPost.metadata.permalink, - ); + sourceToPermalink, + }); + + brokenMarkdownLinks.forEach((l) => onBrokenMarkdownLink(l)); + + return newContent; } // Order matters: we look in priority in localized folder diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 1803120b0d20..f7a7cd4209e6 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -50,7 +50,7 @@ import { generateBlogFeed, generateBlogPosts, getContentPathList, - getPostsBySource, + getSourceToPermalink, } from './blogUtils'; export default function pluginContentBlog( @@ -416,7 +416,7 @@ export default function pluginContentBlog( siteDir, contentPaths, truncateMarker, - sourceToPermalink: getPostsBySource(blogPosts), + sourceToPermalink: getSourceToPermalink(blogPosts), onBrokenMarkdownLink: (brokenMarkdownLink) => { if (onBrokenMarkdownLinks === 'ignore') { return; diff --git a/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts b/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts index 0b37de13cef2..ba8fdaa35079 100644 --- a/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts +++ b/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts @@ -12,13 +12,13 @@ import {BlogMarkdownLoaderOptions} from './types'; const markdownLoader: loader.Loader = function (source) { const filePath = this.resourcePath; - const fileContent = source as string; + const fileString = source as string; const callback = this.async(); const markdownLoaderOptions = getOptions(this) as BlogMarkdownLoaderOptions; // Linkify blog posts let finalContent = linkify({ - fileContent, + fileString, filePath, ...markdownLoaderOptions, }); diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index e2eeaf11cb31..2692118f7671 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -149,6 +149,6 @@ export type BlogMarkdownLoaderOptions = { siteDir: string; contentPaths: BlogContentPaths; truncateMarker: RegExp; - sourceToPermalink: Record; + sourceToPermalink: Record; onBrokenMarkdownLink: (brokenMarkdownLink: BlogBrokenMarkdownLink) => void; }; diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts index 1ddb525b2903..3c772dd14dbd 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts @@ -28,12 +28,17 @@ export function linkify( filePath: string, options: DocsMarkdownOption, ): string { - const version = getVersion(filePath, options); - return replaceMarkdownLinks( + const {siteDir, sourceToPermalink, onBrokenMarkdownLink} = options; + + const {newContent, brokenMarkdownLinks} = replaceMarkdownLinks({ + siteDir, fileString, filePath, - version, - options, - (permalink) => permalink, - ); + contentPaths: getVersion(filePath, options), + sourceToPermalink, + }); + + brokenMarkdownLinks.forEach((l) => onBrokenMarkdownLink(l)); + + return newContent; } diff --git a/packages/docusaurus-utils/src/markdownLinks.ts b/packages/docusaurus-utils/src/markdownLinks.ts index 876a5a160650..b8c874a53c2c 100644 --- a/packages/docusaurus-utils/src/markdownLinks.ts +++ b/packages/docusaurus-utils/src/markdownLinks.ts @@ -19,25 +19,30 @@ export type BrokenMarkdownLink = { link: string; }; -export type ReplaceMarkdownLinksParams< - T extends ContentPaths, - S extends unknown -> = { +export type ReplaceMarkdownLinksParams = { siteDir: string; - sourceToPermalink: Record; - onBrokenMarkdownLink: (brokenMarkdownLink: BrokenMarkdownLink) => void; + fileString: string; + filePath: string; + contentPaths: T; + sourceToPermalink: Record; +}; + +export type ReplaceMarkdownLinksReturn = { + newContent: string; + brokenMarkdownLinks: BrokenMarkdownLink[]; }; -export function replaceMarkdownLinks( - fileString: string, - filePath: string, - contentPaths: T, - options: ReplaceMarkdownLinksParams, - getPermalink: (alias: S) => string, -): string { - const {siteDir, sourceToPermalink, onBrokenMarkdownLink} = options; +export function replaceMarkdownLinks({ + siteDir, + fileString, + filePath, + contentPaths, + sourceToPermalink, +}: ReplaceMarkdownLinksParams): ReplaceMarkdownLinksReturn { const {contentPath, contentPathLocalized} = contentPaths; + const brokenMarkdownLinks: BrokenMarkdownLink[] = []; + // Replace internal markdown linking (except in fenced blocks). let fencedBlock = false; const lines = fileString.split('\n').map((line) => { @@ -61,25 +66,28 @@ export function replaceMarkdownLinks( const aliasedSource = (source: string) => aliasedSitePath(source, siteDir); - const permalink = + const permalink: string | undefined = sourceToPermalink[aliasedSource(resolve(filePath, mdLink))] || sourceToPermalink[aliasedSource(`${contentPathLocalized}/${mdLink}`)] || sourceToPermalink[aliasedSource(`${contentPath}/${mdLink}`)]; if (permalink) { - modifiedLine = modifiedLine.replace(mdLink, getPermalink(permalink)); + modifiedLine = modifiedLine.replace(mdLink, permalink); } else { const brokenMarkdownLink: BrokenMarkdownLink = { contentPaths, filePath, link: mdLink, }; - onBrokenMarkdownLink(brokenMarkdownLink); + + brokenMarkdownLinks.push(brokenMarkdownLink); } mdMatch = mdRegex.exec(modifiedLine); } return modifiedLine; }); - return lines.join('\n'); + const newContent = lines.join('\n'); + + return {newContent, brokenMarkdownLinks}; }