From 71ba449a286074ab98ff63df44c1fb39dc27a5ef Mon Sep 17 00:00:00 2001 From: AkiraVoid Date: Thu, 21 Apr 2022 22:51:24 +0800 Subject: [PATCH] fix(content-blog): make footnote reference DOM ID unique on post listing page (#7212) Co-authored-by: Joshua Chen --- .../package.json | 1 + .../src/index.ts | 6 +- .../src/remark/__tests__/__fixtures__/post.md | 9 +++ .../remark/__tests__/__fixtures__/post2.md | 9 +++ .../footnoteIDFixer.test.ts.snap | 66 +++++++++++++++++++ .../remark/__tests__/footnoteIDFixer.test.ts | 39 +++++++++++ .../src/remark/footnoteIDFixer.ts | 29 ++++++++ .../_blog tests/2022-01-21-dup-footnote.md | 13 ++++ .../_blog tests/2022-01-22-dup-footnote.md | 13 ++++ .../_blog tests/2022-04-20-dup-footnote.md | 13 ++++ 10 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post.md create mode 100644 packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post2.md create mode 100644 packages/docusaurus-plugin-content-blog/src/remark/__tests__/__snapshots__/footnoteIDFixer.test.ts.snap create mode 100644 packages/docusaurus-plugin-content-blog/src/remark/__tests__/footnoteIDFixer.test.ts create mode 100644 packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts create mode 100644 website/_dogfooding/_blog tests/2022-01-21-dup-footnote.md create mode 100644 website/_dogfooding/_blog tests/2022-01-22-dup-footnote.md create mode 100644 website/_dogfooding/_blog tests/2022-04-20-dup-footnote.md diff --git a/packages/docusaurus-plugin-content-blog/package.json b/packages/docusaurus-plugin-content-blog/package.json index 8ab159fa48..9ab46401b4 100644 --- a/packages/docusaurus-plugin-content-blog/package.json +++ b/packages/docusaurus-plugin-content-blog/package.json @@ -31,6 +31,7 @@ "reading-time": "^1.5.0", "remark-admonitions": "^1.2.1", "tslib": "^2.3.1", + "unist-util-visit": "^2.0.3", "utility-types": "^3.10.0", "webpack": "^5.72.0" }, diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 1bcfb02826..22b1a20c19 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -7,6 +7,7 @@ import path from 'path'; import admonitions from 'remark-admonitions'; +import footnoteIDFixer from './remark/footnoteIDFixer'; import { normalizeUrl, docuHash, @@ -435,7 +436,10 @@ export default async function pluginContentBlog( options: { remarkPlugins, rehypePlugins, - beforeDefaultRemarkPlugins, + beforeDefaultRemarkPlugins: [ + footnoteIDFixer, + ...beforeDefaultRemarkPlugins, + ], beforeDefaultRehypePlugins, staticDirs: siteConfig.staticDirectories.map((dir) => path.resolve(siteDir, dir), diff --git a/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post.md b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post.md new file mode 100644 index 0000000000..cfb82b4b19 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post.md @@ -0,0 +1,9 @@ +foo[^1] + +bar[^2] + +baz[^3] + +[^1]: foo +[^2]: foo +[^3]: foo diff --git a/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post2.md b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post2.md new file mode 100644 index 0000000000..cfb82b4b19 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post2.md @@ -0,0 +1,9 @@ +foo[^1] + +bar[^2] + +baz[^3] + +[^1]: foo +[^2]: foo +[^3]: foo diff --git a/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__snapshots__/footnoteIDFixer.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__snapshots__/footnoteIDFixer.test.ts.snap new file mode 100644 index 0000000000..cbf3583335 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/__snapshots__/footnoteIDFixer.test.ts.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`footnoteIDFixer remark plugin appends a hash to each footnote def/ref 1`] = ` +"/* @jsxRuntime classic */ +/* @jsx mdx */ + + + +const layoutProps = { + +}; +const MDXLayout = "wrapper" +export default function MDXContent({ + components, + ...props +}) { + return +

{\`foo\`}{\`1\`}

+

{\`bar\`}{\`2\`}

+

{\`baz\`}{\`3\`}

+
+
+
    +
  1. {\`foo\`}{\`↩\`}
  2. +
  3. {\`foo\`}{\`↩\`}
  4. +
  5. {\`foo\`}{\`↩\`}
  6. +
+
+
; +} + +; +MDXContent.isMDXComponent = true;" +`; diff --git a/packages/docusaurus-plugin-content-blog/src/remark/__tests__/footnoteIDFixer.test.ts b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/footnoteIDFixer.test.ts new file mode 100644 index 0000000000..2890766350 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/footnoteIDFixer.test.ts @@ -0,0 +1,39 @@ +/** + * 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 fs from 'fs-extra'; +import path from 'path'; +import {simpleHash} from '@docusaurus/utils'; +import mdx from '@mdx-js/mdx'; +import footnoteIDFixer from '../footnoteIDFixer'; + +const processFixture = async (name: string) => { + const filepath = path.join(__dirname, `__fixtures__/${name}.md`); + const result = await mdx(await fs.readFile(filepath), { + filepath, + remarkPlugins: [footnoteIDFixer], + }); + + return result.toString(); +}; + +describe('footnoteIDFixer remark plugin', () => { + it('appends a hash to each footnote def/ref', async () => { + const hash = simpleHash(path.join(__dirname, `__fixtures__/post.md`), 6); + expect( + (await processFixture('post')).replace(new RegExp(hash, 'g'), '[HASH]'), + ).toMatchSnapshot(); + }); + + it('produces different hashes for different posts but same hash for the same path', async () => { + const file1 = await processFixture('post'); + const file1again = await processFixture('post'); + const file2 = await processFixture('post2'); + expect(file1).toBe(file1again); + expect(file1).not.toBe(file2); + }); +}); diff --git a/packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts b/packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts new file mode 100644 index 0000000000..a3c317ba61 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts @@ -0,0 +1,29 @@ +/** + * 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 visit from 'unist-util-visit'; +import {simpleHash} from '@docusaurus/utils'; +import type {Transformer} from 'unified'; +import type {FootnoteReference, FootnoteDefinition} from 'mdast'; + +/** + * In the blog list view, each post will be compiled separately. However, they + * may use the same footnote IDs. This leads to duplicated DOM IDs and inability + * to navigate to footnote references. This plugin fixes it by appending a + * unique hash to each reference/definition. + */ +export default function plugin(): Transformer { + return (root, vfile) => { + const suffix = `-${simpleHash(vfile.path!, 6)}`; + visit(root, 'footnoteReference', (node: FootnoteReference) => { + node.identifier += suffix; + }); + visit(root, 'footnoteDefinition', (node: FootnoteDefinition) => { + node.identifier += suffix; + }); + }; +} diff --git a/website/_dogfooding/_blog tests/2022-01-21-dup-footnote.md b/website/_dogfooding/_blog tests/2022-01-21-dup-footnote.md new file mode 100644 index 0000000000..efbec159e7 --- /dev/null +++ b/website/_dogfooding/_blog tests/2022-01-21-dup-footnote.md @@ -0,0 +1,13 @@ +--- +title: Third post with footnote to test posts with same footnote reference. +--- + +foo[^1] + +bar[^2] + +baz[^3] + +[^1]: foo +[^2]: bar +[^3]: baz diff --git a/website/_dogfooding/_blog tests/2022-01-22-dup-footnote.md b/website/_dogfooding/_blog tests/2022-01-22-dup-footnote.md new file mode 100644 index 0000000000..5079f97dfc --- /dev/null +++ b/website/_dogfooding/_blog tests/2022-01-22-dup-footnote.md @@ -0,0 +1,13 @@ +--- +title: Second post with footnote to test posts with same footnote reference. +--- + +foo[^1] + +bar[^2] + +baz[^3] + +[^1]: foo +[^2]: bar +[^3]: baz diff --git a/website/_dogfooding/_blog tests/2022-04-20-dup-footnote.md b/website/_dogfooding/_blog tests/2022-04-20-dup-footnote.md new file mode 100644 index 0000000000..b512db7244 --- /dev/null +++ b/website/_dogfooding/_blog tests/2022-04-20-dup-footnote.md @@ -0,0 +1,13 @@ +--- +title: First post with footnote to test posts with same footnote reference. +--- + +foo[^1] + +bar[^2] + +baz[^3] + +[^1]: foo +[^2]: bar +[^3]: baz