From bf913aea2a1a0c217716bbf44acda8528dd5bc7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 21 Apr 2023 19:48:57 +0200 Subject: [PATCH] feat: upgrade to MDX v2 (#8288) Co-authored-by: Armano --- .stylelintignore | 2 + jest.config.mjs | 14 + jest/deps.d.ts | 7 - package.json | 4 +- .../templates/classic-typescript/package.json | 2 +- .../templates/classic/package.json | 2 +- .../templates/facebook/package.json | 2 +- packages/docusaurus-mdx-loader/package.json | 17 +- .../src/__tests__/frontMatter.test.ts | 93 ++ packages/docusaurus-mdx-loader/src/deps.d.ts | 31 - .../docusaurus-mdx-loader/src/frontMatter.ts | 31 + packages/docusaurus-mdx-loader/src/index.ts | 8 +- packages/docusaurus-mdx-loader/src/loader.ts | 168 ++- .../docusaurus-mdx-loader/src/preprocessor.ts | 47 + .../__snapshots__/index.test.ts.snap | 22 +- .../admonitions/__tests__/index.test.ts | 49 +- .../src/remark/admonitions/index.ts | 254 +--- .../remark/details/__tests__/index.test.ts | 76 + .../src/remark/details/index.ts | 25 + .../src/remark/head/__tests__/index.test.ts | 76 + .../src/remark/head/index.ts | 25 + .../remark/headings/__tests__/index.test.ts | 40 +- .../src/remark/headings/index.ts | 8 +- .../src/remark/mdx1Compat/codeCompatPlugin.ts | 36 + .../__snapshots__/index.test.ts.snap | 49 - .../remark/mermaid/__tests__/index.test.ts | 47 +- .../src/remark/mermaid/index.ts | 2 + .../__snapshots__/index.test.ts.snap | 18 +- .../src/remark/toc/__tests__/index.test.ts | 9 +- .../src/remark/toc/index.ts | 106 +- .../__tests__/__fixtures__/img.md | 8 +- .../__snapshots__/index.test.ts.snap | 26 +- .../transformImage/__tests__/index.test.ts | 9 +- .../src/remark/transformImage/index.ts | 73 +- .../__tests__/__fixtures__/asset.md | 2 + .../__snapshots__/index.test.ts.snap | 32 +- .../transformLinks/__tests__/index.test.ts | 6 +- .../src/remark/transformLinks/index.ts | 59 +- .../__fixtures__/has-mdx-code-blocks.mdx | 95 -- .../__snapshots__/index.test.ts.snap | 819 ---------- .../__tests__/index.test.ts | 36 - .../src/remark/unwrapMdxCodeBlocks/index.ts | 33 - .../src/remark/utils/index.ts | 86 +- packages/docusaurus-migrate/package.json | 2 +- packages/docusaurus-migrate/src/index.ts | 17 +- packages/docusaurus-migrate/src/sanitizeMD.ts | 9 +- .../src/options.ts | 2 +- .../footnoteIDFixer.test.ts.snap | 156 +- .../remark/__tests__/footnoteIDFixer.test.ts | 18 +- .../src/remark/footnoteIDFixer.ts | 1 + .../package.json | 6 +- .../src/__tests__/__fixtures__/multiple.md | 21 + .../__snapshots__/index.test.ts.snap | 548 +++---- .../src/__tests__/index.test.ts | 42 +- .../src/index.ts | 206 ++- .../docusaurus-theme-classic/package.json | 2 +- .../src/getSwizzleConfig.ts | 8 - .../src/theme-classic.d.ts | 14 +- .../src/theme/MDXComponents/Code.tsx | 41 +- .../src/theme/MDXComponents/Details.tsx | 3 +- .../src/theme/MDXComponents/Head.tsx | 31 - .../src/theme/MDXComponents/Pre.tsx | 18 +- .../src/theme/MDXComponents/index.tsx | 6 +- .../src/theme/MDXContent/index.tsx | 1 + .../src/theme/Tabs/index.tsx | 6 +- .../src/components/Details/styles.module.css | 6 +- .../docusaurus-theme-common/src/internal.ts | 2 +- .../src/utils/admonitionUtils.tsx | 15 +- .../src/utils/tabsUtils.tsx | 34 +- .../docusaurus-theme-mermaid/package.json | 1 - packages/docusaurus-types/src/config.d.ts | 20 +- .../validationSchemas.test.ts.snap | 24 +- .../src/__tests__/validationSchemas.test.ts | 8 +- .../src/validationSchemas.ts | 15 +- .../src/validationUtils.ts | 5 +- .../src/__tests__/markdownUtils.test.ts | 553 +++++++ packages/docusaurus-utils/src/index.ts | 3 + .../docusaurus-utils/src/markdownUtils.ts | 69 + .../__snapshots__/config.test.ts.snap | 30 + .../__snapshots__/index.test.ts.snap | 6 + .../server/__tests__/configValidation.test.ts | 59 +- .../docusaurus/src/server/configValidation.ts | 21 + packages/docusaurus/src/webpack/utils.ts | 4 +- project-words.txt | 7 + .../2021-08-21-blog-post-toc-tests.mdx | 2 +- .../2021-10-07-blog-post-mdx-feed-tests.mdx | 2 +- ...10-08-blog-post-mdx-require-feed-tests.mdx | 2 +- .../demo/2020-08-03-second-blog-intro.mdx | 2 +- .../_docs tests/tests/admonitions.mdx | 26 +- .../_pages tests/code-block-tests.mdx | 10 +- website/_dogfooding/_pages tests/index.mdx | 7 +- .../_pages tests/markdown-tests-md.md | 44 + ...wnPageTests.mdx => markdown-tests-mdx.mdx} | 86 +- .../_pages tests/markdown-tests.mdx | 33 - .../blog/2018-09-11-Towards-Docusaurus-2.mdx | 11 +- .../index.mdx | 2 +- website/blog/releases/2.2/index.mdx | 2 +- website/docs/api/docusaurus.config.js.mdx | 2 +- .../docs/api/plugins/plugin-content-blog.mdx | 4 +- website/docs/blog.mdx | 25 +- .../markdown-features-admonitions.mdx | 35 +- .../markdown-features-math-equations.mdx | 144 +- .../markdown-features-react.mdx | 22 +- .../markdown-features-tabs.mdx | 6 +- .../markdown-features-toc.mdx | 8 +- website/docs/i18n/i18n-crowdin.mdx | 3 +- website/docs/introduction.mdx | 15 +- website/docs/search.mdx | 2 +- website/docusaurus.config.js | 19 +- website/package.json | 2 +- website/src/plugins/changelog/index.js | 2 + website/src/remark/configTabs.mjs | 69 +- website/src/theme/MDXComponents.tsx | 2 + .../api/docusaurus.config.js.mdx | 2 +- .../api/plugins/plugin-content-blog.mdx | 2 +- website/versioned_docs/version-2.0.1/blog.mdx | 2 +- .../markdown-features-admonitions.mdx | 12 +- .../markdown-features-react.mdx | 18 +- .../markdown-features-tabs.mdx | 6 +- .../markdown-features-toc.mdx | 8 +- .../version-2.0.1/i18n/i18n-crowdin.mdx | 2 +- .../version-2.0.1/introduction.mdx | 13 - .../versioned_docs/version-2.0.1/search.mdx | 2 +- .../api/docusaurus.config.js.mdx | 2 +- .../api/plugins/plugin-content-blog.mdx | 2 +- website/versioned_docs/version-2.1.0/blog.mdx | 2 +- .../markdown-features-admonitions.mdx | 12 +- .../markdown-features-react.mdx | 18 +- .../markdown-features-tabs.mdx | 6 +- .../markdown-features-toc.mdx | 8 +- .../version-2.1.0/i18n/i18n-crowdin.mdx | 2 +- .../version-2.1.0/introduction.mdx | 13 - .../versioned_docs/version-2.1.0/search.mdx | 2 +- .../api/docusaurus.config.js.mdx | 2 +- .../api/plugins/plugin-content-blog.mdx | 2 +- website/versioned_docs/version-2.2.0/blog.mdx | 2 +- .../markdown-features-admonitions.mdx | 12 +- .../markdown-features-react.mdx | 18 +- .../markdown-features-tabs.mdx | 6 +- .../markdown-features-toc.mdx | 8 +- .../version-2.2.0/i18n/i18n-crowdin.mdx | 2 +- .../version-2.2.0/introduction.mdx | 13 - .../versioned_docs/version-2.2.0/search.mdx | 2 +- .../api/docusaurus.config.js.mdx | 2 +- .../api/plugins/plugin-content-blog.mdx | 2 +- .../markdown-features-admonitions.mdx | 18 +- .../markdown-features-react.mdx | 22 +- .../markdown-features-tabs.mdx | 6 +- .../markdown-features-toc.mdx | 8 +- .../version-2.3.1/i18n/i18n-crowdin.mdx | 2 +- .../version-2.3.1/introduction.mdx | 15 +- .../versioned_docs/version-2.3.1/search.mdx | 2 +- .../api/plugins/plugin-content-blog.mdx | 2 +- .../markdown-features-admonitions.mdx | 18 +- .../markdown-features-react.mdx | 22 +- .../markdown-features-tabs.mdx | 6 +- .../markdown-features-toc.mdx | 8 +- .../version-2.4.0/i18n/i18n-crowdin.mdx | 2 +- .../version-2.4.0/introduction.mdx | 15 +- .../versioned_docs/version-2.4.0/search.mdx | 2 +- yarn.lock | 1313 +++++++++++++---- 161 files changed, 4028 insertions(+), 2821 deletions(-) create mode 100644 packages/docusaurus-mdx-loader/src/__tests__/frontMatter.test.ts delete mode 100644 packages/docusaurus-mdx-loader/src/deps.d.ts create mode 100644 packages/docusaurus-mdx-loader/src/frontMatter.ts create mode 100644 packages/docusaurus-mdx-loader/src/preprocessor.ts create mode 100644 packages/docusaurus-mdx-loader/src/remark/details/__tests__/index.test.ts create mode 100644 packages/docusaurus-mdx-loader/src/remark/details/index.ts create mode 100644 packages/docusaurus-mdx-loader/src/remark/head/__tests__/index.test.ts create mode 100644 packages/docusaurus-mdx-loader/src/remark/head/index.ts create mode 100644 packages/docusaurus-mdx-loader/src/remark/mdx1Compat/codeCompatPlugin.ts delete mode 100644 packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/__snapshots__/index.test.ts.snap delete mode 100644 packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__fixtures__/has-mdx-code-blocks.mdx delete mode 100644 packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap delete mode 100644 packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts delete mode 100644 packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts create mode 100644 packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/multiple.md delete mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx create mode 100644 website/_dogfooding/_pages tests/markdown-tests-md.md rename website/_dogfooding/_pages tests/{markdownPageTests.mdx => markdown-tests-mdx.mdx} (71%) delete mode 100644 website/_dogfooding/_pages tests/markdown-tests.mdx diff --git a/.stylelintignore b/.stylelintignore index 15db7860ba..9b97556a56 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -13,3 +13,5 @@ packages/docusaurus-*/lib/* packages/create-docusaurus/lib/* packages/create-docusaurus/templates/ website/static/katex/katex.min.css + +jest/vendor diff --git a/jest.config.mjs b/jest.config.mjs index dd2e9f3146..2d2850d07d 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -80,6 +80,20 @@ export default { '@docusaurus/plugin-content-docs/src/client/index.ts', '@testing-utils/(.*)': '/jest/utils/$1.ts', + + // MDX packages are ESM-only and it is a pain to use in Jest + // So we use them in Jest tests as CJS versions + // see https://mdxjs.com/docs/troubleshooting-mdx/#problems-integrating-mdx + '^unified$': '/jest/vendor/unified@10.1.2.js', + '^@mdx-js/mdx$': '/jest/vendor/@mdx-js__mdx@2.1.5.js', + '^remark$': '/jest/vendor/remark@14.0.2.js', + '^remark-mdx$': '/jest/vendor/remark-mdx@2.1.5.js', + '^remark-directive$': '/jest/vendor/remark-directive@2.0.1.js', + '^remark-gfm$': '/jest/vendor/remark-gfm@3.0.1.js', + '^estree-util-value-to-estree$': + '/jest/vendor/estree-util-value-to-estree@2.1.0.js', + '^mdast-util-to-string$': + '/jest/vendor/mdast-util-to-string@3.1.0.js', }, snapshotSerializers: [ '/jest/snapshotPathNormalizer.ts', diff --git a/jest/deps.d.ts b/jest/deps.d.ts index 965ca69039..4f7717ddd5 100644 --- a/jest/deps.d.ts +++ b/jest/deps.d.ts @@ -13,13 +13,6 @@ declare module 'to-vfile' { export function read(path: string, encoding?: string): Promise; } -declare module 'remark-mdx' { - import type {Plugin} from 'unified'; - - const mdx: Plugin; - export = mdx; -} - declare module 'remark-rehype'; declare module 'rehype-stringify'; diff --git a/package.json b/package.json index f60da53ecc..23390eb3be 100644 --- a/package.json +++ b/package.json @@ -55,12 +55,12 @@ "test": "jest", "test:build:website": "./admin/scripts/test-release.sh", "watch": "yarn lerna run --parallel watch", - "clear": "(yarn workspace website clear || echo 'Failure while running docusaurus clear') && yarn lerna exec --ignore docusaurus yarn rimraf lib", + "clear": "(yarn workspace website clear || echo 'Failure while running docusaurus clear') && yarn rimraf test-website && yarn rimraf test-website-in-workspace && yarn lerna exec --ignore docusaurus yarn rimraf lib", "test:baseUrl": "yarn build:website:baseUrl && yarn serve:website:baseUrl", "lock:update": "npx --yes yarn-deduplicate" }, "dependencies": { - "unified": "^9.2.2" + "unified": "^10.1.2" }, "devDependencies": { "@crowdin/cli": "^3.10.0", diff --git a/packages/create-docusaurus/templates/classic-typescript/package.json b/packages/create-docusaurus/templates/classic-typescript/package.json index ea90dc7186..c03f04f0d6 100644 --- a/packages/create-docusaurus/templates/classic-typescript/package.json +++ b/packages/create-docusaurus/templates/classic-typescript/package.json @@ -17,7 +17,7 @@ "dependencies": { "@docusaurus/core": "^3.0.0-alpha.0", "@docusaurus/preset-classic": "^3.0.0-alpha.0", - "@mdx-js/react": "^1.6.22", + "@mdx-js/react": "^2.1.5", "clsx": "^1.2.1", "prism-react-renderer": "^1.3.5", "react": "^17.0.2", diff --git a/packages/create-docusaurus/templates/classic/package.json b/packages/create-docusaurus/templates/classic/package.json index 8eca2aa446..d0a06d1bd5 100644 --- a/packages/create-docusaurus/templates/classic/package.json +++ b/packages/create-docusaurus/templates/classic/package.json @@ -16,7 +16,7 @@ "dependencies": { "@docusaurus/core": "^3.0.0-alpha.0", "@docusaurus/preset-classic": "^3.0.0-alpha.0", - "@mdx-js/react": "^1.6.22", + "@mdx-js/react": "^2.1.5", "clsx": "^1.2.1", "prism-react-renderer": "^1.3.5", "react": "^17.0.2", diff --git a/packages/create-docusaurus/templates/facebook/package.json b/packages/create-docusaurus/templates/facebook/package.json index 6da8c5f0da..70b0aead17 100644 --- a/packages/create-docusaurus/templates/facebook/package.json +++ b/packages/create-docusaurus/templates/facebook/package.json @@ -20,7 +20,7 @@ "dependencies": { "@docusaurus/core": "^3.0.0-alpha.0", "@docusaurus/preset-classic": "^3.0.0-alpha.0", - "@mdx-js/react": "^1.6.22", + "@mdx-js/react": "^2.1.5", "clsx": "^1.2.1", "react": "^17.0.2", "react-dom": "^17.0.2" diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json index 833547a475..70e8f18ea8 100644 --- a/packages/docusaurus-mdx-loader/package.json +++ b/packages/docusaurus-mdx-loader/package.json @@ -22,16 +22,23 @@ "@babel/traverse": "^7.21.2", "@docusaurus/logger": "^3.0.0-alpha.0", "@docusaurus/utils": "^3.0.0-alpha.0", - "@mdx-js/mdx": "^1.6.22", + "@docusaurus/utils-validation": "^3.0.0-alpha.0", + "@mdx-js/mdx": "^2.1.5", "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^2.1.0", "file-loader": "^6.2.0", "fs-extra": "^11.1.0", + "hastscript": "^7.1.0", "image-size": "^1.0.2", - "mdast-util-to-string": "^2.0.0", + "mdast-util-to-string": "^3.0.0", + "mdast-util-mdx": "^2.0.0", + "remark-comment": "^1.0.0", + "remark-gfm": "^3.0.1", + "remark-directive": "^2.0.1", "remark-emoji": "^2.2.0", "stringify-object": "^3.3.0", "tslib": "^2.5.0", - "unified": "^9.2.2", + "unified": "^10.1.2", "unist-util-visit": "^2.0.3", "url-loader": "^4.1.1", "webpack": "^5.76.0" @@ -43,8 +50,8 @@ "@types/stringify-object": "^3.3.1", "@types/unist": "^2.0.6", "rehype-stringify": "^8.0.0", - "remark": "^12.0.1", - "remark-mdx": "^1.6.21", + "remark": "^14.0.2", + "remark-mdx": "^2.1.5", "remark-rehype": "^8.1.0", "to-vfile": "^6.1.0", "unist-builder": "^2.0.3", diff --git a/packages/docusaurus-mdx-loader/src/__tests__/frontMatter.test.ts b/packages/docusaurus-mdx-loader/src/__tests__/frontMatter.test.ts new file mode 100644 index 0000000000..7a7e7a4480 --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/__tests__/frontMatter.test.ts @@ -0,0 +1,93 @@ +/** + * 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 escapeStringRegexp from 'escape-string-regexp'; +import { + validateMDXFrontMatter, + DefaultMDXFrontMatter, + type MDXFrontMatter, +} from '../frontMatter'; + +function testField(params: { + prefix: string; + validFrontMatters: MDXFrontMatter[]; + convertibleFrontMatter?: [ + ConvertibleFrontMatter: {[key: string]: unknown}, + ConvertedFrontMatter: MDXFrontMatter, + ][]; + invalidFrontMatters?: [ + InvalidFrontMatter: {[key: string]: unknown}, + ErrorMessage: string, + ][]; +}) { + // eslint-disable-next-line jest/require-top-level-describe + test(`[${params.prefix}] accept valid values`, () => { + params.validFrontMatters.forEach((frontMatter) => { + expect(validateMDXFrontMatter(frontMatter)).toEqual(frontMatter); + }); + }); + + // eslint-disable-next-line jest/require-top-level-describe + test(`[${params.prefix}] convert valid values`, () => { + params.convertibleFrontMatter?.forEach( + ([convertibleFrontMatter, convertedFrontMatter]) => { + expect(validateMDXFrontMatter(convertibleFrontMatter)).toEqual( + convertedFrontMatter, + ); + }, + ); + }); + + // eslint-disable-next-line jest/require-top-level-describe + test(`[${params.prefix}] throw error for values`, () => { + params.invalidFrontMatters?.forEach(([frontMatter, message]) => { + try { + validateMDXFrontMatter(frontMatter); + throw new Error( + `MDX front matter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify( + frontMatter, + null, + 2, + )}`, + ); + } catch (err) { + // eslint-disable-next-line jest/no-conditional-expect + expect((err as Error).message).toMatch( + new RegExp(escapeStringRegexp(message)), + ); + } + }); + }); +} + +describe('MDX front matter schema', () => { + it('accepts empty object', () => { + const frontMatter: Partial = {}; + expect(validateMDXFrontMatter(frontMatter)).toEqual(DefaultMDXFrontMatter); + }); + + it('accepts undefined object', () => { + expect(validateMDXFrontMatter(undefined)).toEqual(DefaultMDXFrontMatter); + }); + + it('rejects unknown field', () => { + const frontMatter = {abc: '1'}; + expect(() => + validateMDXFrontMatter(frontMatter), + ).toThrowErrorMatchingInlineSnapshot(`""abc" is not allowed"`); + }); +}); + +describe('validateDocFrontMatter format', () => { + testField({ + prefix: 'format', + validFrontMatters: [{format: 'md'}, {format: 'mdx'}], + invalidFrontMatters: [ + [{format: 'xdm'}, '"format" must be one of [md, mdx, detect]'], + ], + }); +}); diff --git a/packages/docusaurus-mdx-loader/src/deps.d.ts b/packages/docusaurus-mdx-loader/src/deps.d.ts deleted file mode 100644 index 7f8fb25a2f..0000000000 --- a/packages/docusaurus-mdx-loader/src/deps.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * 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. - */ - -// TODO Types provided by MDX 2.0 https://github.com/mdx-js/mdx/blob/main/packages/mdx/types/index.d.ts -declare module '@mdx-js/mdx' { - import type {Processor, Plugin} from 'unified'; - - type MDXPlugin = - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [Plugin, any] | Plugin; - - type Options = { - filepath?: string; - skipExport?: boolean; - wrapExport?: string; - remarkPlugins?: MDXPlugin[]; - rehypePlugins?: MDXPlugin[]; - }; - - export function sync(content: string, options?: Options): string; - export function createMdxAstCompiler(options?: Options): Processor; - export function createCompiler(options?: Options): Processor; - export default function mdx( - content: string, - options?: Options, - ): Promise; -} diff --git a/packages/docusaurus-mdx-loader/src/frontMatter.ts b/packages/docusaurus-mdx-loader/src/frontMatter.ts new file mode 100644 index 0000000000..3c47648f6d --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/frontMatter.ts @@ -0,0 +1,31 @@ +/** + * 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 { + JoiFrontMatter as Joi, + validateFrontMatter, +} from '@docusaurus/utils-validation'; + +export type MDXFrontMatter = { + format: 'md' | 'mdx' | 'detect'; +}; + +export const DefaultMDXFrontMatter: MDXFrontMatter = { + format: 'detect', +}; + +const MDXFrontMatterSchema = Joi.object({ + format: Joi.string() + .equal('md', 'mdx', 'detect') + .default(DefaultMDXFrontMatter.format), +}).default(DefaultMDXFrontMatter); + +export function validateMDXFrontMatter(frontMatter: unknown): MDXFrontMatter { + return validateFrontMatter(frontMatter, MDXFrontMatterSchema, { + allowUnknown: false, + }); +} diff --git a/packages/docusaurus-mdx-loader/src/index.ts b/packages/docusaurus-mdx-loader/src/index.ts index ad7887dcc7..f242ebdcf3 100644 --- a/packages/docusaurus-mdx-loader/src/index.ts +++ b/packages/docusaurus-mdx-loader/src/index.ts @@ -7,13 +7,11 @@ import {mdxLoader} from './loader'; +import type {TOCItem as TOCItemImported} from './remark/toc'; + export default mdxLoader; -export type TOCItem = { - readonly value: string; - readonly id: string; - readonly level: number; -}; +export type TOCItem = TOCItemImported; export type LoadedMDXContent = { /** As verbatim declared in the MDX document. */ diff --git a/packages/docusaurus-mdx-loader/src/loader.ts b/packages/docusaurus-mdx-loader/src/loader.ts index fee2920a2e..a93bb955bd 100644 --- a/packages/docusaurus-mdx-loader/src/loader.ts +++ b/packages/docusaurus-mdx-loader/src/loader.ts @@ -6,6 +6,7 @@ */ import fs from 'fs-extra'; +import path from 'path'; import logger from '@docusaurus/logger'; import { parseFrontMatter, @@ -13,46 +14,73 @@ import { escapePath, getFileLoaderUtils, } from '@docusaurus/utils'; -import {createCompiler} from '@mdx-js/mdx'; import emoji from 'remark-emoji'; import stringifyObject from 'stringify-object'; - +import preprocessor from './preprocessor'; import headings from './remark/headings'; import toc from './remark/toc'; -import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks'; import transformImage from './remark/transformImage'; import transformLinks from './remark/transformLinks'; +import details from './remark/details'; +import head from './remark/head'; import mermaid from './remark/mermaid'; - import transformAdmonitions from './remark/admonitions'; +import codeCompatPlugin from './remark/mdx1Compat/codeCompatPlugin'; +import {validateMDXFrontMatter} from './frontMatter'; + import type {MarkdownConfig} from '@docusaurus/types'; import type {LoaderContext} from 'webpack'; -import type {Processor, Plugin} from 'unified'; + +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {Processor} from 'unified'; import type {AdmonitionOptions} from './remark/admonitions'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {ProcessorOptions} from '@mdx-js/mdx'; + +// TODO as of April 2023, no way to import/re-export this ESM type easily :/ +// This might change soon, likely after TS 5.2 +// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391 +type Pluggable = any; // TODO fix this asap + +// Copied from https://mdxjs.com/packages/mdx/#optionsmdextensions +// Although we are likely to only use .md / .mdx anyway... +const mdFormatExtensions = [ + '.md', + '.markdown', + '.mdown', + '.mkdn', + '.mkd', + '.mdwn', + '.mkdown', + '.ron', +]; + +function isMDFormat(filepath: string) { + return mdFormatExtensions.includes(path.extname(filepath)); +} + const { loaders: {inlineMarkdownImageFileLoader}, } = getFileLoaderUtils(); -const pragma = ` -/* @jsxRuntime classic */ -/* @jsx mdx */ -/* @jsxFrag React.Fragment */ -`; - const DEFAULT_OPTIONS: MDXOptions = { admonitions: true, rehypePlugins: [], - remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc], + remarkPlugins: [emoji, headings, toc], beforeDefaultRemarkPlugins: [], beforeDefaultRehypePlugins: [], }; -const compilerCache = new Map(); +type CompilerCacheEntry = { + mdCompiler: Processor; + mdxCompiler: Processor; + options: Options; +}; -export type MDXPlugin = - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [Plugin, any] | Plugin; +const compilerCache = new Map(); + +export type MDXPlugin = Pluggable; export type MDXOptions = { admonitions: boolean | Partial; @@ -149,9 +177,21 @@ function getAdmonitionsPlugins( : [transformAdmonitions, admonitionsOption]; return [plugin]; } + return []; } +// TODO temporary, remove this after v3.1? +// Some plugin authors use our mdx-loader, despite it not being public API +// see https://github.com/facebook/docusaurus/issues/8298 +function ensureMarkdownConfig(reqOptions: Options) { + if (!reqOptions.markdownConfig) { + throw new Error( + 'Docusaurus v3+ requires MDX loader options.markdownConfig - plugin authors using the MDX loader should make sure to provide that option', + ); + } +} + export async function mdxLoader( this: LoaderContext, fileString: string, @@ -159,21 +199,47 @@ export async function mdxLoader( const callback = this.async(); const filePath = this.resourcePath; const reqOptions = this.getOptions(); + ensureMarkdownConfig(reqOptions); + + const {createProcessor} = await import('@mdx-js/mdx'); + const {default: gfm} = await import('remark-gfm'); + const {default: comment} = await import('remark-comment'); + const {default: directives} = await import('remark-directive'); const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString); + const mdxFrontMatter = validateMDXFrontMatter(frontMatter.mdx); - const {content, contentTitle} = parseMarkdownContentTitle(contentWithTitle, { - removeContentTitle: reqOptions.removeContentTitle, + const {content: contentUnprocessed, contentTitle} = parseMarkdownContentTitle( + contentWithTitle, + { + removeContentTitle: reqOptions.removeContentTitle, + }, + ); + + const content = preprocessor({ + fileContent: contentUnprocessed, + filePath, + admonitions: reqOptions.admonitions, + markdownConfig: reqOptions.markdownConfig, }); const hasFrontMatter = Object.keys(frontMatter).length > 0; if (!compilerCache.has(this.query)) { + /* + /!\ DO NOT PUT ANY ASYNC / AWAIT / DYNAMIC IMPORTS HERE + This creates cache creation race conditions + TODO extract this in a synchronous method + */ + const remarkPlugins: MDXPlugin[] = [ ...(reqOptions.beforeDefaultRemarkPlugins ?? []), + directives, ...getAdmonitionsPlugins(reqOptions.admonitions ?? false), ...DEFAULT_OPTIONS.remarkPlugins, - ...(reqOptions.markdownConfig?.mermaid ? [mermaid] : []), + details, + head, + ...(reqOptions.markdownConfig.mermaid ? [mermaid] : []), [ transformImage, { @@ -188,8 +254,14 @@ export async function mdxLoader( siteDir: reqOptions.siteDir, }, ], + gfm, + reqOptions.markdownConfig.mdx1Compat.comments ? comment : null, ...(reqOptions.remarkPlugins ?? []), - ]; + ].filter((plugin): plugin is MDXPlugin => Boolean(plugin)); + + // codeCompatPlugin needs to be applied last after user-provided plugins + // (after npm2yarn for example) + remarkPlugins.push(codeCompatPlugin); const rehypePlugins: MDXPlugin[] = [ ...(reqOptions.beforeDefaultRehypePlugins ?? []), @@ -197,26 +269,60 @@ export async function mdxLoader( ...(reqOptions.rehypePlugins ?? []), ]; - const options: Options = { + const options: ProcessorOptions & Options = { ...reqOptions, remarkPlugins, rehypePlugins, + providerImportSource: '@mdx-js/react', }; - compilerCache.set(this.query, [createCompiler(options), options]); + + const compilerCacheEntry: CompilerCacheEntry = { + mdCompiler: createProcessor({ + ...options, + format: 'md', + }), + mdxCompiler: createProcessor({ + ...options, + format: 'mdx', + }), + options, + }; + + compilerCache.set(this.query, compilerCacheEntry); } - const [compiler, options] = compilerCache.get(this.query)!; + const {mdCompiler, mdxCompiler, options} = compilerCache.get(this.query)!; + + function getCompiler() { + const format = + mdxFrontMatter.format === 'detect' + ? isMDFormat(filePath) + ? 'md' + : 'mdx' + : mdxFrontMatter.format; + + return format === 'md' ? mdCompiler : mdxCompiler; + } let result: string; try { - result = await compiler + result = await getCompiler() .process({ - contents: content, - path: this.resourcePath, + value: content, + path: filePath, }) .then((res) => res.toString()); - } catch (err) { - return callback(err as Error); + } catch (errorUnknown) { + const error = errorUnknown as Error; + return callback( + new Error( + `MDX compilation failed for file ${logger.path(filePath)}\nCause: ${ + error.message + }\nDetails:\n${JSON.stringify(error, null, 2)}`, + // TODO error cause doesn't seem to be used by Webpack stats.errors :s + {cause: error}, + ), + ); } // MDX partials are MDX files starting with _ or in a folder starting with _ @@ -265,6 +371,8 @@ ${JSON.stringify(frontMatter, null, 2)}`; ? reqOptions.createAssets({frontMatter, metadata}) : undefined; + // TODO use remark plugins to insert extra exports instead of string concat? + // cf how the toc is exported const exportsCode = ` export const frontMatter = ${stringifyObject(frontMatter)}; export const contentTitle = ${stringifyObject(contentTitle)}; @@ -273,10 +381,6 @@ ${assets ? `export const assets = ${createAssetsExportCode(assets)};` : ''} `; const code = ` -${pragma} -import React from 'react'; -import { mdx } from '@mdx-js/react'; - ${exportsCode} ${result} `; diff --git a/packages/docusaurus-mdx-loader/src/preprocessor.ts b/packages/docusaurus-mdx-loader/src/preprocessor.ts new file mode 100644 index 0000000000..0581e6bcd9 --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/preprocessor.ts @@ -0,0 +1,47 @@ +/** + * 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 { + escapeMarkdownHeadingIds, + unwrapMdxCodeBlocks, + admonitionTitleToDirectiveLabel, +} from '@docusaurus/utils'; +import {normalizeAdmonitionOptions} from './remark/admonitions'; +import type {Options} from './loader'; + +/** + * Preprocess the string before passing it to MDX + * This is not particularly recommended but makes it easier to upgrade to MDX 2 + */ +export default function preprocessContent({ + fileContent: initialFileContent, + filePath, + markdownConfig, + admonitions, +}: { + fileContent: string; + filePath: string; + markdownConfig: Options['markdownConfig']; + admonitions: Options['admonitions'] | undefined; +}): string { + let fileContent = initialFileContent; + if (markdownConfig.preprocessor) { + fileContent = markdownConfig.preprocessor({ + fileContent, + filePath, + }); + } + fileContent = unwrapMdxCodeBlocks(fileContent); + if (markdownConfig.mdx1Compat.headingIds) { + fileContent = escapeMarkdownHeadingIds(fileContent); + } + if (markdownConfig.mdx1Compat.admonitions && admonitions) { + const {keywords} = normalizeAdmonitionOptions(admonitions); + fileContent = admonitionTitleToDirectiveLabel(fileContent, keywords); + } + return fileContent; +} diff --git a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap index b5597e9fb0..c19b192bab 100644 --- a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap @@ -22,25 +22,9 @@ exports[`admonitions remark plugin base 1`] = `

++++

" `; -exports[`admonitions remark plugin custom tag 1`] = ` -"

The blog feature enables you to deploy in no time a full-featured blog.

-

:::info Sample Title

-

Check the Blog Plugin API Reference documentation for an exhaustive list of options.

-

:::

-

Initial setup {#initial-setup}

-

To set up your site's blog, start by creating a blog directory.

-

:::tip

-

Use the Fast Track to understand Docusaurus in 5 minutes ⏱!

-

Use docusaurus.new to test Docusaurus immediately in your browser!

-

:::

-

Admonition with different syntax

" -`; - exports[`admonitions remark plugin default behavior for custom keyword 1`] = ` "

The blog feature enables you to deploy in no time a full-featured blog.

-

:::info Sample Title

-

Check the Blog Plugin API Reference documentation for an exhaustive list of options.

-

:::

+

Sample Title

Check the Blog Plugin API Reference documentation for an exhaustive list of options.

Initial setup {#initial-setup}

To set up your site's blog, start by creating a blog directory.

Use the Fast Track to understand Docusaurus in 5 minutes ⏱!

Use docusaurus.new to test Docusaurus immediately in your browser!

@@ -61,9 +45,7 @@ exports[`admonitions remark plugin nesting 1`] = ` exports[`admonitions remark plugin replace custom keyword 1`] = ` "

The blog feature enables you to deploy in no time a full-featured blog.

-

:::info Sample Title

-

Check the Blog Plugin API Reference documentation for an exhaustive list of options.

-

:::

+

Sample Title

Check the Blog Plugin API Reference documentation for an exhaustive list of options.

Initial setup {#initial-setup}

To set up your site's blog, start by creating a blog directory.

Use the Fast Track to understand Docusaurus in 5 minutes ⏱!

Use docusaurus.new to test Docusaurus immediately in your browser!

diff --git a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts index 7e469ceaaa..7784850e44 100644 --- a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts @@ -6,40 +6,68 @@ */ import path from 'path'; -import remark from 'remark'; import remark2rehype from 'remark-rehype'; import stringify from 'rehype-stringify'; - import vfile from 'to-vfile'; -import plugin from '../index'; +import preprocessor from '../../../preprocessor'; +import plugin, {DefaultAdmonitionOptions} from '../index'; import type {AdmonitionOptions} from '../index'; const processFixture = async ( name: string, options?: Partial, ) => { + const {remark} = await import('remark'); + const {default: directives} = await import('remark-directive'); + const filePath = path.join(__dirname, '__fixtures__', `${name}.md`); const file = await vfile.read(filePath); + const fileContentPreprocessed = preprocessor({ + fileContent: file.toString(), + filePath, + admonitions: DefaultAdmonitionOptions, + markdownConfig: { + mermaid: false, + mdx1Compat: { + admonitions: true, + comments: false, + headingIds: false, + }, + }, + }); + + /* + // TODO we shouldn't use rehype in these tests + // this requires to re-implement admonitions with mdxJsxFlowElement + const {default: mdx} = await import('remark-mdx'); + const result = await remark() + .use(directives) + .use(plugin) + .use(mdx) + .process(fileContentPreprocessed); + return result.value; + */ const result = await remark() + .use(directives) .use(plugin, options) .use(remark2rehype) .use(stringify) - .process(file); + .process(fileContentPreprocessed); - return result.toString(); + return result.value; }; describe('admonitions remark plugin', () => { it('base', async () => { const result = await processFixture('base'); - expect(result).toMatchSnapshot(); + await expect(result).toMatchSnapshot(); }); it('default behavior for custom keyword', async () => { const result = await processFixture('base', { keywords: ['tip'], - // extendDefaults: false, // By default we don't extend + extendDefaults: undefined, // By default we extend }); expect(result).toMatchSnapshot(); }); @@ -60,13 +88,6 @@ describe('admonitions remark plugin', () => { expect(result).toMatchSnapshot(); }); - it('custom tag', async () => { - const result = await processFixture('base', { - tag: '++++', - }); - expect(result).toMatchSnapshot(); - }); - it('interpolation', async () => { const result = await processFixture('interpolation'); expect(result).toMatchSnapshot(); diff --git a/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts b/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts index c05a88c1c2..1ca3d864ad 100644 --- a/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts @@ -4,25 +4,26 @@ * 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 type {Transformer, Processor, Plugin} from 'unified'; -import type {Literal} from 'mdast'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {Transformer, Processor} from 'unified'; -const NEWLINE = '\n'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {ContainerDirective} from 'mdast-util-directive'; +import type {Parent} from 'mdast'; + +// TODO as of April 2023, no way to import/re-export this ESM type easily :/ +// This might change soon, likely after TS 5.2 +// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391 +// import type {Plugin} from 'unified'; +type Plugin = any; // TODO fix this asap -// TODO not ideal option shape -// First let upgrade to MDX 2.0 -// Maybe we'll want to provide different tags for different admonition types? -// Also maybe rename "keywords" to "types"? export type AdmonitionOptions = { - tag: string; keywords: string[]; extendDefaults: boolean; }; export const DefaultAdmonitionOptions: AdmonitionOptions = { - tag: ':::', keywords: [ 'secondary', 'info', @@ -34,16 +35,16 @@ export const DefaultAdmonitionOptions: AdmonitionOptions = { 'important', 'caution', ], - extendDefaults: false, // TODO make it true by default: breaking change + extendDefaults: true, }; -function escapeRegExp(s: string): string { - return s.replace(/[-[\]{}()*+?.\\^$|/]/g, '\\$&'); -} - -function normalizeOptions( - providedOptions: Partial, +export function normalizeAdmonitionOptions( + providedOptions: Partial | true, ): AdmonitionOptions { + if (providedOptions === true) { + return DefaultAdmonitionOptions; + } + const options = {...DefaultAdmonitionOptions, ...providedOptions}; // By default it makes more sense to append keywords to the default ones @@ -58,181 +59,84 @@ function normalizeOptions( return options; } -// This string value does not matter much -// It is ignored because nodes are using hName/hProperties coming from HAST -const admonitionNodeType = 'admonitionHTML'; +type DirectiveLabel = Parent; +type DirectiveContent = ContainerDirective['children']; + +function parseDirective(directive: ContainerDirective): { + directiveLabel: DirectiveLabel | undefined; + contentNodes: DirectiveContent; +} { + const hasDirectiveLabel = + directive.children?.[0]?.data?.directiveLabel === true; + if (hasDirectiveLabel) { + const [directiveLabel, ...contentNodes] = directive.children; + return {directiveLabel: directiveLabel as DirectiveLabel, contentNodes}; + } + return {directiveLabel: undefined, contentNodes: directive.children}; +} + +function getTextOnlyTitle(directiveLabel: DirectiveLabel): string | undefined { + const isTextOnlyTitle = + directiveLabel?.children?.length === 1 && + directiveLabel?.children?.[0]?.type === 'text'; + return isTextOnlyTitle + ? // @ts-expect-error: todo type + (directiveLabel?.children?.[0].value as string) + : undefined; +} const plugin: Plugin = function plugin( this: Processor, optionsInput: Partial = {}, ): Transformer { - const options = normalizeOptions(optionsInput); + const {keywords} = normalizeAdmonitionOptions(optionsInput); - const keywords = Object.values(options.keywords).map(escapeRegExp).join('|'); - const nestingChar = escapeRegExp(options.tag.slice(0, 1)); - const tag = escapeRegExp(options.tag); + return async (root) => { + visit(root, (node) => { + if (node.type === 'containerDirective') { + const directive = node as ContainerDirective; + const isAdmonition = keywords.includes(directive.name); - // resolve th nesting level of an opening tag - // ::: -> 0, :::: -> 1, ::::: -> 2 ... - const nestingLevelRegex = new RegExp( - `^${tag}(?${nestingChar}*)`, - ); - - const regex = new RegExp(`${tag}${nestingChar}*(${keywords})(?: *(.*))?\n`); - const escapeTag = new RegExp( - escapeRegExp(`\\${options.tag}${options.tag.slice(0, 1)}*`), - 'g', - ); - - // The tokenizer is called on blocks to determine if there is an admonition - // present and create tags for it - function blockTokenizer(this: any, eat: any, value: string, silent: boolean) { - // Stop if no match or match does not start at beginning of line - const match = regex.exec(value); - if (!match || match.index !== 0) { - return false; - } - // If silent return the match - if (silent) { - return true; - } - - const now = eat.now(); - const [opening, keyword, title] = match as string[] as [ - string, - string, - string, - ]; - const food = []; - const content = []; - // get the nesting level of the opening tag - const openingLevel = - nestingLevelRegex.exec(opening)!.groups!.nestingLevel!.length; - // used as a stack to keep track of nested admonitions - const nestingLevels: number[] = [openingLevel]; - - let newValue = value; - // consume lines until a closing tag - let idx = newValue.indexOf(NEWLINE); - while (idx !== -1) { - // grab this line and eat it - const next = newValue.indexOf(NEWLINE, idx + 1); - const line = - next !== -1 ? newValue.slice(idx + 1, next) : newValue.slice(idx + 1); - food.push(line); - newValue = newValue.slice(idx + 1); - const nesting = nestingLevelRegex.exec(line); - idx = newValue.indexOf(NEWLINE); - if (!nesting) { - content.push(line); - continue; - } - const tagLevel = nesting.groups!.nestingLevel!.length; - // first level - if (nestingLevels.length === 0) { - nestingLevels.push(tagLevel); - content.push(line); - continue; - } - const currentLevel = nestingLevels[nestingLevels.length - 1]!; - if (tagLevel < currentLevel) { - // entering a nested admonition block - nestingLevels.push(tagLevel); - } else if (tagLevel === currentLevel) { - // closing a nested admonition block - nestingLevels.pop(); - // the closing tag is NOT part of the content - if (nestingLevels.length === 0) { - break; + if (!isAdmonition) { + return; } - } - content.push(line); - } - // consume the processed tag and replace escape sequences - const contentString = content.join(NEWLINE).replace(escapeTag, options.tag); - const add = eat(opening + food.join(NEWLINE)); + const {directiveLabel, contentNodes} = parseDirective(directive); - // parse the content in block mode - const exit = this.enterBlock(); - const contentNodes = this.tokenizeBlock(contentString, now); - exit(); + const textOnlyTitle = + directive.attributes?.title ?? + (directiveLabel ? getTextOnlyTitle(directiveLabel) : undefined); - const titleNodes = this.tokenizeInline(title, now); - - const isSimpleTextTitle = - titleNodes.length === 1 && titleNodes[0].type === 'text'; - - const element = { - type: admonitionNodeType, - data: { - // hName/hProperties come from HAST + // Transform the mdast directive node to a hast admonition node // See https://github.com/syntax-tree/mdast-util-to-hast#fields-on-nodes - hName: 'admonition', - hProperties: { - ...(title && isSimpleTextTitle && {title}), - type: keyword, - }, - }, - children: [ - // For titles containing MDX syntax: create a custom element. The theme - // component will extract it and render it nicely. - // - // Temporary workaround, because it's complex in MDX v1 to emit - // interpolated JSX prop syntax (title={<>my title}). - // For this reason, we use children instead of the title prop. - title && - !isSimpleTextTitle && { - type: admonitionNodeType, + // TODO in MDX v2 we should transform the whole directive to + // mdxJsxFlowElement instead of using hast + directive.data = { + hName: 'admonition', + hProperties: { + ...(textOnlyTitle && {title: textOnlyTitle}), + type: directive.name, + }, + }; + directive.children = contentNodes; + + // TODO legacy MDX v1 workaround + // v1: not possible to inject complex JSX elements as props + // v2: now possible: use a mdxJsxFlowElement element + if (directiveLabel && !textOnlyTitle) { + const complexTitleNode = { + type: 'mdxAdmonitionTitle', data: { hName: 'mdxAdmonitionTitle', hProperties: {}, }, - children: titleNodes, - }, - ...contentNodes, - ].filter(Boolean), - }; - - return add(element); - } - - // add tokenizer to parser after fenced code blocks - const Parser = this.Parser.prototype; - Parser.blockTokenizers.admonition = blockTokenizer; - Parser.blockMethods.splice( - Parser.blockMethods.indexOf('fencedCode') + 1, - 0, - 'admonition', - ); - Parser.interruptParagraph.splice( - Parser.interruptParagraph.indexOf('fencedCode') + 1, - 0, - ['admonition'], - ); - Parser.interruptList.splice( - Parser.interruptList.indexOf('fencedCode') + 1, - 0, - ['admonition'], - ); - Parser.interruptBlockquote.splice( - Parser.interruptBlockquote.indexOf('fencedCode') + 1, - 0, - ['admonition'], - ); - - return (root) => { - // escape everything except admonitionHTML nodes - visit( - root, - (node: unknown): node is Literal => - (node as Literal | undefined)?.type !== admonitionNodeType, - (node: Literal) => { - if (node.value) { - node.value = node.value.replace(escapeTag, options.tag); + children: directiveLabel.children, + }; + // @ts-expect-error: invented node type + directive.children.unshift(complexTitleNode); } - }, - ); + } + }); }; }; diff --git a/packages/docusaurus-mdx-loader/src/remark/details/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/details/__tests__/index.test.ts new file mode 100644 index 0000000000..7badfeda36 --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/remark/details/__tests__/index.test.ts @@ -0,0 +1,76 @@ +/** + * 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 details from '..'; + +async function process(content: string) { + const {remark} = await import('remark'); + + const {default: mdx} = await import('remark-mdx'); + + const result = await remark().use(mdx).use(details).process(content); + + return result.value; +} + +describe('details remark plugin', () => { + it("does nothing if there's no details", async () => { + const input = `# Heading 1 + +Some content +`; + const result = await process(input); + expect(result).toEqual(result); + }); + + it('can convert details', async () => { + const input = `# Details element example + +
+ Toggle me! +
+
This is the detailed content
+
+
+ + Nested toggle! Some surprise inside... + +
+ 😲😲😲😲😲 +
+
+
+
`; + + const result = await process(input); + + expect(result).toMatchInlineSnapshot(` + "# Details element example + +
+ Toggle me! + +
+
This is the detailed content
+ +
+ +
+ + Nested toggle! Some surprise inside... + + +
+ 😲😲😲😲😲 +
+
+
+
+ " + `); + }); +}); diff --git a/packages/docusaurus-mdx-loader/src/remark/details/index.ts b/packages/docusaurus-mdx-loader/src/remark/details/index.ts new file mode 100644 index 0000000000..8d2f1249e7 --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/remark/details/index.ts @@ -0,0 +1,25 @@ +/** + * 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'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {Transformer} from 'unified'; + +// @ts-expect-error: ES support... +import type {MdxJsxFlowElement} from 'mdast-util-mdx'; + +// Transform
to
+// MDX 2 doesn't allow to substitute html elements with the provider anymore +export default function plugin(): Transformer { + return (root) => { + visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => { + if (node.name === 'details') { + node.name = 'Details'; + } + }); + }; +} diff --git a/packages/docusaurus-mdx-loader/src/remark/head/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/head/__tests__/index.test.ts new file mode 100644 index 0000000000..5bf4450525 --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/remark/head/__tests__/index.test.ts @@ -0,0 +1,76 @@ +/** + * 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 head from '..'; + +async function process(content: string) { + const {remark} = await import('remark'); + + const {default: mdx} = await import('remark-mdx'); + + const result = await remark().use(mdx).use(head).process(content); + + return result.value; +} + +describe('head remark plugin', () => { + it("does nothing if there's no details", async () => { + const input = `# Heading + + + + + Head Metadata customized title! + + + + + +Some content +`; + const result = await process(input); + expect(result).toEqual(result); + }); + + it('can convert head', async () => { + const input = `# Heading + + + + + Head Metadata customized title! + + + + + +Some content;`; + + const result = await process(input); + + expect(result).toMatchInlineSnapshot(` + "# Heading + + + + + + + Head Metadata customized title! + + + + + + + + + Some content; + " + `); + }); +}); diff --git a/packages/docusaurus-mdx-loader/src/remark/head/index.ts b/packages/docusaurus-mdx-loader/src/remark/head/index.ts new file mode 100644 index 0000000000..bf064238f5 --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/remark/head/index.ts @@ -0,0 +1,25 @@ +/** + * 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'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {Transformer} from 'unified'; + +// @ts-expect-error: ES support... +import type {MdxJsxFlowElement} from 'mdast-util-mdx'; + +// Transform to +// MDX 2 doesn't allow to substitute html elements with the provider anymore +export default function plugin(): Transformer { + return (root) => { + visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => { + if (node.name === 'head') { + node.name = 'Head'; + } + }); + }; +} diff --git a/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts index 47a31c836f..f43a90601d 100644 --- a/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts @@ -7,18 +7,18 @@ /* Based on remark-slug (https://github.com/remarkjs/remark-slug) and gatsby-remark-autolink-headers (https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-remark-autolink-headers) */ -import remark from 'remark'; import u from 'unist-builder'; import removePosition from 'unist-util-remove-position'; -import toString from 'mdast-util-to-string'; +import {toString} from 'mdast-util-to-string'; import visit from 'unist-util-visit'; import slug from '../index'; import type {Plugin} from 'unified'; import type {Parent} from 'unist'; -function process(doc: string, plugins: Plugin[] = []) { - const processor = remark().use({plugins: [...plugins, slug]}); - return removePosition(processor.runSync(processor.parse(doc)), true); +async function process(doc: string, plugins: Plugin[] = []) { + const {remark} = await import('remark'); + const processor = await remark().use({plugins: [...plugins, slug]}); + return removePosition(await processor.run(processor.parse(doc)), true); } function heading(label: string | null, id: string) { @@ -30,8 +30,8 @@ function heading(label: string | null, id: string) { } describe('headings remark plugin', () => { - it('patches `id`s and `data.hProperties.id', () => { - const result = process('# Normal\n\n## Table of Contents\n\n# Baz\n'); + it('patches `id`s and `data.hProperties.id', async () => { + const result = await process('# Normal\n\n## Table of Contents\n\n# Baz\n'); const expected = u('root', [ u( 'heading', @@ -57,8 +57,8 @@ describe('headings remark plugin', () => { expect(result).toEqual(expected); }); - it('does not overwrite `data` on headings', () => { - const result = process('# Normal\n', [ + it('does not overwrite `data` on headings', async () => { + const result = await process('# Normal\n', [ () => (root) => { (root as Parent).children[0]!.data = {foo: 'bar'}; }, @@ -77,8 +77,8 @@ describe('headings remark plugin', () => { expect(result).toEqual(expected); }); - it('does not overwrite `data.hProperties` on headings', () => { - const result = process('# Normal\n', [ + it('does not overwrite `data.hProperties` on headings', async () => { + const result = await process('# Normal\n', [ () => (root) => { (root as Parent).children[0]!.data = { hProperties: {className: ['foo']}, @@ -99,8 +99,8 @@ describe('headings remark plugin', () => { expect(result).toEqual(expected); }); - it('generates `id`s and `hProperties.id`s, based on `hProperties.id` if they exist', () => { - const result = process( + it('generates `id`s and `hProperties.id`s, based on `hProperties.id` if they exist', async () => { + const result = await process( [ '## Something', '## Something here', @@ -152,8 +152,8 @@ describe('headings remark plugin', () => { expect(result).toEqual(expected); }); - it('creates GitHub-style headings ids', () => { - const result = process( + it('creates GitHub-style headings ids', async () => { + const result = await process( [ '## I ♥ unicode', '', @@ -223,8 +223,10 @@ describe('headings remark plugin', () => { expect(result).toEqual(expected); }); - it('generates id from only text contents of headings if they contains HTML tags', () => { - const result = process('# Normal\n'); + it('generates id from only text contents of headings if they contains HTML tags', async () => { + const result = await process( + '# Normal\n', + ); const expected = u('root', [ u( 'heading', @@ -243,8 +245,8 @@ describe('headings remark plugin', () => { expect(result).toEqual(expected); }); - it('creates custom headings ids', () => { - const result = process(` + it('creates custom headings ids', async () => { + const result = await process(` # Heading One {#custom_h1} ## Heading Two {#custom-heading-two} diff --git a/packages/docusaurus-mdx-loader/src/remark/headings/index.ts b/packages/docusaurus-mdx-loader/src/remark/headings/index.ts index 98aaa37f75..a99685e58b 100644 --- a/packages/docusaurus-mdx-loader/src/remark/headings/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/headings/index.ts @@ -9,12 +9,14 @@ import {parseMarkdownHeadingId, createSlugger} from '@docusaurus/utils'; import visit from 'unist-util-visit'; -import mdastToString from 'mdast-util-to-string'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; import type {Heading, Text} from 'mdast'; export default function plugin(): Transformer { - return (root) => { + return async (root) => { + const {toString} = await import('mdast-util-to-string'); + const slugs = createSlugger(); visit(root, 'heading', (headingNode: Heading) => { const data = headingNode.data ?? (headingNode.data = {}); @@ -29,7 +31,7 @@ export default function plugin(): Transformer { const headingTextNodes = headingNode.children.filter( ({type}) => !['html', 'jsx'].includes(type), ); - const heading = mdastToString( + const heading = toString( headingTextNodes.length > 0 ? headingTextNodes : headingNode, ); diff --git a/packages/docusaurus-mdx-loader/src/remark/mdx1Compat/codeCompatPlugin.ts b/packages/docusaurus-mdx-loader/src/remark/mdx1Compat/codeCompatPlugin.ts new file mode 100644 index 0000000000..b50b6a4ddb --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/remark/mdx1Compat/codeCompatPlugin.ts @@ -0,0 +1,36 @@ +/** + * 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'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {Transformer, Processor} from 'unified'; +import type {Code} from 'mdast'; + +// Solution inspired by https://github.com/pomber/docusaurus-mdx-2/blob/main/packages/mdx-loader/src/remark/codeCompat/index.ts +// TODO after MDX 2 we probably don't need this - remove soon? +// Only fenced code blocks are swapped by pre/code MDX components +// Using
 in JSX shouldn't use our MDX components anymore
+
+// To make theme-classic/src/theme/MDXComponents/Pre work
+// we need to fill two properties that mdx v2 doesn't provide anymore
+export default function codeCompatPlugin(this: Processor): Transformer {
+  return (root) => {
+    visit(root, 'code', (node: Code) => {
+      node.data = node.data || {};
+      node.data.hProperties = node.data.hProperties || {};
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      (node.data.hProperties as any).metastring = node.meta;
+
+      // Retrocompatible support for live codeblock metastring
+      // Not really the appropriate place to handle that :s
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      (node.data.hProperties as any).live = node.meta
+        ?.split(' ')
+        .includes('live');
+    });
+  };
+}
diff --git a/packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/__snapshots__/index.test.ts.snap
deleted file mode 100644
index be606c1c5c..0000000000
--- a/packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/__snapshots__/index.test.ts.snap
+++ /dev/null
@@ -1,49 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`mermaid remark plugin does nothing if there's no mermaid code block 1`] = `
-"
-
-
-const layoutProps = {
-  
-};
-const MDXLayout = "wrapper"
-export default function MDXContent({
-  components,
-  ...props
-}) {
-  return 
-    

{\`Heading 1\`}

-

{\`No Mermaid diagram :(\`}

-
{\`this is not mermaid
-\`}
-
; -} -; -MDXContent.isMDXComponent = true;" -`; - -exports[`mermaid remark plugin works for basic mermaid code blocks 1`] = ` -" - - -const layoutProps = { - -}; -const MDXLayout = "wrapper" -export default function MDXContent({ - components, - ...props -}) { - return -

{\`Heading 1\`}

- B;/n A-->C;/n B-->D;/n C-->D;" - }}> -
; -} -; -MDXContent.isMDXComponent = true;" -`; diff --git a/packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/index.test.ts index e612729554..30e0c35311 100644 --- a/packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/index.test.ts @@ -5,19 +5,28 @@ * LICENSE file in the root directory of this source tree. */ -import {createCompiler} from '@mdx-js/mdx'; +import remark2rehype from 'remark-rehype'; +import stringify from 'rehype-stringify'; import mermaid from '..'; -describe('mermaid remark plugin', () => { - function createTestCompiler() { - return createCompiler({ - remarkPlugins: [mermaid], - }); - } +async function process(content: string) { + const {remark} = await import('remark'); + // const {default: mdx} = await import('remark-mdx'); + // const result = await remark().use(mermaid).use(mdx).process(content); + + const result = await remark() + .use(mermaid) + .use(remark2rehype) + .use(stringify) + .process(content); + + return result.value; +} + +describe('mermaid remark plugin', () => { it("does nothing if there's no mermaid code block", async () => { - const mdxCompiler = createTestCompiler(); - const result = await mdxCompiler.process( + const result = await process( `# Heading 1 No Mermaid diagram :( @@ -27,12 +36,17 @@ this is not mermaid \`\`\` `, ); - expect(result.contents).toMatchSnapshot(); + + expect(result).toMatchInlineSnapshot(` + "

Heading 1

+

No Mermaid diagram :(

+
this is not mermaid
+      
" + `); }); it('works for basic mermaid code blocks', async () => { - const mdxCompiler = createTestCompiler(); - const result = await mdxCompiler.process(`# Heading 1 + const result = await process(`# Heading 1 \`\`\`mermaid graph TD; @@ -41,6 +55,13 @@ graph TD; B-->D; C-->D; \`\`\``); - expect(result.contents).toMatchSnapshot(); + expect(result).toMatchInlineSnapshot(` + "

Heading 1

+ " + `); }); }); diff --git a/packages/docusaurus-mdx-loader/src/remark/mermaid/index.ts b/packages/docusaurus-mdx-loader/src/remark/mermaid/index.ts index d0b6232cdf..7947d3387e 100644 --- a/packages/docusaurus-mdx-loader/src/remark/mermaid/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/mermaid/index.ts @@ -6,6 +6,7 @@ */ import visit from 'unist-util-visit'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; import type {Code} from 'mdast'; @@ -17,6 +18,7 @@ export default function plugin(): Transformer { return (root) => { visit(root, 'code', (node: Code, index, parent) => { if (node.lang === 'mermaid') { + // TODO migrate to mdxJsxFlowElement? cf admonitions parent!.children.splice(index, 1, { type: 'mermaidCodeBlock', data: { diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap index ba71805a2a..8af155e2c9 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap @@ -45,7 +45,7 @@ exports[`toc remark plugin escapes inline code 1`] = ` id: 'divitestidiv-1', level: 2 } -]; +] ## \`\` @@ -78,7 +78,7 @@ exports[`toc remark plugin exports even with existing name 1`] = ` id: 'avengers', level: 3 } -]; +] ## Thanos @@ -89,11 +89,11 @@ exports[`toc remark plugin exports even with existing name 1`] = ` `; exports[`toc remark plugin handles empty headings 1`] = ` -"export const toc = []; +"export const toc = [] # Ignore this -## +## ## ![](an-image.svg) " @@ -120,7 +120,7 @@ export const toc = [ id: 'again', level: 3 } -]; +] ## Title @@ -133,7 +133,7 @@ Content. `; exports[`toc remark plugin outputs empty array for no TOC 1`] = ` -"export const toc = []; +"export const toc = [] foo @@ -172,9 +172,9 @@ exports[`toc remark plugin works on non text phrasing content 1`] = ` id: 'inlinecode', level: 2 } -]; +] -## _Emphasis_ +## *Emphasis* ### **Importance** @@ -208,7 +208,7 @@ exports[`toc remark plugin works on text content 1`] = ` id: 'i--unicode', level: 2 } -]; +] ### Endi diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts index 6df3e94e67..0468feea1d 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts @@ -6,22 +6,25 @@ */ import path from 'path'; -import remark from 'remark'; -import mdx from 'remark-mdx'; import vfile from 'to-vfile'; import plugin from '../index'; import headings from '../../headings/index'; const processFixture = async (name: string) => { + const {remark} = await import('remark'); + const {default: gfm} = await import('remark-gfm'); + const {default: mdx} = await import('remark-mdx'); + const filePath = path.join(__dirname, '__fixtures__', `${name}.md`); const file = await vfile.read(filePath); const result = await remark() .use(headings) + .use(gfm) .use(mdx) .use(plugin) .process(file); - return result.toString(); + return result.value; }; describe('toc remark plugin', () => { diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts index 5e6c694dc3..fea1585db9 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts @@ -8,28 +8,42 @@ import {parse, type ParserOptions} from '@babel/parser'; import traverse from '@babel/traverse'; import stringifyObject from 'stringify-object'; -import toString from 'mdast-util-to-string'; import visit from 'unist-util-visit'; import {toValue} from '../utils'; - import type {Identifier} from '@babel/types'; -import type {TOCItem} from '../..'; import type {Node, Parent} from 'unist'; import type {Heading, Literal} from 'mdast'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; +// TODO as of April 2023, no way to import/re-export this ESM type easily :/ +// This might change soon, likely after TS 5.2 +// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391 +// import type {Plugin} from 'unified'; +type Plugin = any; // TODO fix this asap + +export type TOCItem = { + readonly value: string; + readonly id: string; + readonly level: number; +}; + const parseOptions: ParserOptions = { plugins: ['jsx'], sourceType: 'module', }; -const name = 'toc'; - -const isImport = (child: Node): child is Literal => child.type === 'import'; +const isImport = (child: any): child is Literal => + child.type === 'mdxjsEsm' && child.value.startsWith('import'); const hasImports = (index: number) => index > -1; -const isExport = (child: Node): child is Literal => child.type === 'export'; +const isExport = (child: any): child is Literal => + child.type === 'mdxjsEsm' && child.value.startsWith('export'); -const isTarget = (child: Literal) => { +interface PluginOptions { + name?: string; +} + +const isTarget = (child: Literal, name: string) => { let found = false; const ast = parse(child.value, parseOptions); traverse(ast, { @@ -42,24 +56,23 @@ const isTarget = (child: Literal) => { return found; }; -const getOrCreateExistingTargetIndex = (children: Node[]) => { +const getOrCreateExistingTargetIndex = async ( + children: Node[], + name: string, +) => { let importsIndex = -1; let targetIndex = -1; children.forEach((child, index) => { if (isImport(child)) { importsIndex = index; - } else if (isExport(child) && isTarget(child)) { + } else if (isExport(child) && isTarget(child, name)) { targetIndex = index; } }); if (targetIndex === -1) { - const target = { - default: false, - type: 'export', - value: `export const ${name} = [];`, - }; + const target = await createExportNode(name, []); targetIndex = hasImports(importsIndex) ? importsIndex + 1 : 0; children.splice(targetIndex, 0, target); @@ -68,31 +81,72 @@ const getOrCreateExistingTargetIndex = (children: Node[]) => { return targetIndex; }; -export default function plugin(): Transformer { - return (root) => { +const plugin: Plugin = function plugin( + options: PluginOptions = {}, +): Transformer { + const name = options.name || 'toc'; + + return async (root) => { + const {toString} = await import('mdast-util-to-string'); const headings: TOCItem[] = []; - visit(root, 'heading', (child: Heading, index, parent) => { + visit(root, 'heading', (child: Heading) => { const value = toString(child); - // depth: 1 headings are titles and not included in the TOC - if (parent !== root || !value || child.depth < 2) { + // depth:1 headings are titles and not included in the TOC + if (!value || child.depth < 2) { return; } headings.push({ - value: toValue(child), + value: toValue(child, toString), id: child.data!.id as string, level: child.depth, }); }); const {children} = root as Parent; - const targetIndex = getOrCreateExistingTargetIndex(children); + const targetIndex = await getOrCreateExistingTargetIndex(children, name); - if (headings.length) { - children[targetIndex]!.value = `export const ${name} = ${stringifyObject( - headings, - )};`; + if (headings?.length) { + children[targetIndex] = await createExportNode(name, headings); } }; +}; + +export default plugin; + +async function createExportNode(name: string, object: any) { + const {valueToEstree} = await import('estree-util-value-to-estree'); + + return { + type: 'mdxjsEsm', + value: `export const ${name} = ${stringifyObject(object)}`, + data: { + estree: { + type: 'Program', + body: [ + { + type: 'ExportNamedDeclaration', + declaration: { + type: 'VariableDeclaration', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name, + }, + init: valueToEstree(object), + }, + ], + kind: 'const', + }, + specifiers: [], + source: null, + }, + ], + sourceType: 'module', + }, + }, + }; } diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/img.md b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/img.md index 9690775449..61b961202c 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/img.md +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/img.md @@ -4,6 +4,8 @@ ![img](static/img.png) +in paragraph ![img](static/img.png) + ![img from second static folder](/img2.png) ![img from second static folder](./static2/img2.png) @@ -16,11 +18,9 @@ ![site alias](@site/static/img.png) -![img with hash](/img.png#light) -![img with hash](/img.png#dark) +![img with hash](/img.png#light) ![img with hash](/img.png#dark) -![img with query](/img.png?w=10) -![img with query](/img.png?w=10&h=10) +![img with query](/img.png?w=10) ![img with query](/img.png?w=10&h=10) ![img with both](/img.png?w=10&h=10#light) diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap index 8366a7b23e..4745422c1e 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`transformImage plugin does not choke on invalid image 1`] = ` -"{"invalid/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/invalid.png").default} /> +"invalid image/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/invalid.png").default} /> " `; @@ -21,27 +21,27 @@ exports[`transformImage plugin transform md images to 1`] = ` /node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -{"img"}/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> +img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static2/img2.png").default} width="256" height="82" /> +in paragraph img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static2/img2.png").default} width="256" height="82" /> +img from second static folder/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static2/img2.png").default} width="256" height="82" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png").default} width="256" height="82" /> +img from second static folder/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static2/img2.png").default} width="256" height="82" /> -{"img"}/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} title="Title" width="200" height="200" /> {"img"}/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> +img with URL encoded chars/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png").default} width="256" height="82" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} title="'Quoted' title" width="200" height="200" /> +img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} title="Title" width="200" height="200" /> img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -{"site/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> +!/[img with "quotes"]/(./static/img.png ''Quoted' title') -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default + '#light'} width="200" height="200" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default + '#dark'} width="200" height="200" /> +site alias/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10").default} width="200" height="200" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10").default} width="200" height="200" /> +img with hash/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default + '#light'} width="200" height="200" /> img with hash/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png").default + '#dark'} width="200" height="200" /> -{"img/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10").default + '#light'} width="200" height="200" /> +img with query/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10").default} width="200" height="200" /> img with query/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10").default} width="200" height="200" /> + +img with both/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10").default + '#light'} width="200" height="200" /> ## Heading diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts index d25defc122..f491fd7ac3 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts @@ -7,25 +7,24 @@ import {jest} from '@jest/globals'; import path from 'path'; -import remark from 'remark'; -import mdx from 'remark-mdx'; import vfile from 'to-vfile'; import plugin, {type PluginOptions} from '../index'; -import headings from '../../headings/index'; const processFixture = async ( name: string, options: Partial, ) => { + const {remark} = await import('remark'); + const {default: mdx} = await import('remark-mdx'); const filePath = path.join(__dirname, `__fixtures__/${name}.md`); const file = await vfile.read(filePath); + const result = await remark() - .use(headings) .use(mdx) .use(plugin, {siteDir: __dirname, staticDirs: [], ...options}) .process(file); - return result.toString(); + return result.value; }; const staticDirs = [ diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts index 06892e3ed0..5bd9c1d9a9 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts @@ -9,7 +9,6 @@ import path from 'path'; import url from 'url'; import fs from 'fs-extra'; import {promisify} from 'util'; -import logger from '@docusaurus/logger'; import { toMessageRelativeFilePath, posixPath, @@ -20,15 +19,20 @@ import { import visit from 'unist-util-visit'; import escapeHtml from 'escape-html'; import sizeOf from 'image-size'; +import logger from '@docusaurus/logger'; +import {assetRequireAttributeValue} from '../utils'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {MdxJsxTextElement} from 'mdast-util-mdx'; +import type {Image} from 'mdast'; import type {Parent} from 'unist'; -import type {Image, Literal} from 'mdast'; const { loaders: {inlineMarkdownImageFileLoader}, } = getFileLoaderUtils(); -export type PluginOptions = { +type PluginOptions = { staticDirs: string[]; siteDir: string; }; @@ -40,10 +44,14 @@ type Context = PluginOptions & { type Target = [node: Image, index: number, parent: Parent]; async function toImageRequireNode( - [node, index, parent]: Target, + [node]: Target, imagePath: string, filePath: string, ) { + // MdxJsxTextElement => see https://github.com/facebook/docusaurus/pull/8288#discussion_r1125871405 + const jsxNode = node as unknown as MdxJsxTextElement; + const attributes: MdxJsxTextElement['attributes'] = []; + let relativeImagePath = posixPath( path.relative(path.dirname(filePath), imagePath), ); @@ -52,21 +60,46 @@ async function toImageRequireNode( const parsedUrl = url.parse(node.url); const hash = parsedUrl.hash ?? ''; const search = parsedUrl.search ?? ''; - - const alt = node.alt ? `alt={"${escapeHtml(node.alt)}"} ` : ''; - const src = `require("${inlineMarkdownImageFileLoader}${ + const requireString = `${inlineMarkdownImageFileLoader}${ escapePath(relativeImagePath) + search - }").default${hash ? ` + '${hash}'` : ''}`; - const title = node.title ? ` title="${escapeHtml(node.title)}"` : ''; - let width = ''; - let height = ''; + }`; + if (node.alt) { + attributes.push({ + type: 'mdxJsxAttribute', + name: 'alt', + value: escapeHtml(node.alt), + }); + } + + attributes.push({ + type: 'mdxJsxAttribute', + name: 'src', + value: assetRequireAttributeValue(requireString, hash), + }); + + if (node.title) { + attributes.push({ + type: 'mdxJsxAttribute', + name: 'title', + value: escapeHtml(node.title), + }); + } + try { const size = (await promisify(sizeOf)(imagePath))!; if (size.width) { - width = ` width="${size.width}"`; + attributes.push({ + type: 'mdxJsxAttribute', + name: 'width', + value: String(size.width), + }); } if (size.height) { - height = ` height="${size.height}"`; + attributes.push({ + type: 'mdxJsxAttribute', + name: 'height', + value: String(size.height), + }); } } catch (err) { // Workaround for https://github.com/yarnpkg/berry/pull/3889#issuecomment-1034469784 @@ -77,12 +110,14 @@ ${(err as Error).message}`; } } - const jsxNode: Literal = { - type: 'jsx', - value: ``, - }; + Object.keys(jsxNode).forEach( + (key) => delete jsxNode[key as keyof typeof jsxNode], + ); - parent.children.splice(index, 1, jsxNode); + jsxNode.type = 'mdxJsxTextElement'; + jsxNode.name = 'img'; + jsxNode.attributes = attributes; + jsxNode.children = []; } async function ensureImageFileExist(imagePath: string, sourceFilePath: string) { @@ -122,7 +157,7 @@ async function getImageAbsolutePath( } return imageFilePath; } - // Relative paths are resolved against the source file's folder. + // relative paths are resolved against the source file's folder const imageFilePath = path.join( path.dirname(filePath), decodeURIComponent(imagePath), diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md index 6a8a0e44ab..b179caa006 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md @@ -4,6 +4,8 @@ [asset](./asset.pdf) +in paragraph [asset](./asset.pdf) + [asset with URL encoded chars](./asset%20%282%29.pdf) [asset with hash](./asset.pdf#page=2) diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap index 2e6d8d8648..06f8fcbcab 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap @@ -12,15 +12,17 @@ exports[`transformAsset plugin pathname protocol 1`] = ` exports[`transformAsset plugin transform md links to 1`] = ` "[asset](https://example.com/asset.pdf) -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}> +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default} /> -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}>asset +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset (2).pdf').default}>asset with URL encoded chars +in paragraph /node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default + '#page=2'}>asset with hash +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset (2).pdf").default}>asset with URL encoded chars -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default} title="Title">asset +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default + '#page=2'}>asset with hash + +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default} title="Title">asset [page](noUrl.md) @@ -34,24 +36,24 @@ exports[`transformAsset plugin transform md links to 1`] = ` [assets](/github/!file-loader!/assets.pdf) -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}>asset +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static2/asset2.pdf').default}>asset2 +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static2/asset2.pdf").default}>asset2 -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>staticAsset.pdf +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>staticAsset.pdf -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>@site/static/staticAsset.pdf +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>@site/static/staticAsset.pdf -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default + '#page=2'} title="Title">@site/static/staticAsset.pdf +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default + '#page=2'} title="Title">@site/static/staticAsset.pdf -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>Just staticAsset.pdf, and /node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>awesome staticAsset 2.pdf 'It is really "AWESOME"', but also /node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>coded staticAsset 3.pdf +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>Just staticAsset.pdf, and /node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>**awesome** staticAsset 2.pdf 'It is really "AWESOME"', but also /node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>coded \`staticAsset 3.pdf\` -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png').default}>{"Clickable/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png").default} width="200" height="200" /> +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png").default}>Clickable Docusaurus logo/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png").default} width="200" height="200" /> -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}>Stylized link to asset file +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>Stylized link to asset file -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./data.json').default}>JSON +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./data.json").default}>JSON -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/static-json.json').default}>static JSON +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/static-json.json").default}>static JSON " `; diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts index 181ddd4f73..346c46e599 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts @@ -6,13 +6,13 @@ */ import path from 'path'; -import remark from 'remark'; -import mdx from 'remark-mdx'; import vfile from 'to-vfile'; import plugin from '..'; import transformImage, {type PluginOptions} from '../../transformImage'; const processFixture = async (name: string, options?: PluginOptions) => { + const {remark} = await import('remark'); + const {default: mdx} = await import('remark-mdx'); const siteDir = path.join(__dirname, `__fixtures__`); const staticDirs = [ path.join(siteDir, 'static'), @@ -29,7 +29,7 @@ const processFixture = async (name: string, options?: PluginOptions) => { }) .process(file); - return result.toString(); + return result.value; }; describe('transformAsset plugin', () => { diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.ts b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.ts index 33602c0d26..7108602334 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.ts @@ -17,8 +17,11 @@ import { } from '@docusaurus/utils'; import visit from 'unist-util-visit'; import escapeHtml from 'escape-html'; -import {stringifyContent} from '../utils'; +import {assetRequireAttributeValue} from '../utils'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {MdxJsxTextElement} from 'mdast-util-mdx'; import type {Parent} from 'unist'; import type {Link, Literal} from 'mdast'; @@ -26,7 +29,7 @@ const { loaders: {inlineMarkdownLinkFileLoader}, } = getFileLoaderUtils(); -export type PluginOptions = { +type PluginOptions = { staticDirs: string[]; siteDir: string; }; @@ -40,11 +43,15 @@ type Target = [node: Link, index: number, parent: Parent]; /** * Transforms the link node to a JSX `` element with a `require()` call. */ -function toAssetRequireNode( - [node, index, parent]: Target, +async function toAssetRequireNode( + [node]: Target, assetPath: string, filePath: string, ) { + // MdxJsxTextElement => see https://github.com/facebook/docusaurus/pull/8288#discussion_r1125871405 + const jsxNode = node as unknown as MdxJsxTextElement; + const attributes: MdxJsxTextElement['attributes'] = []; + // require("assets/file.pdf") means requiring from a package called assets const relativeAssetPath = `./${posixPath( path.relative(path.dirname(filePath), assetPath), @@ -54,23 +61,43 @@ function toAssetRequireNode( const hash = parsedUrl.hash ?? ''; const search = parsedUrl.search ?? ''; - const href = `require('${ + const requireString = `${ // A hack to stop Webpack from using its built-in loader to parse JSON path.extname(relativeAssetPath) === '.json' ? `${relativeAssetPath.replace('.json', '.raw')}!=` : '' - }${inlineMarkdownLinkFileLoader}${ - escapePath(relativeAssetPath) + search - }').default${hash ? ` + '${hash}'` : ''}`; - const children = stringifyContent(node); - const title = node.title ? ` title="${escapeHtml(node.title)}"` : ''; + }${inlineMarkdownLinkFileLoader}${escapePath(relativeAssetPath) + search}`; - const jsxNode: Literal = { - type: 'jsx', - value: `${children}`, - }; + attributes.push({ + type: 'mdxJsxAttribute', + name: 'target', + value: '_blank', + }); - parent.children.splice(index, 1, jsxNode); + attributes.push({ + type: 'mdxJsxAttribute', + name: 'href', + value: assetRequireAttributeValue(requireString, hash), + }); + + if (node.title) { + attributes.push({ + type: 'mdxJsxAttribute', + name: 'title', + value: escapeHtml(node.title), + }); + } + + const {children} = node; + + Object.keys(jsxNode).forEach( + (key) => delete jsxNode[key as keyof typeof jsxNode], + ); + + jsxNode.type = 'mdxJsxTextElement'; + jsxNode.name = 'a'; + jsxNode.attributes = attributes; + jsxNode.children = children; } async function ensureAssetFileExist(assetPath: string, sourceFilePath: string) { @@ -144,7 +171,7 @@ async function processLinkNode(target: Target, context: Context) { context, ); if (assetPath) { - toAssetRequireNode(target, assetPath, context.filePath); + await toAssetRequireNode(target, assetPath, context.filePath); } } diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__fixtures__/has-mdx-code-blocks.mdx b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__fixtures__/has-mdx-code-blocks.mdx deleted file mode 100644 index bf3ea16967..0000000000 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__fixtures__/has-mdx-code-blocks.mdx +++ /dev/null @@ -1,95 +0,0 @@ -# MDX code blocks test document - -## Some basic markdown - -text - -[link](https://facebook.com) - -**bold** - -![image](https://facebook.com/favicon.ico) - -## Some basic MDX - -import XYZ from 'xyz'; - - - Test - - -## Some basic MDX code block - -```mdx-code-block -import Avatar from 'avatar'; - - -
Sebastien Lorber
-
-``` - -## Some complex MDX with nested code blocks - - - - -```bash -GIT_USER= yarn deploy -``` - - - - - ```batch - cmd /C "set "GIT_USER=" && yarn deploy" - ``` - - - - -```powershell -cmd /C 'set "GIT_USER=" && yarn deploy' -``` - - - - -## Some complex MDX code block with nested code blocks - -````mdx-code-block - - - -```bash -GIT_USER= yarn deploy -``` - - - - -```batch -cmd /C "set "GIT_USER=" && yarn deploy" -``` - - - - -```powershell -cmd /C 'set "GIT_USER=" && yarn deploy' -``` - - - -```` diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap deleted file mode 100644 index 9b8ed7b0ad..0000000000 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,819 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks 1`] = ` -"# MDX code blocks test document - -## Some basic markdown - -text - -[link](https://facebook.com) - -**bold** - -![image](https://facebook.com/favicon.ico) - -## Some basic MDX - -import XYZ from 'xyz'; - - - Test - - -## Some basic MDX code block - -import Avatar from 'avatar'; - - -
Sebastien Lorber
-
- -## Some complex MDX with nested code blocks - - - - -\`\`\`bash -GIT_USER= yarn deploy -\`\`\` - - - - - \`\`\`batch - cmd /C "set "GIT_USER=" && yarn deploy" - \`\`\` - - - - -\`\`\`powershell -cmd /C 'set "GIT_USER=" && yarn deploy' -\`\`\` - - - - -## Some complex MDX code block with nested code blocks - - - - -\`\`\`bash -GIT_USER= yarn deploy -\`\`\` - - - - -\`\`\`batch -cmd /C "set "GIT_USER=" && yarn deploy" -\`\`\` - - - - -\`\`\`powershell -cmd /C 'set "GIT_USER=" && yarn deploy' -\`\`\` - - - -" -`; - -exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks AST 1`] = ` -{ - "children": [ - { - "children": [ - { - "position": Position { - "end": { - "column": 32, - "line": 1, - "offset": 31, - }, - "indent": [], - "start": { - "column": 3, - "line": 1, - "offset": 2, - }, - }, - "type": "text", - "value": "MDX code blocks test document", - }, - ], - "depth": 1, - "position": Position { - "end": { - "column": 32, - "line": 1, - "offset": 31, - }, - "indent": [], - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "heading", - }, - { - "children": [ - { - "position": Position { - "end": { - "column": 23, - "line": 3, - "offset": 55, - }, - "indent": [], - "start": { - "column": 4, - "line": 3, - "offset": 36, - }, - }, - "type": "text", - "value": "Some basic markdown", - }, - ], - "depth": 2, - "position": Position { - "end": { - "column": 23, - "line": 3, - "offset": 55, - }, - "indent": [], - "start": { - "column": 1, - "line": 3, - "offset": 33, - }, - }, - "type": "heading", - }, - { - "children": [ - { - "position": Position { - "end": { - "column": 5, - "line": 5, - "offset": 61, - }, - "indent": [], - "start": { - "column": 1, - "line": 5, - "offset": 57, - }, - }, - "type": "text", - "value": "text", - }, - ], - "position": Position { - "end": { - "column": 5, - "line": 5, - "offset": 61, - }, - "indent": [], - "start": { - "column": 1, - "line": 5, - "offset": 57, - }, - }, - "type": "paragraph", - }, - { - "children": [ - { - "children": [ - { - "position": Position { - "end": { - "column": 6, - "line": 7, - "offset": 68, - }, - "indent": [], - "start": { - "column": 2, - "line": 7, - "offset": 64, - }, - }, - "type": "text", - "value": "link", - }, - ], - "position": Position { - "end": { - "column": 29, - "line": 7, - "offset": 91, - }, - "indent": [], - "start": { - "column": 1, - "line": 7, - "offset": 63, - }, - }, - "title": null, - "type": "link", - "url": "https://facebook.com", - }, - ], - "position": Position { - "end": { - "column": 29, - "line": 7, - "offset": 91, - }, - "indent": [], - "start": { - "column": 1, - "line": 7, - "offset": 63, - }, - }, - "type": "paragraph", - }, - { - "children": [ - { - "children": [ - { - "position": Position { - "end": { - "column": 7, - "line": 9, - "offset": 99, - }, - "indent": [], - "start": { - "column": 3, - "line": 9, - "offset": 95, - }, - }, - "type": "text", - "value": "bold", - }, - ], - "position": Position { - "end": { - "column": 9, - "line": 9, - "offset": 101, - }, - "indent": [], - "start": { - "column": 1, - "line": 9, - "offset": 93, - }, - }, - "type": "strong", - }, - ], - "position": Position { - "end": { - "column": 9, - "line": 9, - "offset": 101, - }, - "indent": [], - "start": { - "column": 1, - "line": 9, - "offset": 93, - }, - }, - "type": "paragraph", - }, - { - "children": [ - { - "alt": "image", - "position": Position { - "end": { - "column": 43, - "line": 11, - "offset": 145, - }, - "indent": [], - "start": { - "column": 1, - "line": 11, - "offset": 103, - }, - }, - "title": null, - "type": "image", - "url": "https://facebook.com/favicon.ico", - }, - ], - "position": Position { - "end": { - "column": 43, - "line": 11, - "offset": 145, - }, - "indent": [], - "start": { - "column": 1, - "line": 11, - "offset": 103, - }, - }, - "type": "paragraph", - }, - { - "children": [ - { - "position": Position { - "end": { - "column": 18, - "line": 13, - "offset": 164, - }, - "indent": [], - "start": { - "column": 4, - "line": 13, - "offset": 150, - }, - }, - "type": "text", - "value": "Some basic MDX", - }, - ], - "depth": 2, - "position": Position { - "end": { - "column": 18, - "line": 13, - "offset": 164, - }, - "indent": [], - "start": { - "column": 1, - "line": 13, - "offset": 147, - }, - }, - "type": "heading", - }, - { - "position": Position { - "end": { - "column": 23, - "line": 15, - "offset": 188, - }, - "indent": [], - "start": { - "column": 1, - "line": 15, - "offset": 166, - }, - }, - "type": "import", - "value": "import XYZ from 'xyz';", - }, - { - "position": Position { - "end": { - "column": 7, - "line": 19, - "offset": 287, - }, - "indent": [ - 1, - 1, - ], - "start": { - "column": 1, - "line": 17, - "offset": 190, - }, - }, - "type": "jsx", - "value": " - Test -", - }, - { - "children": [ - { - "position": Position { - "end": { - "column": 29, - "line": 21, - "offset": 317, - }, - "indent": [], - "start": { - "column": 4, - "line": 21, - "offset": 292, - }, - }, - "type": "text", - "value": "Some basic MDX code block", - }, - ], - "depth": 2, - "position": Position { - "end": { - "column": 29, - "line": 21, - "offset": 317, - }, - "indent": [], - "start": { - "column": 1, - "line": 21, - "offset": 289, - }, - }, - "type": "heading", - }, - { - "lang": "mdx-code-block", - "meta": null, - "position": Position { - "end": { - "column": 4, - "line": 29, - "offset": 442, - }, - "indent": [ - 1, - 1, - 1, - 1, - 1, - 1, - ], - "start": { - "column": 1, - "line": 23, - "offset": 319, - }, - }, - "type": "code", - "value": "import Avatar from 'avatar'; - - -
Sebastien Lorber
-
", - }, - { - "children": [ - { - "position": Position { - "end": { - "column": 44, - "line": 31, - "offset": 487, - }, - "indent": [], - "start": { - "column": 4, - "line": 31, - "offset": 447, - }, - }, - "type": "text", - "value": "Some complex MDX with nested code blocks", - }, - ], - "depth": 2, - "position": Position { - "end": { - "column": 44, - "line": 31, - "offset": 487, - }, - "indent": [], - "start": { - "column": 1, - "line": 31, - "offset": 444, - }, - }, - "type": "heading", - }, - { - "position": Position { - "end": { - "column": 25, - "line": 40, - "offset": 688, - }, - "indent": [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - ], - "start": { - "column": 1, - "line": 33, - "offset": 489, - }, - }, - "type": "jsx", - "value": " - ", - }, - { - "lang": "bash", - "meta": null, - "position": Position { - "end": { - "column": 4, - "line": 44, - "offset": 740, - }, - "indent": [ - 1, - 1, - ], - "start": { - "column": 1, - "line": 42, - "offset": 690, - }, - }, - "type": "code", - "value": "GIT_USER= yarn deploy", - }, - { - "position": Position { - "end": { - "column": 28, - "line": 47, - "offset": 782, - }, - "indent": [ - 1, - ], - "start": { - "column": 1, - "line": 46, - "offset": 742, - }, - }, - "type": "jsx", - "value": " - ", - }, - { - "lang": null, - "meta": null, - "position": Position { - "end": { - "column": 8, - "line": 51, - "offset": 865, - }, - "indent": [ - 1, - 1, - ], - "start": { - "column": 1, - "line": 49, - "offset": 784, - }, - }, - "type": "code", - "value": "\`\`\`batch -cmd /C "set "GIT_USER=" && yarn deploy" -\`\`\`", - }, - { - "position": Position { - "end": { - "column": 31, - "line": 54, - "offset": 910, - }, - "indent": [ - 1, - ], - "start": { - "column": 1, - "line": 53, - "offset": 867, - }, - }, - "type": "jsx", - "value": " - ", - }, - { - "lang": "powershell", - "meta": null, - "position": Position { - "end": { - "column": 4, - "line": 58, - "offset": 986, - }, - "indent": [ - 1, - 1, - ], - "start": { - "column": 1, - "line": 56, - "offset": 912, - }, - }, - "type": "code", - "value": "cmd /C 'set "GIT_USER=" && yarn deploy'", - }, - { - "position": Position { - "end": { - "column": 8, - "line": 61, - "offset": 1008, - }, - "indent": [ - 1, - ], - "start": { - "column": 1, - "line": 60, - "offset": 988, - }, - }, - "type": "jsx", - "value": " -", - }, - { - "children": [ - { - "position": Position { - "end": { - "column": 55, - "line": 63, - "offset": 1064, - }, - "indent": [], - "start": { - "column": 4, - "line": 63, - "offset": 1013, - }, - }, - "type": "text", - "value": "Some complex MDX code block with nested code blocks", - }, - ], - "depth": 2, - "position": Position { - "end": { - "column": 55, - "line": 63, - "offset": 1064, - }, - "indent": [], - "start": { - "column": 1, - "line": 63, - "offset": 1010, - }, - }, - "type": "heading", - }, - { - "lang": "mdx-code-block", - "meta": null, - "position": Position { - "end": { - "column": 5, - "line": 95, - "offset": 1585, - }, - "indent": [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - ], - "start": { - "column": 1, - "line": 65, - "offset": 1066, - }, - }, - "type": "code", - "value": " - - -\`\`\`bash -GIT_USER= yarn deploy -\`\`\` - - - - -\`\`\`batch -cmd /C "set "GIT_USER=" && yarn deploy" -\`\`\` - - - - -\`\`\`powershell -cmd /C 'set "GIT_USER=" && yarn deploy' -\`\`\` - - -", - }, - ], - "position": { - "end": { - "column": 1, - "line": 96, - "offset": 1586, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "root", -} -`; diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts deleted file mode 100644 index 13fe031f5b..0000000000 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * 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 path from 'path'; -import remark from 'remark'; -import mdx from 'remark-mdx'; -import vfile from 'to-vfile'; -import plugin from '..'; - -const processFixture = async (name: string) => { - const file = await vfile.read(path.join(__dirname, '__fixtures__', name)); - const result = await remark().use(mdx).use(plugin).process(file); - return result.toString(); -}; - -const processFixtureAST = async (name: string) => { - const file = await vfile.read(path.join(__dirname, '__fixtures__', name)); - return remark().use(mdx).use(plugin).parse(file); -}; - -describe('unwrapMdxCodeBlocks remark plugin', () => { - it('unwraps the mdx code blocks', async () => { - const result = await processFixture('has-mdx-code-blocks.mdx'); - expect(result).toMatchSnapshot(); - }); - - // The AST output should be parsed correctly or the MDX loader won't work! - it('unwraps the mdx code blocks AST', async () => { - const result = await processFixtureAST('has-mdx-code-blocks.mdx'); - expect(result).toMatchSnapshot(); - }); -}); diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts deleted file mode 100644 index 07aee3daeb..0000000000 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * 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 type {Transformer, Processor} from 'unified'; -import type {Code, Parent} from 'mdast'; - -// This plugin is mostly to help integrating Docusaurus with translation systems -// that do not support well MDX embedded JSX syntax (like Crowdin). -// We wrap the JSX syntax in code blocks so that translation tools don't mess up -// with the markup, but the JSX inside such code blocks should still be -// evaluated as JSX -// See https://github.com/facebook/docusaurus/pull/4278 -export default function plugin(this: Processor): Transformer { - return (root) => { - visit(root, 'code', (node: Code, index, parent) => { - if (node.lang === 'mdx-code-block') { - const newChildren = (this.parse(node.value) as Parent).children; - - // Replace the mdx code block by its content, parsed - parent!.children.splice( - parent!.children.indexOf(node), - 1, - ...newChildren, - ); - } - }); - }; -} diff --git a/packages/docusaurus-mdx-loader/src/remark/utils/index.ts b/packages/docusaurus-mdx-loader/src/remark/utils/index.ts index 3bf275085b..da3c402099 100644 --- a/packages/docusaurus-mdx-loader/src/remark/utils/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/utils/index.ts @@ -6,31 +6,99 @@ */ import escapeHtml from 'escape-html'; -import toString from 'mdast-util-to-string'; import type {Parent} from 'unist'; import type {PhrasingContent, Heading} from 'mdast'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {MdxJsxAttributeValueExpression} from 'mdast-util-mdx'; -export function stringifyContent(node: Parent): string { - return (node.children as PhrasingContent[]).map(toValue).join(''); +export function stringifyContent( + node: Parent, + toString: (param: unknown) => string, // TODO weird but works): string { +): string { + return (node.children as PhrasingContent[]) + .map((item) => toValue(item, toString)) + .join(''); } -export function toValue(node: PhrasingContent | Heading): string { +export function toValue( + node: PhrasingContent | Heading, + toString: (param: unknown) => string, // TODO weird but works +): string { switch (node.type) { + case 'mdxJsxTextElement': { + const tag = node.name; + return `<${tag}>${stringifyContent(node, toString)}`; + } case 'text': return escapeHtml(node.value); case 'heading': - return stringifyContent(node); + return stringifyContent(node, toString); case 'inlineCode': return `${escapeHtml(node.value)}`; case 'emphasis': - return `${stringifyContent(node)}`; + return `${stringifyContent(node, toString)}`; case 'strong': - return `${stringifyContent(node)}`; + return `${stringifyContent(node, toString)}`; case 'delete': - return `${stringifyContent(node)}`; + return `${stringifyContent(node, toString)}`; case 'link': - return stringifyContent(node); + return stringifyContent(node, toString); default: return toString(node); } } + +export function assetRequireAttributeValue( + requireString: string, + hash: string, +): MdxJsxAttributeValueExpression { + return { + type: 'mdxJsxAttributeValueExpression', + value: `require("${requireString}").default${hash && ` + '${hash}'`}`, + data: { + estree: { + type: 'Program', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'BinaryExpression', + left: { + type: 'MemberExpression', + object: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'require', + }, + arguments: [ + { + type: 'Literal', + value: requireString, + raw: `"${requireString}"`, + }, + ], + optional: false, + }, + property: { + type: 'Identifier', + name: 'default', + }, + computed: false, + optional: false, + }, + operator: '+', + right: { + type: 'Literal', + value: hash, + raw: `"${hash}"`, + }, + }, + }, + ], + sourceType: 'module', + comments: [], + }, + }, + }; +} diff --git a/packages/docusaurus-migrate/package.json b/packages/docusaurus-migrate/package.json index 23b3cc6023..260f992762 100644 --- a/packages/docusaurus-migrate/package.json +++ b/packages/docusaurus-migrate/package.json @@ -38,7 +38,7 @@ "remark-stringify": "^8.1.0", "semver": "^7.3.8", "tslib": "^2.5.0", - "unified": "^9.2.2", + "unified": "^10.1.2", "unist-util-visit": "^2.0.3" }, "devDependencies": { diff --git a/packages/docusaurus-migrate/src/index.ts b/packages/docusaurus-migrate/src/index.ts index ec0615a580..2c162683e3 100644 --- a/packages/docusaurus-migrate/src/index.ts +++ b/packages/docusaurus-migrate/src/index.ts @@ -37,10 +37,10 @@ async function walk(dir: string): Promise { return results; } -function sanitizedFileContent( +async function sanitizedFileContent( content: string, migrateMDFiles: boolean, -): string { +): Promise { const extractedData = extractMetadata(content); const extractedMetaData = Object.entries(extractedData.metadata) .map( @@ -55,7 +55,7 @@ ${extractedMetaData} --- ${ migrateMDFiles - ? sanitizeMD(extractedData.rawContent) + ? await sanitizeMD(extractedData.rawContent) : extractedData.rawContent }`; return sanitizedData; @@ -427,7 +427,7 @@ async function migrateBlogFiles(context: MigrationContext) { const content = await fs.readFile(file, 'utf-8'); await fs.outputFile( file, - sanitizedFileContent(content, shouldMigrateMdFiles), + await sanitizedFileContent(content, shouldMigrateMdFiles), ); }), ); @@ -515,7 +515,7 @@ async function migrateVersionedDocs( const content = await fs.readFile(pathToFile, 'utf-8'); await fs.outputFile( pathToFile, - sanitizedFileContent( + await sanitizedFileContent( content.replace(versionRegex, ''), shouldMigrateMdFiles, ), @@ -695,7 +695,7 @@ async function migrateLatestDocs(context: MigrationContext) { const content = await fs.readFile(file, 'utf-8'); await fs.outputFile( file, - sanitizedFileContent(content, shouldMigrateMdFiles), + await sanitizedFileContent(content, shouldMigrateMdFiles), ); } }), @@ -752,7 +752,10 @@ export async function migrateMDToMDX( files.map(async (filePath) => { if (path.extname(filePath) === '.md') { const content = await fs.readFile(filePath, 'utf-8'); - await fs.outputFile(filePath, sanitizedFileContent(content, true)); + await fs.outputFile( + filePath, + await sanitizedFileContent(content, true), + ); } }), ); diff --git a/packages/docusaurus-migrate/src/sanitizeMD.ts b/packages/docusaurus-migrate/src/sanitizeMD.ts index 61e3904cb0..c04f1341e8 100644 --- a/packages/docusaurus-migrate/src/sanitizeMD.ts +++ b/packages/docusaurus-migrate/src/sanitizeMD.ts @@ -7,7 +7,6 @@ import markdown from 'remark-parse'; import toJsx from '@mapbox/hast-util-to-jsx'; -import unified from 'unified'; import parse from 'rehype-parse'; import visit from 'unist-util-visit'; import remarkStringify from 'remark-stringify'; @@ -21,7 +20,9 @@ const tags = htmlTags.reduce((acc: {[key: string]: boolean}, tag) => { return acc; }, {}); -export default function sanitizeMD(code: string): string { +export default async function sanitizeMD(code: string): Promise { + const {unified} = await import('unified'); + const markdownTree = unified().use(markdown).parse(code); visit(markdownTree, 'code', (node: Code) => { node.value = `\n\n`; @@ -30,7 +31,8 @@ export default function sanitizeMD(code: string): string { node.value = ``; }); - const markdownString = unified() + // @ts-expect-error: :/ + const markdownString: string = await unified() .use(remarkStringify, {fence: '`', fences: true}) .stringify(markdownTree); @@ -45,6 +47,7 @@ export default function sanitizeMD(code: string): string { delete (node as Partial).tagName; } }); + return toJsx(htmlTree) .replace(/\{\/\*|\*\/\}/g, '') .replace(/\{\/\*|\*\/\}/g, '') diff --git a/packages/docusaurus-plugin-content-blog/src/options.ts b/packages/docusaurus-plugin-content-blog/src/options.ts index 0ee9e50f8f..5d136d4399 100644 --- a/packages/docusaurus-plugin-content-blog/src/options.ts +++ b/packages/docusaurus-plugin-content-blog/src/options.ts @@ -26,7 +26,7 @@ export const DEFAULT_OPTIONS: PluginOptions = { beforeDefaultRehypePlugins: [], beforeDefaultRemarkPlugins: [], admonitions: true, - truncateMarker: //, + truncateMarker: /|\{\/\*\s*truncate\s*\*\/\}/, rehypePlugins: [], remarkPlugins: [], showReadingTime: true, 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 index a6d0b438bb..e97d5b3a03 100644 --- 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 @@ -1,65 +1,101 @@ // 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. -
-
-
; +"/*@jsxRuntime automatic @jsxImportSource react*/ +import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime"; +function _createMdxContent(props) { + const _components = Object.assign({ + p: "p", + sup: "sup", + a: "a", + section: "section", + h2: "h2", + ol: "ol", + li: "li" + }, props.components); + return _jsxs(_Fragment, { + children: [_jsxs(_components.p, { + children: ["foo", _jsx(_components.sup, { + children: _jsx(_components.a, { + href: "#user-content-fn-1-[HASH]", + id: "user-content-fnref-1-[HASH]", + "data-footnote-ref": true, + "aria-describedby": "footnote-label", + children: "1" + }) + })] + }), "/n", _jsxs(_components.p, { + children: ["bar", _jsx(_components.sup, { + children: _jsx(_components.a, { + href: "#user-content-fn-2-[HASH]", + id: "user-content-fnref-2-[HASH]", + "data-footnote-ref": true, + "aria-describedby": "footnote-label", + children: "2" + }) + })] + }), "/n", _jsxs(_components.p, { + children: ["baz", _jsx(_components.sup, { + children: _jsx(_components.a, { + href: "#user-content-fn-3-[HASH]", + id: "user-content-fnref-3-[HASH]", + "data-footnote-ref": true, + "aria-describedby": "footnote-label", + children: "3" + }) + })] + }), "/n", _jsxs(_components.section, { + "data-footnotes": true, + className: "footnotes", + children: [_jsx(_components.h2, { + className: "sr-only", + id: "footnote-label", + children: "Footnotes" + }), "/n", _jsxs(_components.ol, { + children: ["/n", _jsxs(_components.li, { + id: "user-content-fn-1-[HASH]", + children: ["/n", _jsxs(_components.p, { + children: ["foo ", _jsx(_components.a, { + href: "#user-content-fnref-1-[HASH]", + "data-footnote-backref": true, + className: "data-footnote-backref", + "aria-label": "Back to content", + children: "↩" + })] + }), "/n"] + }), "/n", _jsxs(_components.li, { + id: "user-content-fn-2-[HASH]", + children: ["/n", _jsxs(_components.p, { + children: ["foo ", _jsx(_components.a, { + href: "#user-content-fnref-2-[HASH]", + "data-footnote-backref": true, + className: "data-footnote-backref", + "aria-label": "Back to content", + children: "↩" + })] + }), "/n"] + }), "/n", _jsxs(_components.li, { + id: "user-content-fn-3-[HASH]", + children: ["/n", _jsxs(_components.p, { + children: ["foo ", _jsx(_components.a, { + href: "#user-content-fnref-3-[HASH]", + "data-footnote-backref": true, + className: "data-footnote-backref", + "aria-label": "Back to content", + children: "↩" + })] + }), "/n"] + }), "/n"] + }), "/n"] + })] + }); } -; -MDXContent.isMDXComponent = true;" +function MDXContent(props = {}) { + const {wrapper: MDXLayout} = props.components || ({}); + return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, { + children: _jsx(_createMdxContent, props) + })) : _createMdxContent(props); +} +export default MDXContent; +" `; 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 index 1c75704744..b8c6cdf8e0 100644 --- a/packages/docusaurus-plugin-content-blog/src/remark/__tests__/footnoteIDFixer.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/remark/__tests__/footnoteIDFixer.test.ts @@ -5,20 +5,24 @@ * LICENSE file in the root directory of this source tree. */ -import fs from 'fs-extra'; import path from 'path'; +import vfile from 'to-vfile'; + 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, 'utf8'), { - filepath, - remarkPlugins: [footnoteIDFixer], + const mdx = await import('@mdx-js/mdx'); + const {default: gfm} = await import('remark-gfm'); + + const filePath = path.join(__dirname, `__fixtures__/${name}.md`); + const file = await vfile.read(filePath); + + const result = await mdx.compile(file, { + remarkPlugins: [gfm, footnoteIDFixer], }); - return result.toString(); + return result.value; }; describe('footnoteIDFixer remark plugin', () => { diff --git a/packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts b/packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts index a3c317ba61..1986f8ed3d 100644 --- a/packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts +++ b/packages/docusaurus-plugin-content-blog/src/remark/footnoteIDFixer.ts @@ -7,6 +7,7 @@ import visit from 'unist-util-visit'; import {simpleHash} from '@docusaurus/utils'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; import type {FootnoteReference, FootnoteDefinition} from 'mdast'; diff --git a/packages/docusaurus-remark-plugin-npm2yarn/package.json b/packages/docusaurus-remark-plugin-npm2yarn/package.json index 004e4ccf51..5a525e5d86 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/package.json +++ b/packages/docusaurus-remark-plugin-npm2yarn/package.json @@ -17,14 +17,16 @@ }, "license": "MIT", "dependencies": { + "mdast-util-mdx": "^2.0.0", "npm-to-yarn": "^2.0.0", "tslib": "^2.5.0", + "unified": "^10.1.2", "unist-util-visit": "^2.0.3" }, "devDependencies": { "@types/mdast": "^3.0.10", - "remark": "^12.0.1", - "remark-mdx": "^1.6.21", + "remark": "^14.0.2", + "remark-mdx": "^2.1.5", "to-vfile": "^6.1.0" }, "engines": { diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/multiple.md b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/multiple.md new file mode 100644 index 0000000000..4649d8b471 --- /dev/null +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/multiple.md @@ -0,0 +1,21 @@ +# Title + +```bash npm2yarn + $ npm install --global docusaurus +``` + +
+ ```bash npm2yarn + npm install + ``` +
+ +```bash +echo "no npm2yarn here" +``` + +## Subtitle + +```bash npm2yarn +yarn add @docusaurus/core +``` diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap index 393470b312..d6e85e082b 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,67 +1,127 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`npm2yarn plugin does not re-import tabs components real-world multiple npm2yarn usage 1`] = ` +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +# Title + + + + \`\`\`bash + $ npm install --global docusaurus + \`\`\` + + + + \`\`\`bash + $ yarn global add docusaurus + \`\`\` + + + + \`\`\`bash + $ pnpm add --global docusaurus + \`\`\` + + + +
+ + + \`\`\`bash + npm install + \`\`\` + + + + \`\`\`bash + yarn install + \`\`\` + + + + \`\`\`bash + pnpm install + \`\`\` + + +
+ +\`\`\`bash +echo "no npm2yarn here" +\`\`\` + +## Subtitle + + + + \`\`\`bash + yarn add @docusaurus/core + \`\`\` + + + + \`\`\`bash + yarn add @docusaurus/core + \`\`\` + + + + \`\`\`bash + yarn add @docusaurus/core + \`\`\` + + +" +`; + exports[`npm2yarn plugin does not re-import tabs components when already imported above 1`] = ` "import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; + + \`\`\`bash + $ npm install --global docusaurus + \`\`\` + - - -\`\`\`bash - $ npm install --global docusaurus -\`\`\` - - - - - -\`\`\`bash - $ yarn global add docusaurus -\`\`\` - - - - - -\`\`\`bash - $ pnpm add --global docusaurus -\`\`\` - - + + \`\`\`bash + $ yarn global add docusaurus + \`\`\` + + + \`\`\`bash + $ pnpm add --global docusaurus + \`\`\` + " `; exports[`npm2yarn plugin does not re-import tabs components when already imported below 1`] = ` " + + \`\`\`bash + $ npm install --global docusaurus + \`\`\` + - - -\`\`\`bash - $ npm install --global docusaurus -\`\`\` - - - - - -\`\`\`bash - $ yarn global add docusaurus -\`\`\` - - - - - -\`\`\`bash - $ pnpm add --global docusaurus -\`\`\` - - + + \`\`\`bash + $ yarn global add docusaurus + \`\`\` + + + \`\`\`bash + $ pnpm add --global docusaurus + \`\`\` + import Tabs from '@theme/Tabs'; @@ -86,322 +146,278 @@ npm install --save docusaurus-plugin-name `; exports[`npm2yarn plugin work with custom converter 1`] = ` -"import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Installing a plugin A plugin is usually a npm package, so you install them like other npm packages using npm. + + \`\`\`bash + npm install --save docusaurus-plugin-name + \`\`\` + - - -\`\`\`bash -npm install --save docusaurus-plugin-name -\`\`\` - - - - - -\`\`\`bash -turbo install --save docusaurus-plugin-name -\`\`\` - - - + + \`\`\`bash + turbo install --save docusaurus-plugin-name + \`\`\` + " `; exports[`npm2yarn plugin work with pnpm converter 1`] = ` -"import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Installing a plugin A plugin is usually a npm package, so you install them like other npm packages using npm. + + \`\`\`bash + npm install --save docusaurus-plugin-name + \`\`\` + - - -\`\`\`bash -npm install --save docusaurus-plugin-name -\`\`\` - - - - - -\`\`\`bash -pnpm add docusaurus-plugin-name -\`\`\` - - - + + \`\`\`bash + pnpm add docusaurus-plugin-name + \`\`\` + " `; exports[`npm2yarn plugin work with yarn converter 1`] = ` -"import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Installing a plugin A plugin is usually a npm package, so you install them like other npm packages using npm. + + \`\`\`bash + npm install --save docusaurus-plugin-name + \`\`\` + - - -\`\`\`bash -npm install --save docusaurus-plugin-name -\`\`\` - - - - - -\`\`\`bash -yarn add docusaurus-plugin-name -\`\`\` - - - + + \`\`\`bash + yarn add docusaurus-plugin-name + \`\`\` + " `; exports[`npm2yarn plugin works on installation file 1`] = ` -"import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + + \`\`\`bash + $ npm install --global docusaurus + \`\`\` + - - -\`\`\`bash - $ npm install --global docusaurus -\`\`\` - - - - - -\`\`\`bash - $ yarn global add docusaurus -\`\`\` - - - - - -\`\`\`bash - $ pnpm add --global docusaurus -\`\`\` - - + + \`\`\`bash + $ yarn global add docusaurus + \`\`\` + + + \`\`\`bash + $ pnpm add --global docusaurus + \`\`\` + " `; exports[`npm2yarn plugin works on plugin file 1`] = ` -"import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Installing a plugin A plugin is usually a npm package, so you install them like other npm packages using npm. + + \`\`\`bash + npm install --save docusaurus-plugin-name + \`\`\` + - - -\`\`\`bash -npm install --save docusaurus-plugin-name -\`\`\` - - - - - -\`\`\`bash -yarn add docusaurus-plugin-name -\`\`\` - - - - - -\`\`\`bash -pnpm add docusaurus-plugin-name -\`\`\` - - + + \`\`\`bash + yarn add docusaurus-plugin-name + \`\`\` + + + \`\`\`bash + pnpm add docusaurus-plugin-name + \`\`\` + " `; exports[`npm2yarn plugin works with common commands 1`] = ` -"import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + + \`\`\`bash + npm run xxx -- --arg + \`\`\` + - - -\`\`\`bash -npm run xxx -- --arg -\`\`\` - - - - - -\`\`\`bash -yarn xxx --arg -\`\`\` - - - - - -\`\`\`bash -pnpm run xxx -- --arg -\`\`\` - - + + \`\`\`bash + yarn xxx --arg + \`\`\` + + + \`\`\`bash + pnpm run xxx -- --arg + \`\`\` + + + \`\`\`bash + npm install package + \`\`\` + - - -\`\`\`bash -npm install package -\`\`\` - - - - - -\`\`\`bash -yarn add package -\`\`\` - - - - - -\`\`\`bash -pnpm add package -\`\`\` - - + + \`\`\`bash + yarn add package + \`\`\` + + + \`\`\`bash + pnpm add package + \`\`\` + + + \`\`\`bash + npm remove package-name + \`\`\` + - - -\`\`\`bash -npm remove package-name -\`\`\` - - - - - -\`\`\`bash -yarn remove package-name -\`\`\` - - - - - -\`\`\`bash -pnpm remove package-name -\`\`\` - - + + \`\`\`bash + yarn remove package-name + \`\`\` + + + \`\`\`bash + pnpm remove package-name + \`\`\` + + + \`\`\`bash + npm init docusaurus + npm init docusaurus@latest my-website classic + \`\`\` + - + + \`\`\`bash + yarn create docusaurus + yarn create docusaurus@latest my-website classic + \`\`\` + -\`\`\`bash -npm init docusaurus -npm init docusaurus@latest my-website classic -\`\`\` + + \`\`\`bash + pnpm create docusaurus + pnpm create docusaurus@latest my-website classic + \`\`\` + + +" +`; - +exports[`npm2yarn plugin works with simplest md 1`] = ` +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' - +# Title -\`\`\`bash -yarn create docusaurus -yarn create docusaurus@latest my-website classic -\`\`\` +Hey - + + + \`\`\`bash + npm install test + \`\`\` + - - -\`\`\`bash -pnpm create docusaurus -pnpm create docusaurus@latest my-website classic -\`\`\` - - + + \`\`\`bash + yarn add test + \`\`\` + + + \`\`\`bash + pnpm add test + \`\`\` + " `; exports[`npm2yarn plugin works with sync option 1`] = ` -"import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +"import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Installing a plugin A plugin is usually a npm package, so you install them like other npm packages using npm. + + \`\`\`bash + npm install --save docusaurus-plugin-name + \`\`\` + - - -\`\`\`bash -npm install --save docusaurus-plugin-name -\`\`\` - - - - - -\`\`\`bash -yarn add docusaurus-plugin-name -\`\`\` - - - - - -\`\`\`bash -pnpm add docusaurus-plugin-name -\`\`\` - - + + \`\`\`bash + yarn add docusaurus-plugin-name + \`\`\` + + + \`\`\`bash + pnpm add docusaurus-plugin-name + \`\`\` + " `; diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts index 84afcc23ae..575365c8f2 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts @@ -7,22 +7,49 @@ import path from 'path'; import vfile from 'to-vfile'; -import mdx from 'remark-mdx'; -import remark from 'remark'; +import dedent from 'dedent'; import npm2yarn from '../index'; +const process = async ( + content: any, + options?: Parameters[0], +) => { + const {remark} = await import('remark'); + const {default: mdx} = await import('remark-mdx'); + + const result = await remark() + .use(mdx) + .use(npm2yarn, options) + .process(content); + + return result.value; +}; + const processFixture = async ( name: string, options?: Parameters[0], ) => { const filePath = path.join(__dirname, '__fixtures__', `${name}.md`); const file = await vfile.read(filePath); - const result = await remark().use(mdx).use(npm2yarn, options).process(file); - - return result.toString(); + return process(file, options); }; describe('npm2yarn plugin', () => { + it('works with simplest md', async () => { + const result = await process(dedent` + # Title + + Hey + + \`\`\`bash npm2yarn + npm install test + \`\`\` + + `); + + expect(result).toMatchSnapshot(); + }); + it('works on installation file', async () => { const result = await processFixture('installation'); @@ -65,6 +92,11 @@ describe('npm2yarn plugin', () => { expect(result).toMatchSnapshot(); }); + it('does not re-import tabs components real-world multiple npm2yarn usage', async () => { + const result = await processFixture('multiple'); + expect(result).toMatchSnapshot(); + }); + it('work with yarn converter', async () => { const result = await processFixture('plugin', {converters: ['yarn']}); diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts b/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts index ee562f491d..e98bcc9830 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts @@ -7,95 +7,186 @@ import visit from 'unist-util-visit'; import npmToYarn from 'npm-to-yarn'; -import type {Code, Content, Literal} from 'mdast'; -import type {Plugin} from 'unified'; +import type {Code, Literal} from 'mdast'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {MdxJsxFlowElement, MdxJsxAttribute} from 'mdast-util-mdx'; import type {Node, Parent} from 'unist'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {Transformer} from 'unified'; + +// TODO as of April 2023, no way to import/re-export this ESM type easily :/ +// This might change soon, likely after TS 5.2 +// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391 +// import type {Plugin} from 'unified'; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type Plugin = any; // TODO fix this asap + +type KnownConverter = 'yarn' | 'pnpm'; type CustomConverter = [name: string, cb: (npmCode: string) => string]; +type Converter = CustomConverter | KnownConverter; + type PluginOptions = { sync?: boolean; - converters?: (CustomConverter | 'yarn' | 'pnpm')[]; + converters?: Converter[]; }; -function createTabItem( - code: string, - node: Code, - value: string, - label?: string, -) { - return [ - { - type: 'jsx', - value: ``, - }, - { - type: node.type, - lang: node.lang, - value: code, - }, - { - type: 'jsx', - value: '', - }, - ] as Content[]; +function createAttribute( + attributeName: string, + attributeValue: MdxJsxAttribute['value'], +): MdxJsxAttribute { + return { + type: 'mdxJsxAttribute', + name: attributeName, + value: attributeValue, + }; +} + +function createTabItem({ + code, + node, + value, + label, +}: { + code: string; + node: Code; + value: string; + label?: string; +}): MdxJsxFlowElement { + return { + type: 'mdxJsxFlowElement', + name: 'TabItem', + attributes: [ + createAttribute('value', value), + label && createAttribute('label', label), + ].filter((attr): attr is MdxJsxAttribute => Boolean(attr)), + children: [ + { + type: node.type, + lang: node.lang, + value: code, + }, + ], + }; } const transformNode = ( node: Code, isSync: boolean, - converters: (CustomConverter | 'yarn' | 'pnpm')[], + converters: Converter[], ) => { - const groupIdProp = isSync ? ' groupId="npm2yarn"' : ''; + const groupIdProp = isSync + ? { + type: 'mdxJsxAttribute', + name: 'groupId', + value: 'npm2yarn', + } + : undefined; const npmCode = node.value; + + function createConvertedTabItem(converter: Converter) { + if (typeof converter === 'string') { + return createTabItem({ + code: npmToYarn(npmCode, converter), + node, + value: converter, + label: converter === 'yarn' ? 'Yarn' : converter, + }); + } + const [converterName, converterFn] = converter; + return createTabItem({ + code: converterFn(npmCode), + node, + value: converterName, + }); + } + return [ { - type: 'jsx', - value: ``, + type: 'mdxJsxFlowElement', + name: 'Tabs', + attributes: [groupIdProp].filter(Boolean), + children: [ + createTabItem({code: npmCode, node, value: 'npm'}), + ...converters.flatMap(createConvertedTabItem), + ], }, - ...createTabItem(npmCode, node, 'npm'), - ...converters.flatMap((converter) => - typeof converter === 'string' - ? createTabItem( - npmToYarn(npmCode, converter), - node, - converter, - converter === 'yarn' ? 'Yarn' : converter, - ) - : createTabItem(converter[1](npmCode), node, converter[0]), - ), - { - type: 'jsx', - value: '', - }, - ] as Content[]; + ] as any[]; }; -const isImport = (node: Node): node is Literal => node.type === 'import'; +const isMdxEsmLiteral = (node: Node): node is Literal => + node.type === 'mdxjsEsm'; +// TODO legacy approximation, good-enough for now but not 100% accurate +const isTabsImport = (node: Node): boolean => + isMdxEsmLiteral(node) && node.value.includes('@theme/Tabs'); + const isParent = (node: Node): node is Parent => Array.isArray((node as Parent).children); -const matchNode = (node: Node): node is Code => +const isNpm2Yarn = (node: Node): node is Code => node.type === 'code' && (node as Code).meta === 'npm2yarn'; -const nodeForImport: Literal = { - type: 'import', - value: - "import Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';", -}; -const plugin: Plugin<[PluginOptions?]> = (options = {}) => { +function createImportNode() { + return { + type: 'mdxjsEsm', + value: + "import Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'", + data: { + estree: { + type: 'Program', + body: [ + { + type: 'ImportDeclaration', + specifiers: [ + { + type: 'ImportDefaultSpecifier', + local: {type: 'Identifier', name: 'Tabs'}, + }, + ], + source: { + type: 'Literal', + value: '@theme/Tabs', + raw: "'@theme/Tabs'", + }, + }, + { + type: 'ImportDeclaration', + specifiers: [ + { + type: 'ImportDefaultSpecifier', + local: {type: 'Identifier', name: 'TabItem'}, + }, + ], + source: { + type: 'Literal', + value: '@theme/TabItem', + raw: "'@theme/TabItem'", + }, + }, + ], + sourceType: 'module', + }, + }, + }; +} + +const plugin: Plugin<[PluginOptions?]> = (options = {}): Transformer => { + // @ts-expect-error: todo temporary const {sync = false, converters = ['yarn', 'pnpm']} = options; return (root) => { - let transformed = false as boolean; - let alreadyImported = false as boolean; + let transformed = false; + let alreadyImported = false; + visit(root, (node: Node) => { - if (isImport(node) && node.value.includes('@theme/Tabs')) { + if (isTabsImport(node)) { alreadyImported = true; } + if (isParent(node)) { let index = 0; while (index < node.children.length) { const child = node.children[index]!; - if (matchNode(child)) { + if (isNpm2Yarn(child)) { const result = transformNode(child, sync, converters); node.children.splice(index, 1, ...result); index += result.length; @@ -106,8 +197,9 @@ const plugin: Plugin<[PluginOptions?]> = (options = {}) => { } } }); + if (transformed && !alreadyImported) { - (root as Parent).children.unshift(nodeForImport); + (root as Parent).children.unshift(createImportNode()); } }; }; diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index da03a71be2..92dc35b541 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -32,7 +32,7 @@ "@docusaurus/utils": "^3.0.0-alpha.0", "@docusaurus/utils-common": "^3.0.0-alpha.0", "@docusaurus/utils-validation": "^3.0.0-alpha.0", - "@mdx-js/react": "^1.6.22", + "@mdx-js/react": "^2.1.5", "clsx": "^1.2.1", "copy-text-to-clipboard": "^3.0.1", "infima": "0.2.0-alpha.43", diff --git a/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts b/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts index 010967c003..c37f92ba31 100644 --- a/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts +++ b/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts @@ -312,14 +312,6 @@ export default function getSwizzleConfig(): SwizzleConfig { }, description: 'The component used to render
tags in MDX', }, - 'MDXComponents/Head': { - actions: { - eject: 'forbidden', - wrap: 'forbidden', - }, - description: - 'Technical component used to assign metadata (generally for SEO purpose) to the current MDX document', - }, 'MDXComponents/Heading': { actions: { eject: 'safe', diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index f010df9a85..0cbee0f5da 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -861,14 +861,6 @@ declare module '@theme/MDXComponents/Img' { export default function MDXImg(props: Props): JSX.Element; } -declare module '@theme/MDXComponents/Head' { - import type {ComponentProps} from 'react'; - - export interface Props extends ComponentProps<'head'> {} - - export default function MDXHead(props: Props): JSX.Element; -} - declare module '@theme/MDXComponents/Heading' { import type {ComponentProps} from 'react'; import type Heading from '@theme/Heading'; @@ -889,7 +881,6 @@ declare module '@theme/MDXComponents/Pre' { declare module '@theme/MDXComponents' { import type {ComponentType, ComponentProps} from 'react'; - import type MDXHead from '@theme/MDXComponents/Head'; import type MDXCode from '@theme/MDXComponents/Code'; import type MDXA from '@theme/MDXComponents/A'; import type MDXPre from '@theme/MDXComponents/Pre'; @@ -898,13 +889,14 @@ declare module '@theme/MDXComponents' { import type MDXImg from '@theme/MDXComponents/Img'; import type Admonition from '@theme/Admonition'; import type Mermaid from '@theme/Mermaid'; + import type Head from '@docusaurus/Head'; export type MDXComponentsObject = { - readonly head: typeof MDXHead; + readonly Head: typeof Head; + readonly Details: typeof MDXDetails; readonly code: typeof MDXCode; readonly a: typeof MDXA; readonly pre: typeof MDXPre; - readonly details: typeof MDXDetails; readonly ul: typeof MDXUl; readonly img: typeof MDXImg; readonly h1: (props: ComponentProps<'h1'>) => JSX.Element; diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx index 6bf8f730eb..97e1ac4d8d 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx @@ -6,50 +6,13 @@ */ import type {ComponentProps} from 'react'; -import React, {isValidElement} from 'react'; +import React from 'react'; import CodeBlock from '@theme/CodeBlock'; import type {Props} from '@theme/MDXComponents/Code'; export default function MDXCode(props: Props): JSX.Element { - const inlineElements: (string | undefined)[] = [ - 'a', - 'abbr', - 'b', - 'br', - 'button', - 'cite', - 'code', - 'del', - 'dfn', - 'em', - 'i', - 'img', - 'input', - 'ins', - 'kbd', - 'label', - 'object', - 'output', - 'q', - 'ruby', - 's', - 'small', - 'span', - 'strong', - 'sub', - 'sup', - 'time', - 'u', - 'var', - 'wbr', - ]; const shouldBeInline = React.Children.toArray(props.children).every( - (el) => - (typeof el === 'string' && !el.includes('\n')) || - (isValidElement(el) && - inlineElements.includes( - (el.props as {mdxType: string} | null)?.mdxType, - )), + (el) => typeof el === 'string' && !el.includes('\n'), ); return shouldBeInline ? ( diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx index 08ddaf1a1f..9b90d4cafb 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx @@ -15,8 +15,7 @@ export default function MDXDetails(props: Props): JSX.Element { // Details theme component const summary = items.find( (item): item is ReactElement> => - React.isValidElement(item) && - (item.props as {mdxType: string} | null)?.mdxType === 'summary', + React.isValidElement(item) && item.type === 'summary', ); const children = <>{items.filter((item) => item !== summary)}; diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx deleted file mode 100644 index 765ce58403..0000000000 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/** - * 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 React, {type ReactElement} from 'react'; -import Head, {type Props as HeadProps} from '@docusaurus/Head'; -import type {Props} from '@theme/MDXComponents/Head'; - -type MDXElement = ReactElement< - {mdxType?: string; originalType?: string} | undefined ->; - -// MDX elements are wrapped through the MDX pragma. In some cases (notably usage -// with Head/Helmet) we need to unwrap those elements. -function unwrapMDXElement(element: MDXElement) { - if (element.props?.mdxType && element.props.originalType) { - const {mdxType, originalType, ...newProps} = element.props; - return React.createElement(element.props.originalType, newProps); - } - return element; -} - -export default function MDXHead(props: Props): JSX.Element { - const unwrappedChildren = React.Children.map(props.children, (child) => - React.isValidElement(child) ? unwrapMDXElement(child as MDXElement) : child, - ); - return {unwrappedChildren}; -} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx index cde1899da8..69957ea29f 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx @@ -5,19 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import React, {isValidElement} from 'react'; -import CodeBlock from '@theme/CodeBlock'; +import React, {type ReactNode} from 'react'; import type {Props} from '@theme/MDXComponents/Pre'; -export default function MDXPre(props: Props): JSX.Element { - return ( - - ); +export default function MDXPre(props: Props): ReactNode | undefined { + // With MDX 2, this element is only used for fenced code blocks + // It always receives a MDXComponents/Code as children + return <>{props.children}; } diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx index 1393195195..777ddb708b 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import MDXHead from '@theme/MDXComponents/Head'; +import Head from '@docusaurus/Head'; import MDXCode from '@theme/MDXComponents/Code'; import MDXA from '@theme/MDXComponents/A'; import MDXPre from '@theme/MDXComponents/Pre'; @@ -20,11 +20,11 @@ import Mermaid from '@theme/Mermaid'; import type {MDXComponentsObject} from '@theme/MDXComponents'; const MDXComponents: MDXComponentsObject = { - head: MDXHead, + Head, + Details: MDXDetails, code: MDXCode, a: MDXA, pre: MDXPre, - details: MDXDetails, ul: MDXUl, img: MDXImg, h1: (props) => , diff --git a/packages/docusaurus-theme-classic/src/theme/MDXContent/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXContent/index.tsx index ad70107193..55c530c927 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXContent/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXContent/index.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import {MDXProvider} from '@mdx-js/react'; import MDXComponents from '@theme/MDXComponents'; import type {Props} from '@theme/MDXContent'; diff --git a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx index 7ccb52c9dc..d3d6166dc1 100644 --- a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx @@ -10,6 +10,7 @@ import clsx from 'clsx'; import { useScrollPositionBlocker, useTabs, + sanitizeTabsChildren, type TabItemProps, } from '@docusaurus/theme-common/internal'; import useIsBrowser from '@docusaurus/useIsBrowser'; @@ -152,7 +153,8 @@ export default function Tabs(props: Props): JSX.Element { // Remount tabs after hydration // Temporary fix for https://github.com/facebook/docusaurus/issues/5653 key={String(isBrowser)} - {...props} - /> + {...props}> + {sanitizeTabsChildren(props.children)} + ); } diff --git a/packages/docusaurus-theme-common/src/components/Details/styles.module.css b/packages/docusaurus-theme-common/src/components/Details/styles.module.css index b5c1400cec..11863a0f3d 100644 --- a/packages/docusaurus-theme-common/src/components/Details/styles.module.css +++ b/packages/docusaurus-theme-common/src/components/Details/styles.module.css @@ -57,6 +57,10 @@ CSS variables, meant to be overridden by final theme padding-top: 1rem; } -.collapsibleContent > *:last-child { +.collapsibleContent p:last-child { + margin-bottom: 0; +} + +.details > summary > p:last-child { margin-bottom: 0; } diff --git a/packages/docusaurus-theme-common/src/internal.ts b/packages/docusaurus-theme-common/src/internal.ts index 1814712856..dc42172ced 100644 --- a/packages/docusaurus-theme-common/src/internal.ts +++ b/packages/docusaurus-theme-common/src/internal.ts @@ -42,7 +42,7 @@ export { useAnnouncementBar, } from './contexts/announcementBar'; -export {useTabs} from './utils/tabsUtils'; +export {useTabs, sanitizeTabsChildren} from './utils/tabsUtils'; export type {TabValue, TabsProps, TabItemProps} from './utils/tabsUtils'; export {useNavbarMobileSidebar} from './contexts/navbarMobileSidebar'; diff --git a/packages/docusaurus-theme-common/src/utils/admonitionUtils.tsx b/packages/docusaurus-theme-common/src/utils/admonitionUtils.tsx index b960d3883a..f9a979deaa 100644 --- a/packages/docusaurus-theme-common/src/utils/admonitionUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/admonitionUtils.tsx @@ -14,15 +14,16 @@ function extractMDXAdmonitionTitle(children: ReactNode): { rest: ReactNode; } { const items = React.Children.toArray(children); - const mdxAdmonitionTitle = items.find( - (item) => - React.isValidElement(item) && - (item.props as {mdxType: string} | null)?.mdxType === - 'mdxAdmonitionTitle', + const mdxAdmonitionTitleWrapper = items.find( + (item) => React.isValidElement(item) && item.type === 'mdxAdmonitionTitle', ) as JSX.Element | undefined; - const rest = items.filter((item) => item !== mdxAdmonitionTitle); + + const rest = items.filter((item) => item !== mdxAdmonitionTitleWrapper); + + const mdxAdmonitionTitle = mdxAdmonitionTitleWrapper?.props.children; + return { - mdxAdmonitionTitle: mdxAdmonitionTitle?.props.children, + mdxAdmonitionTitle, rest: rest.length > 0 ? <>{rest} : null, }; } diff --git a/packages/docusaurus-theme-common/src/utils/tabsUtils.tsx b/packages/docusaurus-theme-common/src/utils/tabsUtils.tsx index 5b974b8af5..42ad4fe4d0 100644 --- a/packages/docusaurus-theme-common/src/utils/tabsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/tabsUtils.tsx @@ -61,25 +61,27 @@ function isTabItem( return !!props && typeof props === 'object' && 'value' in props; } -function ensureValidChildren(children: TabsProps['children']) { - return (React.Children.map(children, (child) => { - // Pass falsy values through: allow conditionally not rendering a tab - if (!child || (isValidElement(child) && isTabItem(child))) { - return child; - } - // child.type.name will give non-sensical values in prod because of - // minification, but we assume it won't throw in prod. - throw new Error( - `Docusaurus error: Bad child <${ - // @ts-expect-error: guarding against unexpected cases - typeof child.type === 'string' ? child.type : child.type.name - }>: all children of the component should be , and every should have a unique "value" prop.`, - ); - })?.filter(Boolean) ?? []) as ReactElement[]; +export function sanitizeTabsChildren(children: TabsProps['children']) { + return (React.Children.toArray(children) + .filter((child) => child !== '\n') + .map((child) => { + if (!child || (isValidElement(child) && isTabItem(child))) { + return child; + } + // child.type.name will give non-sensical values in prod because of + // minification, but we assume it won't throw in prod. + throw new Error( + `Docusaurus error: Bad child <${ + // @ts-expect-error: guarding against unexpected cases + typeof child.type === 'string' ? child.type : child.type.name + }>: all children of the component should be , and every should have a unique "value" prop.`, + ); + }) + ?.filter(Boolean) ?? []) as ReactElement[]; } function extractChildrenTabValues(children: TabsProps['children']): TabValue[] { - return ensureValidChildren(children).map( + return sanitizeTabsChildren(children).map( ({props: {value, label, attributes, default: isDefault}}) => ({ value, label, diff --git a/packages/docusaurus-theme-mermaid/package.json b/packages/docusaurus-theme-mermaid/package.json index 8d6b2d8ccd..53aa3a76e9 100644 --- a/packages/docusaurus-theme-mermaid/package.json +++ b/packages/docusaurus-theme-mermaid/package.json @@ -38,7 +38,6 @@ "@docusaurus/theme-common": "^3.0.0-alpha.0", "@docusaurus/types": "^3.0.0-alpha.0", "@docusaurus/utils-validation": "^3.0.0-alpha.0", - "@mdx-js/react": "^1.6.22", "mermaid": "^9.4.3", "tslib": "^2.5.0" }, diff --git a/packages/docusaurus-types/src/config.d.ts b/packages/docusaurus-types/src/config.d.ts index fa8fe1a190..6c7e16f100 100644 --- a/packages/docusaurus-types/src/config.d.ts +++ b/packages/docusaurus-types/src/config.d.ts @@ -27,7 +27,25 @@ export type MarkdownConfig = { * @see https://docusaurus.io/docs/markdown-features/diagrams/ * @default false */ - mermaid?: boolean; + mermaid: boolean; + + /** + * Gives opportunity to preprocess the MDX string content before compiling. + * A good escape hatch that can be used to handle edge cases. + * + * @param args + */ + preprocessor?: (args: {filePath: string; fileContent: string}) => string; + + /** + * Set of flags make it easier to upgrade from MDX 1 to MDX 2 + * See also https://github.com/facebook/docusaurus/issues/4029 + */ + mdx1Compat: { + comments: boolean; + admonitions: boolean; + headingIds: boolean; + }; }; /** diff --git a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap index c0d9d3dd2a..b1f8cc75ee 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap +++ b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap @@ -2,27 +2,19 @@ exports[`validation schemas admonitionsSchema: for value=[] 1`] = `""value" does not look like a valid admonitions config"`; -exports[`validation schemas admonitionsSchema: for value={"customTypes":{"myKeyword":{"keyword":"myKeyword","infima":true,"svg":""}}} 1`] = ` -"The Docusaurus admonitions system has changed, and the option "customTypes" does not exist anymore. -You now need to swizzle the admonitions component to provide UI customizations such as icons. -Please refer to https://github.com/facebook/docusaurus/pull/7152 for detailed upgrade instructions." -`; +exports[`validation schemas admonitionsSchema: for value={"customTypes":{"myKeyword":{"keyword":"myKeyword","infima":true,"svg":""}}} 1`] = `""customTypes" is not allowed"`; -exports[`validation schemas admonitionsSchema: for value={"icons":"emoji"} 1`] = ` -"The Docusaurus admonitions system has changed, and the option "icons" does not exist anymore. -You now need to swizzle the admonitions component to provide UI customizations such as icons. -Please refer to https://github.com/facebook/docusaurus/pull/7152 for detailed upgrade instructions." -`; +exports[`validation schemas admonitionsSchema: for value={"icons":"emoji"} 1`] = `""icons" is not allowed"`; -exports[`validation schemas admonitionsSchema: for value={"infima":true} 1`] = ` -"The Docusaurus admonitions system has changed, and the option "infima" does not exist anymore. -You now need to swizzle the admonitions component to provide UI customizations such as icons. -Please refer to https://github.com/facebook/docusaurus/pull/7152 for detailed upgrade instructions." -`; +exports[`validation schemas admonitionsSchema: for value={"infima":true} 1`] = `""infima" is not allowed"`; exports[`validation schemas admonitionsSchema: for value={"keywords":["custom-keyword"],"extendDefaults":42} 1`] = `""extendDefaults" must be a boolean"`; -exports[`validation schemas admonitionsSchema: for value={"tag":""} 1`] = `""tag" is not allowed to be empty"`; +exports[`validation schemas admonitionsSchema: for value={"tag":""} 1`] = `"It is not possible anymore to use a custom admonition tag. The only admonition tag supported is ':::' (Markdown Directive syntax)"`; + +exports[`validation schemas admonitionsSchema: for value={"tag":"+++","keywords":["info","tip"]} 1`] = `"It is not possible anymore to use a custom admonition tag. The only admonition tag supported is ':::' (Markdown Directive syntax)"`; + +exports[`validation schemas admonitionsSchema: for value={"tag":"+++"} 1`] = `"It is not possible anymore to use a custom admonition tag. The only admonition tag supported is ':::' (Markdown Directive syntax)"`; exports[`validation schemas admonitionsSchema: for value={"unknownAttribute":"val"} 1`] = `""unknownAttribute" is not allowed"`; diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts index 7028560736..0769edfd07 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts @@ -97,22 +97,22 @@ describe('validation schemas', () => { testOK(true); testOK(false); testOK({}); - testOK({tag: '+++'}); testOK({keywords: ['info', 'tip']}); testOK({keywords: ['info', 'tip'], extendDefaults: true}); testOK({keywords: ['info', 'tip'], extendDefaults: false}); testOK({keywords: []}); testOK({keywords: [], extendDefaults: true}); // noop testOK({keywords: [], extendDefaults: false}); // disable admonitions - testOK({tag: '+++', keywords: ['info', 'tip']}); - testOK({tag: '+++', keywords: ['custom-keyword'], extendDefaults: true}); - testOK({tag: '+++', keywords: ['custom-keyword'], extendDefaults: false}); + testOK({keywords: ['custom-keyword'], extendDefaults: true}); + testOK({keywords: ['custom-keyword'], extendDefaults: false}); testFail(3); testFail([]); testFail({unknownAttribute: 'val'}); testFail({tag: ''}); testFail({keywords: ['custom-keyword'], extendDefaults: 42}); + testFail({tag: '+++'}); + testFail({tag: '+++', keywords: ['info', 'tip']}); // Legacy types testFail({ diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index 0044855aee..5d2959359c 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -37,17 +37,10 @@ const MarkdownPluginsSchema = Joi.array() export const RemarkPluginsSchema = MarkdownPluginsSchema; export const RehypePluginsSchema = MarkdownPluginsSchema; -const LegacyAdmonitionConfigSchema = Joi.forbidden().messages({ - 'any.unknown': `The Docusaurus admonitions system has changed, and the option {#label} does not exist anymore. -You now need to swizzle the admonitions component to provide UI customizations such as icons. -Please refer to https://github.com/facebook/docusaurus/pull/7152 for detailed upgrade instructions.`, -}); - export const AdmonitionsSchema = JoiFrontMatter.alternatives() .try( JoiFrontMatter.boolean().required(), JoiFrontMatter.object({ - tag: JoiFrontMatter.string(), keywords: JoiFrontMatter.array().items( JoiFrontMatter.string(), // Apparently this is how we tell job to accept empty arrays... @@ -55,10 +48,10 @@ export const AdmonitionsSchema = JoiFrontMatter.alternatives() ), extendDefaults: JoiFrontMatter.boolean(), - // TODO Remove before 2023 - customTypes: LegacyAdmonitionConfigSchema, - icons: LegacyAdmonitionConfigSchema, - infima: LegacyAdmonitionConfigSchema, + // TODO Remove before 2024 + tag: Joi.any().forbidden().messages({ + 'any.unknown': `It is not possible anymore to use a custom admonition tag. The only admonition tag supported is ':::' (Markdown Directive syntax)`, + }), }).required(), ) .default(true) diff --git a/packages/docusaurus-utils-validation/src/validationUtils.ts b/packages/docusaurus-utils-validation/src/validationUtils.ts index 5d87c1a5e8..6b3a891571 100644 --- a/packages/docusaurus-utils-validation/src/validationUtils.ts +++ b/packages/docusaurus-utils-validation/src/validationUtils.ts @@ -8,6 +8,7 @@ import logger from '@docusaurus/logger'; import Yaml from 'js-yaml'; import {PluginIdSchema} from './validationSchemas'; +import type {ValidationOptions} from 'joi'; import type Joi from './Joi'; /** Print warnings returned from Joi validation. */ @@ -77,13 +78,15 @@ export function normalizeThemeConfig( * Validate front matter with better error message */ export function validateFrontMatter( - frontMatter: {[key: string]: unknown}, + frontMatter: unknown, schema: Joi.ObjectSchema, + options?: ValidationOptions, ): T { const {value, error, warning} = schema.validate(frontMatter, { convert: true, allowUnknown: true, abortEarly: false, + ...options, }); printWarning(warning); diff --git a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts index 014709f4df..9a1ecbee32 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts @@ -12,6 +12,9 @@ import { parseMarkdownString, parseMarkdownHeadingId, writeMarkdownHeadingId, + escapeMarkdownHeadingIds, + unwrapMdxCodeBlocks, + admonitionTitleToDirectiveLabel, } from '../markdownUtils'; describe('createExcerpt', () => { @@ -916,6 +919,556 @@ describe('parseMarkdownHeadingId', () => { }); }); +describe('escapeMarkdownHeadingIds', () => { + it('can escape simple heading id', () => { + expect(escapeMarkdownHeadingIds('# title 1 {#id-1}')).toBe( + '# title 1 \\{#id-1}', + ); + expect(escapeMarkdownHeadingIds('# title 1 {#id-1}')).toBe( + '# title 1 \\{#id-1}', + ); + expect(escapeMarkdownHeadingIds('# title 1{#id-1}')).toBe( + '# title 1\\{#id-1}', + ); + expect(escapeMarkdownHeadingIds('# title 1 \\{#id-1}')).toBe( + '# title 1 \\{#id-1}', + ); + expect(escapeMarkdownHeadingIds('# title 1\\{#id-1}')).toBe( + '# title 1\\{#id-1}', + ); + }); + + it('can escape level 1-6 heading ids', () => { + expect( + escapeMarkdownHeadingIds(dedent` + # title 1 {#id-1} + + ## title 2 {#id-2} + + ### title 3 {#id-3} + + #### title 4 {#id-4} + + ##### title 5 {#id-5} + + ###### title 6 {#id-6} + `), + ).toEqual(dedent` + # title 1 \{#id-1} + + ## title 2 \{#id-2} + + ### title 3 \{#id-3} + + #### title 4 \{#id-4} + + ##### title 5 \{#id-5} + + ###### title 6 \{#id-6} + `); + }); + + it('does not escape level 7 heading id', () => { + expect( + escapeMarkdownHeadingIds(dedent` + ####### title 7 {#id-7} + `), + ).toEqual(dedent` + ####### title 7 {#id-7} + `); + }); + + it('does not escape non-heading', () => { + expect( + escapeMarkdownHeadingIds(dedent` + some text {#non-id} + `), + ).toEqual(dedent` + some text {#non-id} + `); + }); + + it('works for realistic example', () => { + expect( + escapeMarkdownHeadingIds(dedent` + # Support + + Docusaurus has a community of thousands of developers. + + On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials. + + Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within. + + ## Stack Overflow {#stack-overflow} + + Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)! + + ## Discussion forums \{#discussion-forums} + + There are many online forums for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit. + + - [Docusaurus online chat](https://discord.gg/docusaurus) + - [#help-and-questions](https://discord.gg/fwbcrQ3dHR) for user help + - [#contributors](https://discord.gg/6g6ASPA) for contributing help + - [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/) + + ## Feature requests {#feature-requests} + + For new feature requests, you can create a post on our [feature requests board (Canny)](/feature-requests), which is a handy tool for road-mapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first! + + ## News {#news} + + For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website. + `), + ).toEqual(dedent` + # Support + + Docusaurus has a community of thousands of developers. + + On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials. + + Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within. + + ## Stack Overflow \{#stack-overflow} + + Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)! + + ## Discussion forums \{#discussion-forums} + + There are many online forums for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit. + + - [Docusaurus online chat](https://discord.gg/docusaurus) + - [#help-and-questions](https://discord.gg/fwbcrQ3dHR) for user help + - [#contributors](https://discord.gg/6g6ASPA) for contributing help + - [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/) + + ## Feature requests \{#feature-requests} + + For new feature requests, you can create a post on our [feature requests board (Canny)](/feature-requests), which is a handy tool for road-mapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first! + + ## News \{#news} + + For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website. + `); + }); +}); + +describe('unwrapMdxCodeBlocks', () => { + it('can unwrap a simple mdx code block', () => { + expect( + unwrapMdxCodeBlocks(dedent` + # Title + + \`\`\`mdx-code-block + import Comp, {User} from "@site/components/comp" + + + + + + export const age = 36 + \`\`\` + + text + `), + ).toEqual(dedent` + # Title + + import Comp, {User} from "@site/components/comp" + + + + + + export const age = 36 + + text + `); + }); + + it('can unwrap a nested mdx code block', () => { + expect( + unwrapMdxCodeBlocks(dedent` + # Title + + \`\`\`\`mdx-code-block + + some content + + \`\`\`js + export const age = 36 + \`\`\` + + \`\`\`\` + + text + `), + ).toEqual(dedent` + # Title + + + some content + + \`\`\`js + export const age = 36 + \`\`\` + + + text + `); + }); + + it('works for realistic example', () => { + expect( + unwrapMdxCodeBlocks(dedent` + # Canary releases + + \`\`\`mdx-code-block + import { + VersionsProvider, + } from "@site/src/components/Versions"; + + + \`\`\` + + Docusaurus has a canary releases system. + + It permits you to **test new unreleased features** as soon as the pull requests are merged on the [next version](./5-release-process.md#next-version) of Docusaurus. + + It is a good way to **give feedback to maintainers**, ensuring the newly implemented feature works as intended. + + :::note + + Using a canary release in production might seem risky, but in practice, it's not. + + A canary release passes all automated tests and is used in production by the Docusaurus site itself. + + \`\`\`mdx-code-block + + \`\`\` + `), + ).toEqual(dedent` + # Canary releases + + import { + VersionsProvider, + } from "@site/src/components/Versions"; + + + + Docusaurus has a canary releases system. + + It permits you to **test new unreleased features** as soon as the pull requests are merged on the [next version](./5-release-process.md#next-version) of Docusaurus. + + It is a good way to **give feedback to maintainers**, ensuring the newly implemented feature works as intended. + + :::note + + Using a canary release in production might seem risky, but in practice, it's not. + + A canary release passes all automated tests and is used in production by the Docusaurus site itself. + + + `); + }); +}); + +describe('admonitionTitleToDirectiveLabel', () => { + const directives = ['info', 'note', 'tip', 'caution']; + + it('does not transform markdown without any admonition', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + # Title + + intro + + ## Sub Title + + content + `, + directives, + ), + ).toEqual(dedent` + # Title + + intro + + ## Sub Title + + content + `); + }); + + it('transform simple admonition', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + before + + :::note Title + + content + + ::: + + after + `, + directives, + ), + ).toEqual(dedent` + before + + :::note[Title] + + content + + ::: + + after + `); + }); + + it('does not transform already transformed admonition', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + before + + :::note[Title] + + content + + ::: + + after + `, + directives, + ), + ).toEqual(dedent` + before + + :::note[Title] + + content + + ::: + + after + `); + }); + + it('does not transform non-container directives', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + before + + ::note Title + + content + + ::: + + after + `, + directives, + ), + ).toEqual(dedent` + before + + ::note Title + + content + + ::: + + after + `); + }); + + it('does not transform left-padded directives', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + before + + :::note Title + + content + + ::: + + after + `, + directives, + ), + ).toEqual(dedent` + before + + :::note Title + + content + + ::: + + after + `); + }); + + it('does not transform admonition without title', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + before + + :::note + + content + + ::: + + after + `, + directives, + ), + ).toEqual(dedent` + before + + :::note + + content + + ::: + + after + `); + }); + + it('does not transform non-admonition directive', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + before + + :::whatever Title + + content + + ::: + + after + `, + directives, + ), + ).toEqual(dedent` + before + + :::whatever Title + + content + + ::: + + after + `); + }); + + it('transform real-world nested messy admonitions', () => { + expect( + admonitionTitleToDirectiveLabel( + dedent` + --- + title: "contains :::note" + --- + + # Title + + intro + + ::::note note **title** + + note content + + ::::tip tip title + + tip content + + :::whatever whatever title + + whatever content + + ::: + + :::: + + ::::: + + ## Heading {#my-heading} + + ::::info weird spaced title + + into content + + :::tip[tip directiveLabel] + + tip content + + :::: + + ## Conclusion + + end + `, + directives, + ), + ).toEqual(dedent` + --- + title: "contains :::note" + --- + + # Title + + intro + + ::::note[note **title**] + + note content + + ::::tip[tip title] + + tip content + + :::whatever whatever title + + whatever content + + ::: + + :::: + + ::::: + + ## Heading {#my-heading} + + ::::info[weird spaced title] + + into content + + :::tip[tip directiveLabel] + + tip content + + :::: + + ## Conclusion + + end + `); + }); +}); + describe('writeMarkdownHeadingId', () => { it('works for simple level-2 heading', () => { expect(writeMarkdownHeadingId('## ABC')).toBe('## ABC {#abc}'); diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 2d9349d48c..fbfe062952 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -66,6 +66,9 @@ export { } from './tags'; export { parseMarkdownHeadingId, + escapeMarkdownHeadingIds, + unwrapMdxCodeBlocks, + admonitionTitleToDirectiveLabel, createExcerpt, parseFrontMatter, parseMarkdownContentTitle, diff --git a/packages/docusaurus-utils/src/markdownUtils.ts b/packages/docusaurus-utils/src/markdownUtils.ts index f80c4e9052..dc8589ac71 100644 --- a/packages/docusaurus-utils/src/markdownUtils.ts +++ b/packages/docusaurus-utils/src/markdownUtils.ts @@ -39,6 +39,75 @@ export function parseMarkdownHeadingId(heading: string): { return {text: heading, id: undefined}; } +/** + * MDX 2 requires escaping { with a \ so our anchor syntax need that now. + * See https://mdxjs.com/docs/troubleshooting-mdx/#could-not-parse-expression-with-acorn-error + */ +export function escapeMarkdownHeadingIds(content: string): string { + const markdownHeadingRegexp = /(?:^|\n)#{1,6}(?!#).*/g; + return content.replaceAll(markdownHeadingRegexp, (substring) => + // TODO probably not the most efficient impl... + substring + .replace('{#', '\\{#') + // prevent duplicate escaping + .replace('\\\\{#', '\\{#'), + ); +} + +/** + * Hacky temporary escape hatch for Crowdin bad MDX support + * See https://docusaurus.io/docs/i18n/crowdin#mdx + * + * TODO Titus suggested a clean solution based on ```mdx eval and Remark + * See https://github.com/mdx-js/mdx/issues/701#issuecomment-947030041 + * + * @param content + */ +export function unwrapMdxCodeBlocks(content: string): string { + // We only support 3/4 backticks on purpose, should be good enough + const regexp3 = + /(?^|\n)```mdx-code-block\n(?.*?)\n```(?\n|$)/gs; + const regexp4 = + /(?^|\n)````mdx-code-block\n(?.*?)\n````(?\n|$)/gs; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const replacer = (substring: string, ...args: any[]) => { + const groups = args.at(-1); + return `${groups.begin}${groups.children}${groups.end}`; + }; + + return content.replaceAll(regexp3, replacer).replaceAll(regexp4, replacer); +} + +/** + * Add support for our legacy ":::note Title" admonition syntax + * Not supported by https://github.com/remarkjs/remark-directive + * Syntax is transformed to ":::note[Title]" (container directive label) + * See https://talk.commonmark.org/t/generic-directives-plugins-syntax/444 + * + * @param content + * @param admonitionContainerDirectives + */ +export function admonitionTitleToDirectiveLabel( + content: string, + admonitionContainerDirectives: string[], +): string { + // this will also process ":::note Title" inside docs code blocks + // good enough: we fixed older versions docs to not be affected + + const directiveNameGroup = `(${admonitionContainerDirectives.join('|')})`; + const regexp = new RegExp( + `^(?:{3,}${directiveNameGroup}) +(?.*)$`, + 'gm', + ); + + return content.replaceAll(regexp, (substring, ...args: any[]) => { + const groups = args.at(-1); + + return `${groups.directive}[${groups.title}]`; + }); +} + // TODO: Find a better way to do so, possibly by compiling the Markdown content, // stripping out HTML tags and obtaining the first line. /** diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap index 9ba1e01a4c..da4d582b28 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -17,7 +17,13 @@ exports[`loadSiteConfig website with .cjs siteConfig 1`] = ` "path": "i18n", }, "markdown": { + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, "mermaid": false, + "preprocessor": undefined, }, "noIndex": false, "onBrokenLinks": "throw", @@ -58,7 +64,13 @@ exports[`loadSiteConfig website with valid async config 1`] = ` "path": "i18n", }, "markdown": { + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, "mermaid": false, + "preprocessor": undefined, }, "noIndex": false, "onBrokenLinks": "throw", @@ -101,7 +113,13 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = ` "path": "i18n", }, "markdown": { + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, "mermaid": false, + "preprocessor": undefined, }, "noIndex": false, "onBrokenLinks": "throw", @@ -144,7 +162,13 @@ exports[`loadSiteConfig website with valid config creator function 1`] = ` "path": "i18n", }, "markdown": { + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, "mermaid": false, + "preprocessor": undefined, }, "noIndex": false, "onBrokenLinks": "throw", @@ -190,7 +214,13 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = ` "path": "i18n", }, "markdown": { + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, "mermaid": false, + "preprocessor": undefined, }, "noIndex": false, "onBrokenLinks": "throw", diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap index 0894af65ee..1051919eb8 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap @@ -91,7 +91,13 @@ exports[`load loads props for site with custom i18n path 1`] = ` "path": "i18n", }, "markdown": { + "mdx1Compat": { + "admonitions": true, + "comments": true, + "headingIds": true, + }, "mermaid": false, + "preprocessor": undefined, }, "noIndex": false, "onBrokenLinks": "throw", diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index e6e0bcd225..465e99e05c 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -32,7 +32,7 @@ describe('normalizeConfig', () => { }); it('accepts correctly defined config options', () => { - const userConfig = { + const userConfig: Config = { ...DEFAULT_CONFIG, ...baseConfig, tagline: 'my awesome site', @@ -60,6 +60,12 @@ describe('normalizeConfig', () => { ], markdown: { mermaid: true, + preprocessor: ({fileContent}) => fileContent, + mdx1Compat: { + comments: true, + admonitions: false, + headingIds: true, + }, }, }; const normalizedConfig = normalizeConfig(userConfig); @@ -496,6 +502,12 @@ describe('markdown', () => { it('accepts valid markdown object', () => { const markdown: DocusaurusConfig['markdown'] = { mermaid: true, + preprocessor: ({fileContent}) => fileContent, + mdx1Compat: { + comments: false, + admonitions: true, + headingIds: false, + }, }; expect( normalizeConfig({ @@ -504,6 +516,51 @@ describe('markdown', () => { ).toEqual(expect.objectContaining({markdown})); }); + it('accepts partial markdown object', () => { + const markdown: DeepPartial<DocusaurusConfig['markdown']> = { + mdx1Compat: { + admonitions: true, + headingIds: false, + }, + }; + expect( + normalizeConfig({ + markdown, + }), + ).toEqual( + expect.objectContaining({ + markdown: { + ...DEFAULT_CONFIG.markdown, + ...markdown, + mdx1Compat: { + ...DEFAULT_CONFIG.markdown.mdx1Compat, + ...markdown.mdx1Compat, + }, + }, + }), + ); + }); + + it('throw for preprocessor bad arity', () => { + expect(() => + normalizeConfig({ + markdown: {preprocessor: () => 'content'}, + }), + ).toThrowErrorMatchingInlineSnapshot(` + ""markdown.preprocessor" must have an arity of 1 + " + `); + expect(() => + normalizeConfig({ + // @ts-expect-error: types forbid this + markdown: {preprocessor: (arg1, arg2) => String(arg1) + String(arg2)}, + }), + ).toThrowErrorMatchingInlineSnapshot(` + ""markdown.preprocessor" must have an arity of 1 + " + `); + }); + it('throw for null object', () => { expect(() => { normalizeConfig({ diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 092a634677..47db1ed29b 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -66,6 +66,12 @@ export const DEFAULT_CONFIG: Pick< staticDirectories: [DEFAULT_STATIC_DIR_NAME], markdown: { mermaid: false, + preprocessor: undefined, + mdx1Compat: { + comments: true, + admonitions: true, + headingIds: true, + }, }, }; @@ -271,6 +277,21 @@ export const ConfigSchema = Joi.object<DocusaurusConfig>({ }).optional(), markdown: Joi.object({ mermaid: Joi.boolean().default(DEFAULT_CONFIG.markdown.mermaid), + preprocessor: Joi.function() + .arity(1) + .optional() + .default(() => DEFAULT_CONFIG.markdown.preprocessor), + mdx1Compat: Joi.object({ + comments: Joi.boolean().default( + DEFAULT_CONFIG.markdown.mdx1Compat.comments, + ), + admonitions: Joi.boolean().default( + DEFAULT_CONFIG.markdown.mdx1Compat.admonitions, + ), + headingIds: Joi.boolean().default( + DEFAULT_CONFIG.markdown.mdx1Compat.headingIds, + ), + }).default(DEFAULT_CONFIG.markdown.mdx1Compat), }).default(DEFAULT_CONFIG.markdown), }).messages({ 'docusaurus.configValidationWarning': diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 868182479d..0be200e49f 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -40,7 +40,9 @@ export function formatStatsErrorMessage( // Also the error causal chain is lost here // We log the stacktrace inside serverEntry.tsx for now (not ideal) const {errors} = formatWebpackMessages(statsJson); - return errors.join('\n---\n'); + return errors + .map((str) => logger.red(str)) + .join(`\n\n${logger.yellow('--------------------------')}\n\n`); } return undefined; } diff --git a/project-words.txt b/project-words.txt index 106f7768d0..cae0c44958 100644 --- a/project-words.txt +++ b/project-words.txt @@ -137,6 +137,7 @@ immer infima inlines intelli +intellij interactiveness interpolatable investec @@ -179,6 +180,7 @@ mdast mdxa mdxast mdxhast +mdxjs metadatum metastring metrica @@ -190,6 +192,9 @@ mkcert mkdir mkdirs mkdocs +mkdn +mdwn +mkdown moesif msapplication nabors @@ -389,6 +394,7 @@ wcag webfactory webp webpackbar +webstorm wolcott writeups xclip @@ -400,3 +406,4 @@ yangshunz zhou zoomable zpao +hastscript diff --git a/website/_dogfooding/_blog tests/2021-08-21-blog-post-toc-tests.mdx b/website/_dogfooding/_blog tests/2021-08-21-blog-post-toc-tests.mdx index 105d193ae6..fe66256a74 100644 --- a/website/_dogfooding/_blog tests/2021-08-21-blog-post-toc-tests.mdx +++ b/website/_dogfooding/_blog tests/2021-08-21-blog-post-toc-tests.mdx @@ -7,7 +7,7 @@ toc_max_heading_level: 4 tags: [paginated-tag] --- -<!-- truncate --> +{/* truncate */} import Content, { toc as ContentToc, diff --git a/website/_dogfooding/_blog tests/2021-10-07-blog-post-mdx-feed-tests.mdx b/website/_dogfooding/_blog tests/2021-10-07-blog-post-mdx-feed-tests.mdx index a171eefe3f..7f501c7e4b 100644 --- a/website/_dogfooding/_blog tests/2021-10-07-blog-post-mdx-feed-tests.mdx +++ b/website/_dogfooding/_blog tests/2021-10-07-blog-post-mdx-feed-tests.mdx @@ -16,7 +16,7 @@ hide_reading_time: true Some MDX tests, mostly to test how the RSS feed render those -<!-- truncate --> +{/* truncate */} ## Imports diff --git a/website/_dogfooding/_blog tests/2021-10-08-blog-post-mdx-require-feed-tests.mdx b/website/_dogfooding/_blog tests/2021-10-08-blog-post-mdx-require-feed-tests.mdx index 1485ef0817..4c572b44fa 100644 --- a/website/_dogfooding/_blog tests/2021-10-08-blog-post-mdx-require-feed-tests.mdx +++ b/website/_dogfooding/_blog tests/2021-10-08-blog-post-mdx-require-feed-tests.mdx @@ -15,7 +15,7 @@ tags: Some MDX tests, mostly to test how the RSS feed render those -<!-- truncate --> +{/* truncate */} Test MDX with require calls diff --git a/website/_dogfooding/_blog tests/demo/2020-08-03-second-blog-intro.mdx b/website/_dogfooding/_blog tests/demo/2020-08-03-second-blog-intro.mdx index c21273c78a..890a2c9a54 100644 --- a/website/_dogfooding/_blog tests/demo/2020-08-03-second-blog-intro.mdx +++ b/website/_dogfooding/_blog tests/demo/2020-08-03-second-blog-intro.mdx @@ -6,7 +6,7 @@ tags: [paginated-tag, blog, docusaurus] Did you know you can use multiple instances of the same plugin? -<!--truncate--> +{/* truncate */} :::tip diff --git a/website/_dogfooding/_docs tests/tests/admonitions.mdx b/website/_dogfooding/_docs tests/tests/admonitions.mdx index 94d751430b..1ecbb3c9a2 100644 --- a/website/_dogfooding/_docs tests/tests/admonitions.mdx +++ b/website/_dogfooding/_docs tests/tests/admonitions.mdx @@ -16,24 +16,22 @@ ## Large font icon +import Admonition from '@theme/Admonition'; + ```mdx-code-block -<admonition +<Admonition type="tip" icon={<span style={{fontSize: 60}}>💡</span>} title="Did you know..."> - <p> content - </p> -</admonition> +</Admonition> -<admonition +<Admonition type="info" icon={<span style={{fontSize: 40}}>ℹ️</span>} title="Did you know..."> - <p> content - </p> -</admonition> +</Admonition> ``` ## Large svg icon @@ -41,21 +39,17 @@ ```mdx-code-block import InfoIcon from "@theme/Admonition/Icon/Info" -<admonition +<Admonition type="tip" icon={<InfoIcon style={{width: 60, height: 60}}/>} title="Did you know..."> - <p> content - </p> -</admonition> +</Admonition> -<admonition +<Admonition type="info" icon={<InfoIcon style={{width: 40, height: 40}}/>} title="Did you know..."> - <p> content - </p> -</admonition> +</Admonition> ``` diff --git a/website/_dogfooding/_pages tests/code-block-tests.mdx b/website/_dogfooding/_pages tests/code-block-tests.mdx index e5e1fbbc1b..8248d0dace 100644 --- a/website/_dogfooding/_pages tests/code-block-tests.mdx +++ b/website/_dogfooding/_pages tests/code-block-tests.mdx @@ -5,6 +5,14 @@ import TabItem from '@theme/TabItem'; # Code block tests +:::danger legacy test page - MDX v1 + +This test page is quite outdated: MDX v2 lowercase tags are not substituted anymore in the same way as they were in v1. + +::: + +--- + ```java class HelloWorld { public static void main(String args[]) { @@ -27,7 +35,7 @@ Multi-line text inside `pre` will turn into one-liner, but it's okay (https://gi <pre>1 2 3</pre> -<!-- prettier-ignore --> +{/* prettier-ignore */} <pre> 1 2 diff --git a/website/_dogfooding/_pages tests/index.mdx b/website/_dogfooding/_pages tests/index.mdx index b5d1255f48..09c2b2cc4f 100644 --- a/website/_dogfooding/_pages tests/index.mdx +++ b/website/_dogfooding/_pages tests/index.mdx @@ -18,6 +18,11 @@ import Readme from "../README.mdx" <Readme /> ``` +### Markdown tests + +- [Markdown tests MDX](/tests/pages/markdown-tests-mdx) +- [Markdown tests MD](/tests/pages/markdown-tests-md) + ### Other tests - [Crash test](/tests/pages/crashTest) @@ -25,8 +30,6 @@ import Readme from "../README.mdx" - [Link tests](/tests/pages/link-tests) - [Error boundary tests](/tests/pages/error-boundary-tests) - [Hydration tests](/tests/pages/hydration-tests) -- [Asset linking tests](/tests/pages/markdown-tests) -- [General Markdown tests](/tests/pages/markdownPageTests) - [TOC tests](/tests/pages/page-toc-tests) - [Diagram tests](/tests/pages/diagrams) - [Tabs tests](/tests/pages/tabs-tests) diff --git a/website/_dogfooding/_pages tests/markdown-tests-md.md b/website/_dogfooding/_pages tests/markdown-tests-md.md new file mode 100644 index 0000000000..a0d9800eb6 --- /dev/null +++ b/website/_dogfooding/_pages tests/markdown-tests-md.md @@ -0,0 +1,44 @@ +--- +title: Markdown Page tests title +description: Markdown Page tests description +wrapperClassName: docusaurus-markdown-example +--- + +# Markdown .md tests + +This file should be interpreted in a more CommonMark compliant way + +## Comment + +Html comment: <!-- comment --> + +<!-- prettier-ignore --> +MDX comment: {/* comment */} + +## JSX syntax + +import BrowserWindow from '@site/src/components/BrowserWindow'; + +<BrowserWindow> + +BrowserWindow content + +<BrowserWindow/> + +export const answer = 42; + +Test {xyz} + +## Admonition + +Admonitions still work + +:::note[title] + +note + +::: + +## Heading Id {#custom-heading-id} + +Custom heading syntax `{#custom-heading-id}` still works diff --git a/website/_dogfooding/_pages tests/markdownPageTests.mdx b/website/_dogfooding/_pages tests/markdown-tests-mdx.mdx similarity index 71% rename from website/_dogfooding/_pages tests/markdownPageTests.mdx rename to website/_dogfooding/_pages tests/markdown-tests-mdx.mdx index a7ce3561d2..5f5c4b635f 100644 --- a/website/_dogfooding/_pages tests/markdownPageTests.mdx +++ b/website/_dogfooding/_pages tests/markdown-tests-mdx.mdx @@ -4,7 +4,7 @@ description: Markdown Page tests description wrapperClassName: docusaurus-markdown-example --- -# Markdown page tests +# Markdown .mdx tests This is a page generated from Markdown to illustrate the Markdown page feature and test some edge cases. @@ -51,20 +51,12 @@ import TabItem from '@theme/TabItem'; MDX comments can be used with ```mdx -<!-- - -My comment - ---> +{/* My comment */} ``` See, nothing is displayed: -<!-- - -My comment - ---> +{/* My comment */} ## Import code block from source code file @@ -180,7 +172,7 @@ function Clock(props) { ### Weird heading {#a b} -### Weird heading {#a{b} +### Weird heading {#a\{b} ## Pipe @@ -247,9 +239,19 @@ Can be arbitrarily nested: - [ ] Task - [ ] Task +## Emojis + +Emojis in this text will be replaced with [remark-emoji](https://www.npmjs.com/package/remark-emoji): :dog: :+1: + ## Admonitions -:::caution Interpolated `title` with a <button style={{color: "red"}} onClick={() => alert("it works")}>button</button> +:::caution Interpolated `title` with a <button style={{color: "red"}} onClick={() => alert("it works")}>button</button> (old syntax) + +Admonition body + +::: + +:::caution[Interpolated `title` with a <button style={{color: "red"}} onClick={() => alert("it works")}>button</button> (directive label syntax)] Admonition body @@ -281,4 +283,60 @@ hey ::::: -after admonition +::::tip[Use tabs in admonitions] + +:::info[Admonition nested] + +test + +::: + +<Tabs> + <TabItem value="apple" label="Apple"> + +:::note[Admonition in tab] + +test + +::: + + </TabItem> + <TabItem value="orange" label="Orange">This is an orange 🍊</TabItem> + <TabItem value="banana" label="Banana">This is a banana 🍌</TabItem> +</Tabs> + +:::: + +## Linking + +This is a test page to see if Docusaurus Markdown features are working properly + +### Linking to assets + +See [#3337](https://github.com/facebook/docusaurus/issues/3337) + +- [/someFile.pdf](/someFile.pdf) + +- [/someFile.xyz](/someFile.xyz) + +- [@site/\_dogfooding/\_asset-tests/someFile.pdf](@site/_dogfooding/_asset-tests/someFile.pdf) + +- [@site/\_dogfooding/\_asset-tests/someFile.xyz](@site/_dogfooding/_asset-tests/someFile.xyz) + +### Linking to non-SPA page hosted within website + +See [#3309](https://github.com/facebook/docusaurus/issues/3309) + +- [pathname:///dogfooding/javadoc](pathname:///dogfooding/javadoc) + +- [pathname:///dogfooding/javadoc/index.html](pathname:///dogfooding/javadoc/index.html) + +- [pathname://../dogfooding/javadoc](pathname://../dogfooding/javadoc) + +- [pathname://../dogfooding/javadoc/index.html](pathname://../dogfooding/javadoc/index.html) + +### Linking to JSON + +- [./script.js](./_script.js) + +- [./data.json](./data.json) diff --git a/website/_dogfooding/_pages tests/markdown-tests.mdx b/website/_dogfooding/_pages tests/markdown-tests.mdx deleted file mode 100644 index 48420cb718..0000000000 --- a/website/_dogfooding/_pages tests/markdown-tests.mdx +++ /dev/null @@ -1,33 +0,0 @@ -# Markdown tests - -This is a test page to see if Docusaurus Markdown features are working properly - -## Linking to assets - -See [#3337](https://github.com/facebook/docusaurus/issues/3337) - -- [/someFile.pdf](/someFile.pdf) - -- [/someFile.xyz](/someFile.xyz) - -- [@site/\_dogfooding/\_asset-tests/someFile.pdf](@site/_dogfooding/_asset-tests/someFile.pdf) - -- [@site/\_dogfooding/\_asset-tests/someFile.xyz](@site/_dogfooding/_asset-tests/someFile.xyz) - -## Linking to non-SPA page hosted within website - -See [#3309](https://github.com/facebook/docusaurus/issues/3309) - -- [pathname:///dogfooding/javadoc](pathname:///dogfooding/javadoc) - -- [pathname:///dogfooding/javadoc/index.html](pathname:///dogfooding/javadoc/index.html) - -- [pathname://../dogfooding/javadoc](pathname://../dogfooding/javadoc) - -- [pathname://../dogfooding/javadoc/index.html](pathname://../dogfooding/javadoc/index.html) - -## Linking to JSON - -- [./script.js](./_script.js) - -- [./data.json](./data.json) diff --git a/website/blog/2018-09-11-Towards-Docusaurus-2.mdx b/website/blog/2018-09-11-Towards-Docusaurus-2.mdx index 0cf963c66b..5496e46ae9 100644 --- a/website/blog/2018-09-11-Towards-Docusaurus-2.mdx +++ b/website/blog/2018-09-11-Towards-Docusaurus-2.mdx @@ -21,15 +21,12 @@ It all started with this [RFC issue](https://github.com/facebook/docusaurus/issu <blockquote> <h4> <a href="https://github.com/facebook/docusaurus/issues/789"> - [RFC] Docusaurus v2 · Issue #789 · facebook/docusaurus + {'[RFC] Docusaurus v2 · Issue #789 · facebook/docusaurus'} </a> </h4> - <p> - These are some of the problems I'm seeing in Docusaurus now and also how we - can address them in v2. A number of the ideas here were inspired by VuePress - and other static site generators. In the current static site generators - ecosystem, t... - </p> + These are some of the problems I'm seeing in Docusaurus now and also how we can + address them in v2. A number of the ideas here were inspired by VuePress and other + static site generators. In the current static site generators ecosystem, t... </blockquote> Most of the suggested improvements are mentioned in the issue; I will provide details on some of issues in Docusaurus 1 and how we are going to address them in Docusaurus 2. diff --git a/website/blog/2022-08-01-announcing-docusaurus-2.0/index.mdx b/website/blog/2022-08-01-announcing-docusaurus-2.0/index.mdx index 6d97a024fb..bfc046cf32 100644 --- a/website/blog/2022-08-01-announcing-docusaurus-2.0/index.mdx +++ b/website/blog/2022-08-01-announcing-docusaurus-2.0/index.mdx @@ -32,7 +32,7 @@ After **4 years of work, [75 alphas](https://github.com/facebook/docusaurus/rele ![social-card image](./img/social-card.png) -<!--truncate--> +{/* truncate */} :::info We are on [ProductHunt](https://www.producthunt.com/posts/docusaurus-2-0) and [Hacker News](https://news.ycombinator.com/item?id=32303052)! diff --git a/website/blog/releases/2.2/index.mdx b/website/blog/releases/2.2/index.mdx index ccae084d65..f1ec204d64 100644 --- a/website/blog/releases/2.2/index.mdx +++ b/website/blog/releases/2.2/index.mdx @@ -12,7 +12,7 @@ The upgrade should be easy: as explained in our [release process documentation]( ![Docusaurus 2.2 social card](./img/social-card.png) -<!--truncate--> +{/* truncate */} ## Highlights diff --git a/website/docs/api/docusaurus.config.js.mdx b/website/docs/api/docusaurus.config.js.mdx index e9c7c6e99d..9b4ff87628 100644 --- a/website/docs/api/docusaurus.config.js.mdx +++ b/website/docs/api/docusaurus.config.js.mdx @@ -123,7 +123,7 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction. Example: -<!-- cSpell:ignore فارسی --> +{/* cSpell:ignore فارسی */} ```js title="docusaurus.config.js" module.exports = { diff --git a/website/docs/api/plugins/plugin-content-blog.mdx b/website/docs/api/plugins/plugin-content-blog.mdx index 1353ff8720..68c0515dff 100644 --- a/website/docs/api/plugins/plugin-content-blog.mdx +++ b/website/docs/api/plugins/plugin-content-blog.mdx @@ -61,7 +61,7 @@ Accepted fields: | `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. | | `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. | | `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. | -| `truncateMarker` | `RegExp` | `/<!--\s*(truncate)\s*-->/` | Truncate marker marking where the summary ends. | +| `truncateMarker` | `RegExp` | `/<!--\s*truncate\s*-->/` \| `\{\/\*\s*truncate\s*\*\/\}/` | Truncate marker marking where the summary ends. | | `showReadingTime` | `boolean` | `true` | Show estimated reading time for the blog post. | | `readingTime` | `ReadingTimeFn` | The default reading time | A callback to customize the reading time number displayed. | | `authorsMapPath` | `string` | `'authors.yml'` | Path to the authors map file, relative to the blog content directory. | @@ -69,7 +69,7 @@ Accepted fields: | `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.createFeedItems` | <code><a href="#CreateFeedItemsFn">CreateFeedItemsFn</a> \| undefined</code> | `undefined` | An optional function which can be used to transform and / or filter the items in the feed. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | -| `feedOptions.description` | `string` | <code>\`${siteConfig.title} Blog\`</code> | Description of the feed. | +| `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. | | `feedOptions.copyright` | `string` | `undefined` | Copyright message. | | `feedOptions.language` | `string` (See [documentation](http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes) for possible values) | `undefined` | Language metadata of the feed. | | `sortPosts` | <code>'descending' \| 'ascending' </code> | `'descending'` | Governs the direction of blog post sorting. | diff --git a/website/docs/blog.mdx b/website/docs/blog.mdx index b6a3f53d67..2c1bb0179e 100644 --- a/website/docs/blog.mdx +++ b/website/docs/blog.mdx @@ -63,7 +63,7 @@ hide_table_of_contents: false Welcome to this blog. This blog is created with [**Docusaurus 2**](https://docusaurus.io/). -<!--truncate--> +<!-- truncate --> This is my first post on Docusaurus 2. @@ -78,22 +78,31 @@ The blog's index page (by default, it is at `/blog`) is the _blog list page_, wh Use the `<!--truncate-->` marker in your blog post to represent what will be shown as the summary when viewing all published blog posts. Anything above `<!--truncate-->` will be part of the summary. For example: -```md +```md title="website/blog/my-post.md" {7} --- -title: Truncation Example +title: Markdown blog truncation example --- All these will be part of the blog post summary. -Even this. - -<!--truncate--> +<!-- truncate --> But anything from here on down will not be. +``` -Not this. +For files using the `.mdx` extension, use a [MDX](https://mdxjs.com/) comment `{/* truncate */}` instead: -Or this. +{/* prettier-ignore */} +```md title="website/blog/my-post.mdx" {7} +--- +title: MDX blog truncation Example +--- + +All these will be part of the blog post summary. + +{/* truncate */} + +But anything from here on down will not be. ``` By default, 10 posts are shown on each blog list page, but you can control pagination with the `postsPerPage` option in the plugin configuration. If you set `postsPerPage: 'ALL'`, pagination will be disabled and all posts will be displayed on the first page. You can also add a meta description to the blog list page for better SEO: diff --git a/website/docs/guides/markdown-features/markdown-features-admonitions.mdx b/website/docs/guides/markdown-features/markdown-features-admonitions.mdx index 231851f7db..d1ae159315 100644 --- a/website/docs/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/docs/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,7 +87,7 @@ Some **content** with _Markdown_ `syntax`. Check [this `api`](#). If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Prettier doesn't change this --> :::note @@ -110,9 +110,9 @@ Hello world You may also specify an optional title. ```md -:::note Your Title +:::note[Your Title **with** some _Markdown_ `syntax`!] -Some **content** with _Markdown_ `syntax`. +Some **content** with some _Markdown_ `syntax`. ::: ``` @@ -120,9 +120,9 @@ Some **content** with _Markdown_ `syntax`. ```mdx-code-block <BrowserWindow> -:::note Your Title +:::note[Your Title **with** some _Markdown_ `syntax`!] -Some **content** with _Markdown_ `syntax`. +Some **content** with some _Markdown_ `syntax`. ::: @@ -186,7 +186,7 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -:::tip Use tabs in admonitions +:::tip[Use tabs in admonitions] <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -200,7 +200,7 @@ import TabItem from '@theme/TabItem'; ```mdx-code-block <BrowserWindow> -:::tip Use tabs in admonitions +:::tip[Use tabs in admonitions] <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -235,20 +235,16 @@ The types that are accepted are the same as above: `note`, `tip`, `danger`, `inf ```jsx title="MyReactPage.jsx" <Admonition type="tip" icon="💡" title="Did you know..."> - <p> - Use plugins to introduce shorter syntax for the most commonly used JSX - elements in your project. - </p> + Use plugins to introduce shorter syntax for the most commonly used JSX + elements in your project. </Admonition> ``` ```mdx-code-block <BrowserWindow> <Admonition type="tip" icon="💡" title="Did you know..."> - <p> - Use plugins to introduce shorter syntax for the most commonly used JSX - elements in your project. - </p> + Use plugins to introduce shorter syntax for the most commonly used JSX + elements in your project. </Admonition> </BrowserWindow> ``` @@ -286,7 +282,6 @@ module.exports = { { docs: { admonitions: { - tag: ':::', keywords: ['note', 'tip', 'info', 'caution', 'danger'], extendDefaults: true, }, @@ -299,9 +294,8 @@ module.exports = { The plugin accepts the following options: -- `tag`: The tag that encloses the admonition. Defaults to `:::`. - `keywords`: An array of keywords that can be used as the type for the admonition. -- `extendDefaults`: Should the provided options (such as `keywords`) be merged into the existing defaults. Defaults to `false`. +- `extendDefaults`: Should the provided options (such as `keywords`) be merged into the existing defaults. Defaults to `true`. The `keyword` will be passed as the `type` prop of the `Admonition` component. @@ -321,7 +315,6 @@ module.exports = { // ... docs: { admonitions: { - tag: ':::', keywords: ['my-custom-admonition'], extendDefaults: true, }, @@ -361,7 +354,7 @@ export default AdmonitionTypes; Now you can use your new admonition keyword in a Markdown file, and it will be parsed and rendered with your custom logic: ```md -:::my-custom-admonition Custom Admonition +:::my-custom-admonition[My Title] It works! @@ -370,7 +363,7 @@ It works! <BrowserWindow> -:::my-custom-admonition Custom Admonition +:::my-custom-admonition[My Title] It works! diff --git a/website/docs/guides/markdown-features/markdown-features-math-equations.mdx b/website/docs/guides/markdown-features/markdown-features-math-equations.mdx index 631a9dbaa5..1b1a8ad38d 100644 --- a/website/docs/guides/markdown-features/markdown-features-math-equations.mdx +++ b/website/docs/guides/markdown-features/markdown-features-math-equations.mdx @@ -54,27 +54,32 @@ $$ To enable KaTeX, you need to install `remark-math` and `rehype-katex` plugins. ```bash npm2yarn -npm install --save remark-math@3 rehype-katex@5 hast-util-is-element@1.1.0 +npm install --save remark-math@5 rehype-katex@6 ``` :::caution -Use the exact same versions. The latest versions are incompatible with Docusaurus 2. +Make sure to use `remark-math >= 5` and `rehype-katex >= 6` for Docusaurus v3 (using MDX v2). ::: -Import the plugins in `docusaurus.config.js`: +Those 2 plugins are now only available as ESM packages, and you will need to import them dynamically. -```js -const math = require('remark-math'); -const katex = require('rehype-katex'); +First, turn your site config into an async config creator function: + +```js title="docusaurus.config.js" +module.exports = async function createConfigAsync() { + return { + // your site config... + }; +}; ``` -Add them to your content plugin or preset options (usually `@docusaurus/preset-classic` docs options): +It is now possible to import the plugins dynamically and add them to your content plugin or preset options (usually `@docusaurus/preset-classic` docs options): ```js -remarkPlugins: [math], -rehypePlugins: [katex], +remarkPlugins: [(await import('remark-math')).default], +rehypePlugins: [(await import('rehype-katex')).default], ``` Include the KaTeX CSS in your config under `stylesheets`: @@ -94,39 +99,36 @@ stylesheets: [ Overall the changes look like: ```js title="docusaurus.config.js" -// highlight-start -const math = require('remark-math'); -const katex = require('rehype-katex'); -// highlight-end - -module.exports = { - title: 'Docusaurus', - tagline: 'Build optimized websites quickly, focus on your content', - presets: [ - [ - '@docusaurus/preset-classic', - { - docs: { - path: 'docs', - // highlight-start - remarkPlugins: [math], - rehypePlugins: [katex], - // highlight-end +module.exports = async function createConfigAsync() { + return { + title: 'Docusaurus', + tagline: 'Build optimized websites quickly, focus on your content', + presets: [ + [ + '@docusaurus/preset-classic', + { + docs: { + path: 'docs', + // highlight-start + remarkPlugins: [(await import('remark-math')).default], + rehypePlugins: [(await import('rehype-katex')).default], + // highlight-end + }, }, + ], + ], + // highlight-start + stylesheets: [ + { + href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', + type: 'text/css', + integrity: + 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', + crossorigin: 'anonymous', }, ], - ], - // highlight-start - stylesheets: [ - { - href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', - type: 'text/css', - integrity: - 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', - crossorigin: 'anonymous', - }, - ], - // highlight-end + // highlight-end + }; }; ``` @@ -144,67 +146,3 @@ module.exports = { ], }; ``` - -## Upgrading rehype-katex beyond recommended version {#upgrading-rehype-katex-beyond-recommended-version} - -:::tip - -Only use the latest version if you actually need the bleeding-edge features of $\KaTeX$. Most users should find the older versions work just as well. - -::: - -The latest versions of `rehype-katex` (starting from `v6.0.0`) has moved to ES Modules, a new module system of JavaScript, which Docusaurus doesn't officially support yet. However, it is possible to import `rehype-katex` dynamically, using an async config creator. Docusaurus will call this creator function and wait for it to return the config object. - -```js title="docusaurus.config.js" -async function createConfig() { - // ES Modules are imported with `import()` instead of `require()`, and are imported asynchronously - // highlight-next-line - const katex = (await import('rehype-katex')).default; - return { - // ... - }; -} -``` - -In this case, the overall configuration changes will look like: - -```js title="docusaurus.config.js" -// highlight-next-line -const math = require('remark-math'); - -async function createConfig() { - // highlight-next-line - const katex = (await import('rehype-katex')).default; - return { - title: 'Docusaurus', - tagline: 'Build optimized websites quickly, focus on your content', - presets: [ - [ - '@docusaurus/preset-classic', - { - docs: { - path: 'docs', - // highlight-start - remarkPlugins: [math], - rehypePlugins: [katex], - // highlight-end - }, - }, - ], - ], - // highlight-start - stylesheets: [ - { - href: 'https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css', - type: 'text/css', - integrity: - 'sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ', - crossorigin: 'anonymous', - }, - ], - // highlight-end - }; -} - -module.exports = createConfig; -``` diff --git a/website/docs/guides/markdown-features/markdown-features-react.mdx b/website/docs/guides/markdown-features/markdown-features-react.mdx index 9768159642..aa8e93c034 100644 --- a/website/docs/guides/markdown-features/markdown-features-react.mdx +++ b/website/docs/guides/markdown-features/markdown-features-react.mdx @@ -64,8 +64,8 @@ export const Highlight = ({children, color}) => ( <BrowserWindow minHeight={240}> -<Highlight color="#25c2a0">Docusaurus green</Highlight> -{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors. +<><Highlight color="#25c2a0">Docusaurus green</Highlight> +{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.</> I can write **Markdown** alongside my _JSX_! @@ -76,7 +76,7 @@ I can write **Markdown** alongside my _JSX_! Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx /* Instead of this: */ <span style="background-color: red">Foo</span> @@ -94,7 +94,7 @@ In addition, MDX is not [100% compatible with CommonMark](https://github.com/fac You can also import your own components defined in other files or third-party components installed via npm. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Docusaurus theme component --> import TOCInline from '@theme/TOCInline'; @@ -341,7 +341,7 @@ Use JSX within JSX tag, or move the Markdown to the outer layer: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> **Bold still doesn't work** @@ -367,7 +367,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -397,7 +397,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -427,7 +427,7 @@ Don't indent: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -463,14 +463,13 @@ npm install --save raw-loader Now you can import code snippets from another file as it is: -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="myMarkdownFile.mdx" import CodeBlock from '@theme/CodeBlock'; import MyComponentSource from '!!raw-loader!./myComponent'; <CodeBlock language="jsx">{MyComponentSource}</CodeBlock> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import CodeBlock from '@theme/CodeBlock'; @@ -509,13 +508,12 @@ By convention, using the **`_` filename prefix** will not create any doc page an This is text some content from `_markdown-partial-example.mdx`. ``` -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="someOtherDoc.mdx" import PartialExample from './_markdown-partial-example.mdx'; <PartialExample name="Sebastien" /> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import PartialExample from './_markdown-partial-example.mdx'; diff --git a/website/docs/guides/markdown-features/markdown-features-tabs.mdx b/website/docs/guides/markdown-features/markdown-features-tabs.mdx index 69b1b0c424..996d9fa453 100644 --- a/website/docs/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/docs/guides/markdown-features/markdown-features-tabs.mdx @@ -15,7 +15,7 @@ import styles from './markdown-features-tabs-styles.module.css'; Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx): -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -32,7 +32,6 @@ import TabItem from '@theme/TabItem'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```mdx-code-block <BrowserWindow> @@ -250,7 +249,7 @@ You might want to customize the appearance of a certain set of tabs. You can pas You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`. -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="some-doc.mdx" import styles from './styles.module.css'; @@ -266,7 +265,6 @@ import styles from './styles.module.css'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```css title="styles.module.css" .red { diff --git a/website/docs/guides/markdown-features/markdown-features-toc.mdx b/website/docs/guides/markdown-features/markdown-features-toc.mdx index 4b2857c4f7..b1b6507f25 100644 --- a/website/docs/guides/markdown-features/markdown-features-toc.mdx +++ b/website/docs/guides/markdown-features/markdown-features-toc.mdx @@ -43,8 +43,8 @@ Generated IDs have **some limitations**: A special Markdown syntax lets you set an **explicit heading id**: -```md -### Hello World {#my-explicit-id} +```mdx-code-block +<Code language="md">{'### Hello World \u007B#my-explicit-id}\n'}</Code> ``` :::tip @@ -102,7 +102,7 @@ It is also possible to display an inline table of contents directly inside a Mar The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; @@ -129,7 +129,7 @@ declare const toc: { Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; diff --git a/website/docs/i18n/i18n-crowdin.mdx b/website/docs/i18n/i18n-crowdin.mdx index 104b636a7b..f60b2a5102 100644 --- a/website/docs/i18n/i18n-crowdin.mdx +++ b/website/docs/i18n/i18n-crowdin.mdx @@ -351,7 +351,8 @@ We recommend extracting the complex embedded JSX code as separate standalone com To deploy Docusaurus, run the following command: -````mdx-code-block +````mdx-code-block  + import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/website/docs/introduction.mdx b/website/docs/introduction.mdx index 46b616c7d5..383563a61f 100644 --- a/website/docs/introduction.mdx +++ b/website/docs/introduction.mdx @@ -50,12 +50,13 @@ Or read the **[5-minute tutorial](https://tutorial.docusaurus.io)** online. In this presentation at [Algolia Community Event](https://www.algolia.com/), [Meta Open Source team](https://opensource.facebook.com/) shared a brief walk-through of Docusaurus. They covered how to get started with the project, enable plugins, and set up functionalities like documentation and blogging. +{/* cSpell:ignore Yhyx Sksg */} + ```mdx-code-block import LiteYouTubeEmbed from 'react-lite-youtube-embed'; <div className="video-container"> <LiteYouTubeEmbed - // cSpell:ignore Yhyx Sksg id="Yhyx7otSksg" params="autoplay=1&autohide=1&showinfo=0&rel=0" title="Docusaurus: Documentation Made Easy" @@ -129,18 +130,6 @@ Docusaurus 2 is born to be compassionately accessible to all your users, and lig We believe that, as developers, knowing how a library works helps us become better at using it. Hence we're dedicating effort to explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it. -<!-- - -Explain the principles that guide the development of Docusaurus. - -References ---- -- https://www.gatsbyjs.org/docs/behind-the-scenes/ -- https://reactjs.org/docs/design-principles.html -- https://v1.vuepress.vuejs.org/miscellaneous/design-concepts.html - ---> - ## Comparison with other tools {#comparison-with-other-tools} Across all static site generators, Docusaurus has a unique focus on documentation sites and has many out-of-the-box features. diff --git a/website/docs/search.mdx b/website/docs/search.mdx index 32fdcd7f68..78f785bca0 100644 --- a/website/docs/search.mdx +++ b/website/docs/search.mdx @@ -247,7 +247,7 @@ Still, you can reuse the [Infima CSS variables](styling-layout.mdx#styling-your- ### Customizing the Algolia search behavior {#customizing-the-algolia-search-behavior} -<!-- TODO: update options link once the documentation is available on the DocSearch website --> +{/* TODO: update options link once the documentation is available on the DocSearch website */} Algolia DocSearch supports a [list of options](https://autocomplete-experimental.netlify.app/docs/DocSearchModal#reference) that you can pass to the `algolia` field in the `docusaurus.config.js` file. diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 156ab21d68..0a308b8aea 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -7,7 +7,6 @@ // @ts-check const path = require('path'); -const math = require('remark-math'); const npm2yarn = require('@docusaurus/remark-plugin-npm2yarn'); const versions = require('./versions.json'); const VersionsArchived = require('./versionsArchived.json'); @@ -140,6 +139,20 @@ module.exports = async function createConfigAsync() { }, markdown: { mermaid: true, + mdx1Compat: { + // comments: false, + }, + preprocessor: ({filePath, fileContent}) => { + if (isDev) { + // "vscode://file/${projectPath}${filePath}:${line}:${column}", + // "webstorm://open?file=${projectPath}${filePath}&line=${line}&column=${column}", + const vscodeLink = `vscode://file/${filePath}`; + const webstormLink = `webstorm://open?file=${filePath}`; + const intellijLink = `idea://open?file=${filePath}`; + return `${fileContent}\n\n---\n\n**DEV**: open this file in [VSCode](<${vscodeLink}>) | [WebStorm](<${webstormLink}>) | [IntelliJ](<${intellijLink}>)\n`; + } + return fileContent; + }, }, onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', @@ -331,13 +344,12 @@ module.exports = async function createConfigAsync() { }, admonitions: { keywords: ['my-custom-admonition'], - extendDefaults: true, }, showLastUpdateAuthor: true, showLastUpdateTime: true, remarkPlugins: [ - math, [npm2yarn, {sync: true}], + (await import('remark-math')).default, (await import('./src/remark/configTabs.mjs')).default, ], rehypePlugins: [(await import('rehype-katex')).default], @@ -346,6 +358,7 @@ module.exports = async function createConfigAsync() { isDev || isDeployPreview || isBranchDeploy ? 'current' : undefined, + onlyIncludeVersions: (() => { if (isBuildFast) { return ['current']; diff --git a/website/package.json b/website/package.json index 50949de6a0..a1009bf646 100644 --- a/website/package.json +++ b/website/package.json @@ -63,7 +63,7 @@ "react-medium-image-zoom": "^5.1.3", "react-popper": "^2.3.0", "rehype-katex": "^6.0.2", - "remark-math": "^3.0.1", + "remark-math": "^5.1.1", "swc-loader": "^0.2.3", "unist-util-visit": "^2.0.3", "webpack": "^5.76.0", diff --git a/website/src/plugins/changelog/index.js b/website/src/plugins/changelog/index.js index 0b68627169..c0b294fc11 100644 --- a/website/src/plugins/changelog/index.js +++ b/website/src/plugins/changelog/index.js @@ -67,6 +67,8 @@ function processSection(section) { return { title: title.replace(/ \(.*\)/, ''), content: `--- +mdx: + format: md date: ${`${date}T${hour}:00`}${ authors ? ` diff --git a/website/src/remark/configTabs.mjs b/website/src/remark/configTabs.mjs index 7b893cf924..14eb7ad9f5 100644 --- a/website/src/remark/configTabs.mjs +++ b/website/src/remark/configTabs.mjs @@ -36,26 +36,59 @@ export default function plugin() { .replace(pluginMeta, '') .trim() .replace(/^.*?= /, '') - .replace(/;$/, '') - // eslint-disable-next-line prefer-named-capture-group - .replace(/([`$\\])/g, '\\$1'); + .replace(/;$/, ''); - parent.children.splice( - index, - 1, - { - type: 'import', - value: `import ConfigTabs from "@site/src/components/ConfigTabs";`, + const importNode = { + type: 'mdxjsEsm', + value: 'import ConfigTabs from "@site/src/components/ConfigTabs"', + data: { + estree: { + type: 'Program', + body: [ + { + type: 'ImportDeclaration', + specifiers: [ + { + type: 'ImportDefaultSpecifier', + local: {type: 'Identifier', name: 'ConfigTabs'}, + }, + ], + source: { + type: 'Literal', + value: '@site/src/components/ConfigTabs', + raw: "'@site/src/components/ConfigTabs'", + }, + }, + ], + sourceType: 'module', + }, }, - { - type: 'jsx', - value: `<ConfigTabs - pluginName="${pluginName.trim()}" - presetOptionName="${presetOptionName.trim()}" - code={\`${config}\`} - />`, - }, - ); + }; + + const jsxNode = { + type: 'mdxJsxFlowElement', + name: 'ConfigTabs', + attributes: [ + { + type: 'mdxJsxAttribute', + name: 'pluginName', + value: pluginName.trim(), + }, + { + type: 'mdxJsxAttribute', + name: 'presetOptionName', + value: presetOptionName.trim(), + }, + { + type: 'mdxJsxAttribute', + name: 'code', + value: config, + }, + ], + children: [], + }; + + parent.children.splice(index, 1, importNode, jsxNode); }); }; return transformer; diff --git a/website/src/theme/MDXComponents.tsx b/website/src/theme/MDXComponents.tsx index d2fd0c1282..8cfc831503 100644 --- a/website/src/theme/MDXComponents.tsx +++ b/website/src/theme/MDXComponents.tsx @@ -6,11 +6,13 @@ */ import MDXComponents from '@theme-original/MDXComponents'; +import Code from '@theme/MDXComponents/Code'; import Highlight from '@site/src/components/Highlight'; import TweetQuote from '@site/src/components/TweetQuote'; export default { ...MDXComponents, + Code, Highlight, TweetQuote, }; diff --git a/website/versioned_docs/version-2.0.1/api/docusaurus.config.js.mdx b/website/versioned_docs/version-2.0.1/api/docusaurus.config.js.mdx index cdce44e0dd..ae1803e512 100644 --- a/website/versioned_docs/version-2.0.1/api/docusaurus.config.js.mdx +++ b/website/versioned_docs/version-2.0.1/api/docusaurus.config.js.mdx @@ -123,7 +123,7 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction. Example: -<!-- cSpell:ignore فارسی --> +{/* cSpell:ignore فارسی */} ```js title="docusaurus.config.js" module.exports = { diff --git a/website/versioned_docs/version-2.0.1/api/plugins/plugin-content-blog.mdx b/website/versioned_docs/version-2.0.1/api/plugins/plugin-content-blog.mdx index 38119b6da8..b20a58284b 100644 --- a/website/versioned_docs/version-2.0.1/api/plugins/plugin-content-blog.mdx +++ b/website/versioned_docs/version-2.0.1/api/plugins/plugin-content-blog.mdx @@ -68,7 +68,7 @@ Accepted fields: | `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. | | `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | -| `feedOptions.description` | `string` | <code>\`${siteConfig.title} Blog\`</code> | Description of the feed. | +| `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. | | `feedOptions.copyright` | `string` | `undefined` | Copyright message. | | `feedOptions.language` | `string` (See [documentation](http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes) for possible values) | `undefined` | Language metadata of the feed. | | `sortPosts` | <code>'descending' \| 'ascending' </code> | `'descending'` | Governs the direction of blog post sorting. | diff --git a/website/versioned_docs/version-2.0.1/blog.mdx b/website/versioned_docs/version-2.0.1/blog.mdx index a2262e2f11..cc91a00324 100644 --- a/website/versioned_docs/version-2.0.1/blog.mdx +++ b/website/versioned_docs/version-2.0.1/blog.mdx @@ -63,7 +63,7 @@ hide_table_of_contents: false Welcome to this blog. This blog is created with [**Docusaurus 2**](https://docusaurus.io/). -<!--truncate--> +<!-- truncate --> This is my first post on Docusaurus 2. diff --git a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-admonitions.mdx b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-admonitions.mdx index f4c00f7c3f..9957822ebf 100644 --- a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,7 +87,7 @@ Some **content** with _Markdown_ `syntax`. Check [this `api`](#). If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Prettier doesn't change this --> :::note @@ -110,7 +110,7 @@ Hello world You may also specify an optional title. ```md -:::note Your Title +:::note Your Title Some **content** with _Markdown_ `syntax`. @@ -138,7 +138,9 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -152,7 +154,9 @@ import TabItem from '@theme/TabItem'; ```mdx-code-block <BrowserWindow> -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> diff --git a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-react.mdx b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-react.mdx index 5bd883980e..da8e9fd86b 100644 --- a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-react.mdx +++ b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-react.mdx @@ -76,7 +76,7 @@ I can write **Markdown** alongside my _JSX_! Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx /* Instead of this: */ <span style="background-color: red">Foo</span> @@ -94,7 +94,7 @@ In addition, MDX is not [100% compatible with CommonMark](https://github.com/fac You can also import your own components defined in other files or third-party components installed via npm. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Docusaurus theme component --> import TOCInline from '@theme/TOCInline'; @@ -341,7 +341,7 @@ Use JSX within JSX tag, or move the Markdown to the outer layer: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> **Bold still doesn't work** @@ -367,7 +367,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -397,7 +397,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -427,7 +427,7 @@ Don't indent: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -463,14 +463,13 @@ npm install --save raw-loader Now you can import code snippets from another file as it is: -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="myMarkdownFile.mdx" import CodeBlock from '@theme/CodeBlock'; import MyComponentSource from '!!raw-loader!./myComponent'; <CodeBlock language="jsx">{MyComponentSource}</CodeBlock> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import CodeBlock from '@theme/CodeBlock'; @@ -509,13 +508,12 @@ By convention, using the **`_` filename prefix** will not create any doc page an This is text some content from `_markdown-partial-example.mdx`. ``` -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="someOtherDoc.mdx" import PartialExample from './_markdown-partial-example.mdx'; <PartialExample name="Sebastien" /> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import PartialExample from './_markdown-partial-example.mdx'; diff --git a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-tabs.mdx index 897f54a8a7..987f1067a3 100644 --- a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-tabs.mdx @@ -15,7 +15,7 @@ import styles from './markdown-features-tabs-styles.module.css'; Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx): -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -32,7 +32,6 @@ import TabItem from '@theme/TabItem'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```mdx-code-block <BrowserWindow> @@ -250,7 +249,7 @@ You might want to customize the appearance of a certain set of tabs. You can pas You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`. -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="some-doc.mdx" import styles from './styles.module.css'; @@ -266,7 +265,6 @@ import styles from './styles.module.css'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```css title="styles.module.css" .red { diff --git a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-toc.mdx b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-toc.mdx index 4b2857c4f7..b1b6507f25 100644 --- a/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-toc.mdx +++ b/website/versioned_docs/version-2.0.1/guides/markdown-features/markdown-features-toc.mdx @@ -43,8 +43,8 @@ Generated IDs have **some limitations**: A special Markdown syntax lets you set an **explicit heading id**: -```md -### Hello World {#my-explicit-id} +```mdx-code-block +<Code language="md">{'### Hello World \u007B#my-explicit-id}\n'}</Code> ``` :::tip @@ -102,7 +102,7 @@ It is also possible to display an inline table of contents directly inside a Mar The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; @@ -129,7 +129,7 @@ declare const toc: { Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; diff --git a/website/versioned_docs/version-2.0.1/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.0.1/i18n/i18n-crowdin.mdx index 104b636a7b..455d68c157 100644 --- a/website/versioned_docs/version-2.0.1/i18n/i18n-crowdin.mdx +++ b/website/versioned_docs/version-2.0.1/i18n/i18n-crowdin.mdx @@ -351,7 +351,7 @@ We recommend extracting the complex embedded JSX code as separate standalone com To deploy Docusaurus, run the following command: -````mdx-code-block +````mdx-code-block  import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/website/versioned_docs/version-2.0.1/introduction.mdx b/website/versioned_docs/version-2.0.1/introduction.mdx index 46b616c7d5..a03b487c78 100644 --- a/website/versioned_docs/version-2.0.1/introduction.mdx +++ b/website/versioned_docs/version-2.0.1/introduction.mdx @@ -55,7 +55,6 @@ import LiteYouTubeEmbed from 'react-lite-youtube-embed'; <div className="video-container"> <LiteYouTubeEmbed - // cSpell:ignore Yhyx Sksg id="Yhyx7otSksg" params="autoplay=1&autohide=1&showinfo=0&rel=0" title="Docusaurus: Documentation Made Easy" @@ -129,18 +128,6 @@ Docusaurus 2 is born to be compassionately accessible to all your users, and lig We believe that, as developers, knowing how a library works helps us become better at using it. Hence we're dedicating effort to explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it. -<!-- - -Explain the principles that guide the development of Docusaurus. - -References ---- -- https://www.gatsbyjs.org/docs/behind-the-scenes/ -- https://reactjs.org/docs/design-principles.html -- https://v1.vuepress.vuejs.org/miscellaneous/design-concepts.html - ---> - ## Comparison with other tools {#comparison-with-other-tools} Across all static site generators, Docusaurus has a unique focus on documentation sites and has many out-of-the-box features. diff --git a/website/versioned_docs/version-2.0.1/search.mdx b/website/versioned_docs/version-2.0.1/search.mdx index 66e6b3c13a..c1dad98ff9 100644 --- a/website/versioned_docs/version-2.0.1/search.mdx +++ b/website/versioned_docs/version-2.0.1/search.mdx @@ -241,7 +241,7 @@ Still, you can reuse the [Infima CSS variables](styling-layout.mdx#styling-your- ### Customizing the Algolia search behavior {#customizing-the-algolia-search-behavior} -<!-- TODO: update options link once the documentation is available on the DocSearch website --> +{/* TODO: update options link once the documentation is available on the DocSearch website */} Algolia DocSearch supports a [list of options](https://autocomplete-experimental.netlify.app/docs/DocSearchModal#reference) that you can pass to the `algolia` field in the `docusaurus.config.js` file. diff --git a/website/versioned_docs/version-2.1.0/api/docusaurus.config.js.mdx b/website/versioned_docs/version-2.1.0/api/docusaurus.config.js.mdx index 466bf06f92..a6c5215fc2 100644 --- a/website/versioned_docs/version-2.1.0/api/docusaurus.config.js.mdx +++ b/website/versioned_docs/version-2.1.0/api/docusaurus.config.js.mdx @@ -123,7 +123,7 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction. Example: -<!-- cSpell:ignore فارسی --> +{/* cSpell:ignore فارسی */} ```js title="docusaurus.config.js" module.exports = { diff --git a/website/versioned_docs/version-2.1.0/api/plugins/plugin-content-blog.mdx b/website/versioned_docs/version-2.1.0/api/plugins/plugin-content-blog.mdx index 38119b6da8..b20a58284b 100644 --- a/website/versioned_docs/version-2.1.0/api/plugins/plugin-content-blog.mdx +++ b/website/versioned_docs/version-2.1.0/api/plugins/plugin-content-blog.mdx @@ -68,7 +68,7 @@ Accepted fields: | `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. | | `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | -| `feedOptions.description` | `string` | <code>\`${siteConfig.title} Blog\`</code> | Description of the feed. | +| `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. | | `feedOptions.copyright` | `string` | `undefined` | Copyright message. | | `feedOptions.language` | `string` (See [documentation](http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes) for possible values) | `undefined` | Language metadata of the feed. | | `sortPosts` | <code>'descending' \| 'ascending' </code> | `'descending'` | Governs the direction of blog post sorting. | diff --git a/website/versioned_docs/version-2.1.0/blog.mdx b/website/versioned_docs/version-2.1.0/blog.mdx index a2262e2f11..cc91a00324 100644 --- a/website/versioned_docs/version-2.1.0/blog.mdx +++ b/website/versioned_docs/version-2.1.0/blog.mdx @@ -63,7 +63,7 @@ hide_table_of_contents: false Welcome to this blog. This blog is created with [**Docusaurus 2**](https://docusaurus.io/). -<!--truncate--> +<!-- truncate --> This is my first post on Docusaurus 2. diff --git a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-admonitions.mdx b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-admonitions.mdx index f4c00f7c3f..9957822ebf 100644 --- a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,7 +87,7 @@ Some **content** with _Markdown_ `syntax`. Check [this `api`](#). If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Prettier doesn't change this --> :::note @@ -110,7 +110,7 @@ Hello world You may also specify an optional title. ```md -:::note Your Title +:::note Your Title Some **content** with _Markdown_ `syntax`. @@ -138,7 +138,9 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -152,7 +154,9 @@ import TabItem from '@theme/TabItem'; ```mdx-code-block <BrowserWindow> -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> diff --git a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-react.mdx b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-react.mdx index 5bd883980e..da8e9fd86b 100644 --- a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-react.mdx +++ b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-react.mdx @@ -76,7 +76,7 @@ I can write **Markdown** alongside my _JSX_! Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx /* Instead of this: */ <span style="background-color: red">Foo</span> @@ -94,7 +94,7 @@ In addition, MDX is not [100% compatible with CommonMark](https://github.com/fac You can also import your own components defined in other files or third-party components installed via npm. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Docusaurus theme component --> import TOCInline from '@theme/TOCInline'; @@ -341,7 +341,7 @@ Use JSX within JSX tag, or move the Markdown to the outer layer: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> **Bold still doesn't work** @@ -367,7 +367,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -397,7 +397,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -427,7 +427,7 @@ Don't indent: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -463,14 +463,13 @@ npm install --save raw-loader Now you can import code snippets from another file as it is: -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="myMarkdownFile.mdx" import CodeBlock from '@theme/CodeBlock'; import MyComponentSource from '!!raw-loader!./myComponent'; <CodeBlock language="jsx">{MyComponentSource}</CodeBlock> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import CodeBlock from '@theme/CodeBlock'; @@ -509,13 +508,12 @@ By convention, using the **`_` filename prefix** will not create any doc page an This is text some content from `_markdown-partial-example.mdx`. ``` -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="someOtherDoc.mdx" import PartialExample from './_markdown-partial-example.mdx'; <PartialExample name="Sebastien" /> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import PartialExample from './_markdown-partial-example.mdx'; diff --git a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-tabs.mdx index 897f54a8a7..987f1067a3 100644 --- a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-tabs.mdx @@ -15,7 +15,7 @@ import styles from './markdown-features-tabs-styles.module.css'; Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx): -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -32,7 +32,6 @@ import TabItem from '@theme/TabItem'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```mdx-code-block <BrowserWindow> @@ -250,7 +249,7 @@ You might want to customize the appearance of a certain set of tabs. You can pas You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`. -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="some-doc.mdx" import styles from './styles.module.css'; @@ -266,7 +265,6 @@ import styles from './styles.module.css'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```css title="styles.module.css" .red { diff --git a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-toc.mdx b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-toc.mdx index 4b2857c4f7..b1b6507f25 100644 --- a/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-toc.mdx +++ b/website/versioned_docs/version-2.1.0/guides/markdown-features/markdown-features-toc.mdx @@ -43,8 +43,8 @@ Generated IDs have **some limitations**: A special Markdown syntax lets you set an **explicit heading id**: -```md -### Hello World {#my-explicit-id} +```mdx-code-block +<Code language="md">{'### Hello World \u007B#my-explicit-id}\n'}</Code> ``` :::tip @@ -102,7 +102,7 @@ It is also possible to display an inline table of contents directly inside a Mar The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; @@ -129,7 +129,7 @@ declare const toc: { Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; diff --git a/website/versioned_docs/version-2.1.0/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.1.0/i18n/i18n-crowdin.mdx index 104b636a7b..455d68c157 100644 --- a/website/versioned_docs/version-2.1.0/i18n/i18n-crowdin.mdx +++ b/website/versioned_docs/version-2.1.0/i18n/i18n-crowdin.mdx @@ -351,7 +351,7 @@ We recommend extracting the complex embedded JSX code as separate standalone com To deploy Docusaurus, run the following command: -````mdx-code-block +````mdx-code-block  import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/website/versioned_docs/version-2.1.0/introduction.mdx b/website/versioned_docs/version-2.1.0/introduction.mdx index 46b616c7d5..a03b487c78 100644 --- a/website/versioned_docs/version-2.1.0/introduction.mdx +++ b/website/versioned_docs/version-2.1.0/introduction.mdx @@ -55,7 +55,6 @@ import LiteYouTubeEmbed from 'react-lite-youtube-embed'; <div className="video-container"> <LiteYouTubeEmbed - // cSpell:ignore Yhyx Sksg id="Yhyx7otSksg" params="autoplay=1&autohide=1&showinfo=0&rel=0" title="Docusaurus: Documentation Made Easy" @@ -129,18 +128,6 @@ Docusaurus 2 is born to be compassionately accessible to all your users, and lig We believe that, as developers, knowing how a library works helps us become better at using it. Hence we're dedicating effort to explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it. -<!-- - -Explain the principles that guide the development of Docusaurus. - -References ---- -- https://www.gatsbyjs.org/docs/behind-the-scenes/ -- https://reactjs.org/docs/design-principles.html -- https://v1.vuepress.vuejs.org/miscellaneous/design-concepts.html - ---> - ## Comparison with other tools {#comparison-with-other-tools} Across all static site generators, Docusaurus has a unique focus on documentation sites and has many out-of-the-box features. diff --git a/website/versioned_docs/version-2.1.0/search.mdx b/website/versioned_docs/version-2.1.0/search.mdx index 66e6b3c13a..c1dad98ff9 100644 --- a/website/versioned_docs/version-2.1.0/search.mdx +++ b/website/versioned_docs/version-2.1.0/search.mdx @@ -241,7 +241,7 @@ Still, you can reuse the [Infima CSS variables](styling-layout.mdx#styling-your- ### Customizing the Algolia search behavior {#customizing-the-algolia-search-behavior} -<!-- TODO: update options link once the documentation is available on the DocSearch website --> +{/* TODO: update options link once the documentation is available on the DocSearch website */} Algolia DocSearch supports a [list of options](https://autocomplete-experimental.netlify.app/docs/DocSearchModal#reference) that you can pass to the `algolia` field in the `docusaurus.config.js` file. diff --git a/website/versioned_docs/version-2.2.0/api/docusaurus.config.js.mdx b/website/versioned_docs/version-2.2.0/api/docusaurus.config.js.mdx index 052baa5b06..0601b2e39e 100644 --- a/website/versioned_docs/version-2.2.0/api/docusaurus.config.js.mdx +++ b/website/versioned_docs/version-2.2.0/api/docusaurus.config.js.mdx @@ -123,7 +123,7 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction. Example: -<!-- cSpell:ignore فارسی --> +{/* cSpell:ignore فارسی */} ```js title="docusaurus.config.js" module.exports = { diff --git a/website/versioned_docs/version-2.2.0/api/plugins/plugin-content-blog.mdx b/website/versioned_docs/version-2.2.0/api/plugins/plugin-content-blog.mdx index 38119b6da8..b20a58284b 100644 --- a/website/versioned_docs/version-2.2.0/api/plugins/plugin-content-blog.mdx +++ b/website/versioned_docs/version-2.2.0/api/plugins/plugin-content-blog.mdx @@ -68,7 +68,7 @@ Accepted fields: | `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. | | `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | -| `feedOptions.description` | `string` | <code>\`${siteConfig.title} Blog\`</code> | Description of the feed. | +| `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. | | `feedOptions.copyright` | `string` | `undefined` | Copyright message. | | `feedOptions.language` | `string` (See [documentation](http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes) for possible values) | `undefined` | Language metadata of the feed. | | `sortPosts` | <code>'descending' \| 'ascending' </code> | `'descending'` | Governs the direction of blog post sorting. | diff --git a/website/versioned_docs/version-2.2.0/blog.mdx b/website/versioned_docs/version-2.2.0/blog.mdx index a2262e2f11..cc91a00324 100644 --- a/website/versioned_docs/version-2.2.0/blog.mdx +++ b/website/versioned_docs/version-2.2.0/blog.mdx @@ -63,7 +63,7 @@ hide_table_of_contents: false Welcome to this blog. This blog is created with [**Docusaurus 2**](https://docusaurus.io/). -<!--truncate--> +<!-- truncate --> This is my first post on Docusaurus 2. diff --git a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-admonitions.mdx b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-admonitions.mdx index f4c00f7c3f..9957822ebf 100644 --- a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,7 +87,7 @@ Some **content** with _Markdown_ `syntax`. Check [this `api`](#). If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Prettier doesn't change this --> :::note @@ -110,7 +110,7 @@ Hello world You may also specify an optional title. ```md -:::note Your Title +:::note Your Title Some **content** with _Markdown_ `syntax`. @@ -138,7 +138,9 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -152,7 +154,9 @@ import TabItem from '@theme/TabItem'; ```mdx-code-block <BrowserWindow> -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> diff --git a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-react.mdx b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-react.mdx index 5bd883980e..898208953d 100644 --- a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-react.mdx +++ b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-react.mdx @@ -76,7 +76,7 @@ I can write **Markdown** alongside my _JSX_! Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx /* Instead of this: */ <span style="background-color: red">Foo</span> @@ -94,7 +94,7 @@ In addition, MDX is not [100% compatible with CommonMark](https://github.com/fac You can also import your own components defined in other files or third-party components installed via npm. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Docusaurus theme component --> import TOCInline from '@theme/TOCInline'; @@ -341,7 +341,7 @@ Use JSX within JSX tag, or move the Markdown to the outer layer: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> **Bold still doesn't work** @@ -367,7 +367,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -397,7 +397,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -427,7 +427,7 @@ Don't indent: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -463,14 +463,13 @@ npm install --save raw-loader Now you can import code snippets from another file as it is: -<!-- prettier-ignore-start --> +<!-- prettier-ignore --> ```jsx title="myMarkdownFile.mdx" import CodeBlock from '@theme/CodeBlock'; import MyComponentSource from '!!raw-loader!./myComponent'; <CodeBlock language="jsx">{MyComponentSource}</CodeBlock> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import CodeBlock from '@theme/CodeBlock'; @@ -509,13 +508,12 @@ By convention, using the **`_` filename prefix** will not create any doc page an This is text some content from `_markdown-partial-example.mdx`. ``` -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="someOtherDoc.mdx" import PartialExample from './_markdown-partial-example.mdx'; <PartialExample name="Sebastien" /> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import PartialExample from './_markdown-partial-example.mdx'; diff --git a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-tabs.mdx index 897f54a8a7..987f1067a3 100644 --- a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-tabs.mdx @@ -15,7 +15,7 @@ import styles from './markdown-features-tabs-styles.module.css'; Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx): -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -32,7 +32,6 @@ import TabItem from '@theme/TabItem'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```mdx-code-block <BrowserWindow> @@ -250,7 +249,7 @@ You might want to customize the appearance of a certain set of tabs. You can pas You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`. -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="some-doc.mdx" import styles from './styles.module.css'; @@ -266,7 +265,6 @@ import styles from './styles.module.css'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```css title="styles.module.css" .red { diff --git a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-toc.mdx b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-toc.mdx index 4b2857c4f7..b1b6507f25 100644 --- a/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-toc.mdx +++ b/website/versioned_docs/version-2.2.0/guides/markdown-features/markdown-features-toc.mdx @@ -43,8 +43,8 @@ Generated IDs have **some limitations**: A special Markdown syntax lets you set an **explicit heading id**: -```md -### Hello World {#my-explicit-id} +```mdx-code-block +<Code language="md">{'### Hello World \u007B#my-explicit-id}\n'}</Code> ``` :::tip @@ -102,7 +102,7 @@ It is also possible to display an inline table of contents directly inside a Mar The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; @@ -129,7 +129,7 @@ declare const toc: { Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; diff --git a/website/versioned_docs/version-2.2.0/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.2.0/i18n/i18n-crowdin.mdx index 104b636a7b..455d68c157 100644 --- a/website/versioned_docs/version-2.2.0/i18n/i18n-crowdin.mdx +++ b/website/versioned_docs/version-2.2.0/i18n/i18n-crowdin.mdx @@ -351,7 +351,7 @@ We recommend extracting the complex embedded JSX code as separate standalone com To deploy Docusaurus, run the following command: -````mdx-code-block +````mdx-code-block  import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/website/versioned_docs/version-2.2.0/introduction.mdx b/website/versioned_docs/version-2.2.0/introduction.mdx index 46b616c7d5..a03b487c78 100644 --- a/website/versioned_docs/version-2.2.0/introduction.mdx +++ b/website/versioned_docs/version-2.2.0/introduction.mdx @@ -55,7 +55,6 @@ import LiteYouTubeEmbed from 'react-lite-youtube-embed'; <div className="video-container"> <LiteYouTubeEmbed - // cSpell:ignore Yhyx Sksg id="Yhyx7otSksg" params="autoplay=1&autohide=1&showinfo=0&rel=0" title="Docusaurus: Documentation Made Easy" @@ -129,18 +128,6 @@ Docusaurus 2 is born to be compassionately accessible to all your users, and lig We believe that, as developers, knowing how a library works helps us become better at using it. Hence we're dedicating effort to explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it. -<!-- - -Explain the principles that guide the development of Docusaurus. - -References ---- -- https://www.gatsbyjs.org/docs/behind-the-scenes/ -- https://reactjs.org/docs/design-principles.html -- https://v1.vuepress.vuejs.org/miscellaneous/design-concepts.html - ---> - ## Comparison with other tools {#comparison-with-other-tools} Across all static site generators, Docusaurus has a unique focus on documentation sites and has many out-of-the-box features. diff --git a/website/versioned_docs/version-2.2.0/search.mdx b/website/versioned_docs/version-2.2.0/search.mdx index 4febd41378..ddef7a4a09 100644 --- a/website/versioned_docs/version-2.2.0/search.mdx +++ b/website/versioned_docs/version-2.2.0/search.mdx @@ -241,7 +241,7 @@ Still, you can reuse the [Infima CSS variables](styling-layout.mdx#styling-your- ### Customizing the Algolia search behavior {#customizing-the-algolia-search-behavior} -<!-- TODO: update options link once the documentation is available on the DocSearch website --> +{/* TODO: update options link once the documentation is available on the DocSearch website */} Algolia DocSearch supports a [list of options](https://autocomplete-experimental.netlify.app/docs/DocSearchModal#reference) that you can pass to the `algolia` field in the `docusaurus.config.js` file. diff --git a/website/versioned_docs/version-2.3.1/api/docusaurus.config.js.mdx b/website/versioned_docs/version-2.3.1/api/docusaurus.config.js.mdx index 052baa5b06..0601b2e39e 100644 --- a/website/versioned_docs/version-2.3.1/api/docusaurus.config.js.mdx +++ b/website/versioned_docs/version-2.3.1/api/docusaurus.config.js.mdx @@ -123,7 +123,7 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction. Example: -<!-- cSpell:ignore فارسی --> +{/* cSpell:ignore فارسی */} ```js title="docusaurus.config.js" module.exports = { diff --git a/website/versioned_docs/version-2.3.1/api/plugins/plugin-content-blog.mdx b/website/versioned_docs/version-2.3.1/api/plugins/plugin-content-blog.mdx index b9677afcd8..e6ffc4d9b0 100644 --- a/website/versioned_docs/version-2.3.1/api/plugins/plugin-content-blog.mdx +++ b/website/versioned_docs/version-2.3.1/api/plugins/plugin-content-blog.mdx @@ -69,7 +69,7 @@ Accepted fields: | `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.createFeedItems` | <code><a href="#CreateFeedItemsFn">CreateFeedItemsFn</a> \| undefined</code> | `undefined` | An optional function which can be used to transform and / or filter the items in the feed. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | -| `feedOptions.description` | `string` | <code>\`${siteConfig.title} Blog\`</code> | Description of the feed. | +| `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. | | `feedOptions.copyright` | `string` | `undefined` | Copyright message. | | `feedOptions.language` | `string` (See [documentation](http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes) for possible values) | `undefined` | Language metadata of the feed. | | `sortPosts` | <code>'descending' \| 'ascending' </code> | `'descending'` | Governs the direction of blog post sorting. | diff --git a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-admonitions.mdx b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-admonitions.mdx index f4c00f7c3f..3bad5bb2ac 100644 --- a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,7 +87,7 @@ Some **content** with _Markdown_ `syntax`. Check [this `api`](#). If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Prettier doesn't change this --> :::note @@ -110,7 +110,7 @@ Hello world You may also specify an optional title. ```md -:::note Your Title +:::note Your Title Some **content** with _Markdown_ `syntax`. @@ -138,7 +138,9 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -152,7 +154,9 @@ import TabItem from '@theme/TabItem'; ```mdx-code-block <BrowserWindow> -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -197,10 +201,8 @@ The types that are accepted are the same as above: `note`, `tip`, `danger`, `inf ```mdx-code-block <BrowserWindow> <Admonition type="tip" icon="💡" title="Did you know..."> - <p> - Use plugins to introduce shorter syntax for the most commonly used JSX - elements in your project. - </p> + Use plugins to introduce shorter syntax for the most commonly used JSX + elements in your project. </Admonition> </BrowserWindow> ``` diff --git a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-react.mdx b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-react.mdx index 5bd883980e..431377b98b 100644 --- a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-react.mdx +++ b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-react.mdx @@ -64,8 +64,8 @@ export const Highlight = ({children, color}) => ( <BrowserWindow minHeight={240}> -<Highlight color="#25c2a0">Docusaurus green</Highlight> -{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors. +<><Highlight color="#25c2a0">Docusaurus green</Highlight> +{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.</> I can write **Markdown** alongside my _JSX_! @@ -76,7 +76,7 @@ I can write **Markdown** alongside my _JSX_! Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx /* Instead of this: */ <span style="background-color: red">Foo</span> @@ -94,7 +94,7 @@ In addition, MDX is not [100% compatible with CommonMark](https://github.com/fac You can also import your own components defined in other files or third-party components installed via npm. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Docusaurus theme component --> import TOCInline from '@theme/TOCInline'; @@ -341,7 +341,7 @@ Use JSX within JSX tag, or move the Markdown to the outer layer: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> **Bold still doesn't work** @@ -367,7 +367,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -397,7 +397,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -427,7 +427,7 @@ Don't indent: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -463,14 +463,13 @@ npm install --save raw-loader Now you can import code snippets from another file as it is: -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="myMarkdownFile.mdx" import CodeBlock from '@theme/CodeBlock'; import MyComponentSource from '!!raw-loader!./myComponent'; <CodeBlock language="jsx">{MyComponentSource}</CodeBlock> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import CodeBlock from '@theme/CodeBlock'; @@ -509,13 +508,12 @@ By convention, using the **`_` filename prefix** will not create any doc page an This is text some content from `_markdown-partial-example.mdx`. ``` -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="someOtherDoc.mdx" import PartialExample from './_markdown-partial-example.mdx'; <PartialExample name="Sebastien" /> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import PartialExample from './_markdown-partial-example.mdx'; diff --git a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-tabs.mdx index 948c61ef67..4f9973d557 100644 --- a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-tabs.mdx @@ -15,7 +15,7 @@ import styles from './markdown-features-tabs-styles.module.css'; Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx): -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -32,7 +32,6 @@ import TabItem from '@theme/TabItem'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```mdx-code-block <BrowserWindow> @@ -250,7 +249,7 @@ You might want to customize the appearance of a certain set of tabs. You can pas You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`. -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="some-doc.mdx" import styles from './styles.module.css'; @@ -266,7 +265,6 @@ import styles from './styles.module.css'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```css title="styles.module.css" .red { diff --git a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-toc.mdx b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-toc.mdx index 4b2857c4f7..b1b6507f25 100644 --- a/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-toc.mdx +++ b/website/versioned_docs/version-2.3.1/guides/markdown-features/markdown-features-toc.mdx @@ -43,8 +43,8 @@ Generated IDs have **some limitations**: A special Markdown syntax lets you set an **explicit heading id**: -```md -### Hello World {#my-explicit-id} +```mdx-code-block +<Code language="md">{'### Hello World \u007B#my-explicit-id}\n'}</Code> ``` :::tip @@ -102,7 +102,7 @@ It is also possible to display an inline table of contents directly inside a Mar The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; @@ -129,7 +129,7 @@ declare const toc: { Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; diff --git a/website/versioned_docs/version-2.3.1/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.3.1/i18n/i18n-crowdin.mdx index 104b636a7b..455d68c157 100644 --- a/website/versioned_docs/version-2.3.1/i18n/i18n-crowdin.mdx +++ b/website/versioned_docs/version-2.3.1/i18n/i18n-crowdin.mdx @@ -351,7 +351,7 @@ We recommend extracting the complex embedded JSX code as separate standalone com To deploy Docusaurus, run the following command: -````mdx-code-block +````mdx-code-block  import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/website/versioned_docs/version-2.3.1/introduction.mdx b/website/versioned_docs/version-2.3.1/introduction.mdx index 46b616c7d5..2aeeba0948 100644 --- a/website/versioned_docs/version-2.3.1/introduction.mdx +++ b/website/versioned_docs/version-2.3.1/introduction.mdx @@ -53,9 +53,10 @@ In this presentation at [Algolia Community Event](https://www.algolia.com/), [Me ```mdx-code-block import LiteYouTubeEmbed from 'react-lite-youtube-embed'; +{/* cSpell:ignore Yhyx Sksg */} + <div className="video-container"> <LiteYouTubeEmbed - // cSpell:ignore Yhyx Sksg id="Yhyx7otSksg" params="autoplay=1&autohide=1&showinfo=0&rel=0" title="Docusaurus: Documentation Made Easy" @@ -129,18 +130,6 @@ Docusaurus 2 is born to be compassionately accessible to all your users, and lig We believe that, as developers, knowing how a library works helps us become better at using it. Hence we're dedicating effort to explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it. -<!-- - -Explain the principles that guide the development of Docusaurus. - -References ---- -- https://www.gatsbyjs.org/docs/behind-the-scenes/ -- https://reactjs.org/docs/design-principles.html -- https://v1.vuepress.vuejs.org/miscellaneous/design-concepts.html - ---> - ## Comparison with other tools {#comparison-with-other-tools} Across all static site generators, Docusaurus has a unique focus on documentation sites and has many out-of-the-box features. diff --git a/website/versioned_docs/version-2.3.1/search.mdx b/website/versioned_docs/version-2.3.1/search.mdx index 32fdcd7f68..78f785bca0 100644 --- a/website/versioned_docs/version-2.3.1/search.mdx +++ b/website/versioned_docs/version-2.3.1/search.mdx @@ -247,7 +247,7 @@ Still, you can reuse the [Infima CSS variables](styling-layout.mdx#styling-your- ### Customizing the Algolia search behavior {#customizing-the-algolia-search-behavior} -<!-- TODO: update options link once the documentation is available on the DocSearch website --> +{/* TODO: update options link once the documentation is available on the DocSearch website */} Algolia DocSearch supports a [list of options](https://autocomplete-experimental.netlify.app/docs/DocSearchModal#reference) that you can pass to the `algolia` field in the `docusaurus.config.js` file. diff --git a/website/versioned_docs/version-2.4.0/api/plugins/plugin-content-blog.mdx b/website/versioned_docs/version-2.4.0/api/plugins/plugin-content-blog.mdx index b9677afcd8..e6ffc4d9b0 100644 --- a/website/versioned_docs/version-2.4.0/api/plugins/plugin-content-blog.mdx +++ b/website/versioned_docs/version-2.4.0/api/plugins/plugin-content-blog.mdx @@ -69,7 +69,7 @@ Accepted fields: | `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.createFeedItems` | <code><a href="#CreateFeedItemsFn">CreateFeedItemsFn</a> \| undefined</code> | `undefined` | An optional function which can be used to transform and / or filter the items in the feed. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | -| `feedOptions.description` | `string` | <code>\`${siteConfig.title} Blog\`</code> | Description of the feed. | +| `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. | | `feedOptions.copyright` | `string` | `undefined` | Copyright message. | | `feedOptions.language` | `string` (See [documentation](http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes) for possible values) | `undefined` | Language metadata of the feed. | | `sortPosts` | <code>'descending' \| 'ascending' </code> | `'descending'` | Governs the direction of blog post sorting. | diff --git a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-admonitions.mdx b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-admonitions.mdx index f4c00f7c3f..3bad5bb2ac 100644 --- a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,7 +87,7 @@ Some **content** with _Markdown_ `syntax`. Check [this `api`](#). If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Prettier doesn't change this --> :::note @@ -110,7 +110,7 @@ Hello world You may also specify an optional title. ```md -:::note Your Title +:::note Your Title Some **content** with _Markdown_ `syntax`. @@ -138,7 +138,9 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -152,7 +154,9 @@ import TabItem from '@theme/TabItem'; ```mdx-code-block <BrowserWindow> -:::tip Use tabs in admonitions +:::tip + +Use tabs in admonitions <Tabs> <TabItem value="apple" label="Apple">This is an apple 🍎</TabItem> @@ -197,10 +201,8 @@ The types that are accepted are the same as above: `note`, `tip`, `danger`, `inf ```mdx-code-block <BrowserWindow> <Admonition type="tip" icon="💡" title="Did you know..."> - <p> - Use plugins to introduce shorter syntax for the most commonly used JSX - elements in your project. - </p> + Use plugins to introduce shorter syntax for the most commonly used JSX + elements in your project. </Admonition> </BrowserWindow> ``` diff --git a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-react.mdx b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-react.mdx index 5bd883980e..431377b98b 100644 --- a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-react.mdx +++ b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-react.mdx @@ -64,8 +64,8 @@ export const Highlight = ({children, color}) => ( <BrowserWindow minHeight={240}> -<Highlight color="#25c2a0">Docusaurus green</Highlight> -{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors. +<><Highlight color="#25c2a0">Docusaurus green</Highlight> +{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.</> I can write **Markdown** alongside my _JSX_! @@ -76,7 +76,7 @@ I can write **Markdown** alongside my _JSX_! Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx /* Instead of this: */ <span style="background-color: red">Foo</span> @@ -94,7 +94,7 @@ In addition, MDX is not [100% compatible with CommonMark](https://github.com/fac You can also import your own components defined in other files or third-party components installed via npm. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```md <!-- Docusaurus theme component --> import TOCInline from '@theme/TOCInline'; @@ -341,7 +341,7 @@ Use JSX within JSX tag, or move the Markdown to the outer layer: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> **Bold still doesn't work** @@ -367,7 +367,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -397,7 +397,7 @@ Add an empty new line: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -427,7 +427,7 @@ Don't indent: <div className={styles.wrappingBlock}> ``` -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx <div style={{color: 'red'}}> @@ -463,14 +463,13 @@ npm install --save raw-loader Now you can import code snippets from another file as it is: -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="myMarkdownFile.mdx" import CodeBlock from '@theme/CodeBlock'; import MyComponentSource from '!!raw-loader!./myComponent'; <CodeBlock language="jsx">{MyComponentSource}</CodeBlock> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import CodeBlock from '@theme/CodeBlock'; @@ -509,13 +508,12 @@ By convention, using the **`_` filename prefix** will not create any doc page an This is text some content from `_markdown-partial-example.mdx`. ``` -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="someOtherDoc.mdx" import PartialExample from './_markdown-partial-example.mdx'; <PartialExample name="Sebastien" /> ``` -<!-- prettier-ignore-end --> ```mdx-code-block import PartialExample from './_markdown-partial-example.mdx'; diff --git a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-tabs.mdx index 948c61ef67..4f9973d557 100644 --- a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-tabs.mdx @@ -15,7 +15,7 @@ import styles from './markdown-features-tabs-styles.module.css'; Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx): -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -32,7 +32,6 @@ import TabItem from '@theme/TabItem'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```mdx-code-block <BrowserWindow> @@ -250,7 +249,7 @@ You might want to customize the appearance of a certain set of tabs. You can pas You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`. -<!-- prettier-ignore-start --> +{/* prettier-ignore */} ```jsx title="some-doc.mdx" import styles from './styles.module.css'; @@ -266,7 +265,6 @@ import styles from './styles.module.css'; </TabItem> </Tabs> ``` -<!-- prettier-ignore-end --> ```css title="styles.module.css" .red { diff --git a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-toc.mdx b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-toc.mdx index 4b2857c4f7..b1b6507f25 100644 --- a/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-toc.mdx +++ b/website/versioned_docs/version-2.4.0/guides/markdown-features/markdown-features-toc.mdx @@ -43,8 +43,8 @@ Generated IDs have **some limitations**: A special Markdown syntax lets you set an **explicit heading id**: -```md -### Hello World {#my-explicit-id} +```mdx-code-block +<Code language="md">{'### Hello World \u007B#my-explicit-id}\n'}</Code> ``` :::tip @@ -102,7 +102,7 @@ It is also possible to display an inline table of contents directly inside a Mar The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; @@ -129,7 +129,7 @@ declare const toc: { Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. -<!-- prettier-ignore --> +{/* prettier-ignore */} ```jsx import TOCInline from '@theme/TOCInline'; diff --git a/website/versioned_docs/version-2.4.0/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.4.0/i18n/i18n-crowdin.mdx index 104b636a7b..455d68c157 100644 --- a/website/versioned_docs/version-2.4.0/i18n/i18n-crowdin.mdx +++ b/website/versioned_docs/version-2.4.0/i18n/i18n-crowdin.mdx @@ -351,7 +351,7 @@ We recommend extracting the complex embedded JSX code as separate standalone com To deploy Docusaurus, run the following command: -````mdx-code-block +````mdx-code-block  import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/website/versioned_docs/version-2.4.0/introduction.mdx b/website/versioned_docs/version-2.4.0/introduction.mdx index 46b616c7d5..383563a61f 100644 --- a/website/versioned_docs/version-2.4.0/introduction.mdx +++ b/website/versioned_docs/version-2.4.0/introduction.mdx @@ -50,12 +50,13 @@ Or read the **[5-minute tutorial](https://tutorial.docusaurus.io)** online. In this presentation at [Algolia Community Event](https://www.algolia.com/), [Meta Open Source team](https://opensource.facebook.com/) shared a brief walk-through of Docusaurus. They covered how to get started with the project, enable plugins, and set up functionalities like documentation and blogging. +{/* cSpell:ignore Yhyx Sksg */} + ```mdx-code-block import LiteYouTubeEmbed from 'react-lite-youtube-embed'; <div className="video-container"> <LiteYouTubeEmbed - // cSpell:ignore Yhyx Sksg id="Yhyx7otSksg" params="autoplay=1&autohide=1&showinfo=0&rel=0" title="Docusaurus: Documentation Made Easy" @@ -129,18 +130,6 @@ Docusaurus 2 is born to be compassionately accessible to all your users, and lig We believe that, as developers, knowing how a library works helps us become better at using it. Hence we're dedicating effort to explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it. -<!-- - -Explain the principles that guide the development of Docusaurus. - -References ---- -- https://www.gatsbyjs.org/docs/behind-the-scenes/ -- https://reactjs.org/docs/design-principles.html -- https://v1.vuepress.vuejs.org/miscellaneous/design-concepts.html - ---> - ## Comparison with other tools {#comparison-with-other-tools} Across all static site generators, Docusaurus has a unique focus on documentation sites and has many out-of-the-box features. diff --git a/website/versioned_docs/version-2.4.0/search.mdx b/website/versioned_docs/version-2.4.0/search.mdx index 32fdcd7f68..78f785bca0 100644 --- a/website/versioned_docs/version-2.4.0/search.mdx +++ b/website/versioned_docs/version-2.4.0/search.mdx @@ -247,7 +247,7 @@ Still, you can reuse the [Infima CSS variables](styling-layout.mdx#styling-your- ### Customizing the Algolia search behavior {#customizing-the-algolia-search-behavior} -<!-- TODO: update options link once the documentation is available on the DocSearch website --> +{/* TODO: update options link once the documentation is available on the DocSearch website */} Algolia DocSearch supports a [list of options](https://autocomplete-experimental.netlify.app/docs/DocSearchModal#reference) that you can pass to the `algolia` field in the `docusaurus.config.js` file. diff --git a/yarn.lock b/yarn.lock index a6a6a24992..4bededa789 100644 --- a/yarn.lock +++ b/yarn.lock @@ -159,28 +159,6 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== -"@babel/core@7.12.9": - version "7.12.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" - integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.5" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.5" - "@babel/parser" "^7.12.7" - "@babel/template" "^7.12.7" - "@babel/traverse" "^7.12.9" - "@babel/types" "^7.12.7" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - "@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.19.6", "@babel/core@^7.20.12": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" @@ -211,7 +189,7 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.12.5", "@babel/generator@^7.21.0", "@babel/generator@^7.21.1", "@babel/generator@^7.7.2": +"@babel/generator@^7.21.0", "@babel/generator@^7.21.1", "@babel/generator@^7.7.2": version "7.21.1" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== @@ -322,7 +300,7 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.0", "@babel/helper-module-transforms@^7.21.2": +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.0", "@babel/helper-module-transforms@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== @@ -343,11 +321,6 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-plugin-utils@7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" @@ -421,7 +394,7 @@ "@babel/traverse" "^7.20.5" "@babel/types" "^7.20.5" -"@babel/helpers@^7.12.5", "@babel/helpers@^7.21.0": +"@babel/helpers@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== @@ -439,7 +412,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2": +"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== @@ -535,15 +508,6 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" - integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-proposal-object-rest-spread@^7.20.2": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" @@ -668,13 +632,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926" - integrity sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.7.2": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" @@ -703,7 +660,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== @@ -924,7 +881,7 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/helper-replace-supers" "^7.18.6" -"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7": +"@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz#0ee349e9d1bc96e78e3b37a7af423a4078a7083f" integrity sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA== @@ -1218,7 +1175,7 @@ dependencies: regenerator-runtime "^0.13.11" -"@babel/template@^7.12.7", "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": +"@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== @@ -1227,7 +1184,7 @@ "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.7.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75" integrity sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw== @@ -1243,7 +1200,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.7", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== @@ -2025,40 +1982,36 @@ stringify-entities "^3.0.1" stringify-object "^3.3.0" -"@mdx-js/mdx@^1.6.22": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" - integrity sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA== +"@mdx-js/mdx@^2.1.5": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-2.3.0.tgz#d65d8c3c28f3f46bb0e7cb3bf7613b39980671a9" + integrity sha512-jLuwRlz8DQfQNiUCJR50Y09CGPq3fLtmtUQfVrj79E0JWu3dvsVcxVIcfhR5h0iXu+/z++zDrYeiJqifRynJkA== dependencies: - "@babel/core" "7.12.9" - "@babel/plugin-syntax-jsx" "7.12.1" - "@babel/plugin-syntax-object-rest-spread" "7.8.3" - "@mdx-js/util" "1.6.22" - babel-plugin-apply-mdx-type-prop "1.6.22" - babel-plugin-extract-import-names "1.6.22" - camelcase-css "2.0.1" - detab "2.0.4" - hast-util-raw "6.0.1" - lodash.uniq "4.5.0" - mdast-util-to-hast "10.0.1" - remark-footnotes "2.0.0" - remark-mdx "1.6.22" - remark-parse "8.0.3" - remark-squeeze-paragraphs "4.0.0" - style-to-object "0.3.0" - unified "9.2.0" - unist-builder "2.0.3" - unist-util-visit "2.0.3" + "@types/estree-jsx" "^1.0.0" + "@types/mdx" "^2.0.0" + estree-util-build-jsx "^2.0.0" + estree-util-is-identifier-name "^2.0.0" + estree-util-to-js "^1.1.0" + estree-walker "^3.0.0" + hast-util-to-estree "^2.0.0" + markdown-extensions "^1.0.0" + periscopic "^3.0.0" + remark-mdx "^2.0.0" + remark-parse "^10.0.0" + remark-rehype "^10.0.0" + unified "^10.0.0" + unist-util-position-from-estree "^1.0.0" + unist-util-stringify-position "^3.0.0" + unist-util-visit "^4.0.0" + vfile "^5.0.0" -"@mdx-js/react@^1.6.22": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" - integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== - -"@mdx-js/util@1.6.22": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" - integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== +"@mdx-js/react@^2.1.5": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-2.3.0.tgz#4208bd6d70f0d0831def28ef28c26149b03180b3" + integrity sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g== + dependencies: + "@types/mdx" "^2.0.0" + "@types/react" ">=16" "@netlify/functions@^1.4.0": version "1.4.0" @@ -2848,6 +2801,13 @@ resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-1.0.6.tgz#7305a7fa590decc0d5968500234e95fd68788978" integrity sha512-1QxDaP54hpzM6bq9E+yFEo4F9WbWHhsDe4vktZXF/iDlc9FqGr9qlg+3X/nuKQXx8QxHV7ue8NXFazzajsxFBA== +"@types/acorn@^4.0.0": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22" + integrity sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ== + dependencies: + "@types/estree" "*" + "@types/babel__core@^7.1.14": version "7.20.0" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" @@ -2955,6 +2915,13 @@ dependencies: "@types/node" "*" +"@types/debug@^4.0.0": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + "@types/dedent@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@types/dedent/-/dedent-0.7.0.tgz#155f339ca404e6dd90b9ce46a3f78fd69ca9b050" @@ -2986,7 +2953,14 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*": +"@types/estree-jsx@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.0.tgz#7bfc979ab9f692b492017df42520f7f765e98df1" + integrity sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ== + dependencies: + "@types/estree" "*" + +"@types/estree@*", "@types/estree@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== @@ -3189,6 +3163,11 @@ dependencies: "@types/react" "*" +"@types/mdx@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.3.tgz#43fd32414f17fcbeced3578109a6edd877a2d96e" + integrity sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ== + "@types/micromatch@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/micromatch/-/micromatch-4.0.2.tgz#ce29c8b166a73bf980a5727b1e4a4d099965151d" @@ -3216,6 +3195,11 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + "@types/node@*", "@types/node@^18.11.18": version "18.14.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.6.tgz#ae1973dd2b1eeb1825695bb11ebfb746d27e3e93" @@ -3335,7 +3319,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.0.28": +"@types/react@*", "@types/react@>=16", "@types/react@^18.0.28": version "18.0.28" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.28.tgz#accaeb8b86f4908057ad629a26635fe641480065" integrity sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew== @@ -3476,7 +3460,7 @@ dependencies: source-map "^0.6.1" -"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3", "@types/unist@^2.0.6": +"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.6": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== @@ -3847,7 +3831,7 @@ acorn-import-assertions@^1.7.6: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== -acorn-jsx@^5.0.1, acorn-jsx@^5.3.2: +acorn-jsx@^5.0.0, acorn-jsx@^5.0.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -3862,7 +3846,7 @@ acorn@^6.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== -acorn@^8.0.4, acorn@^8.1.0, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0, acorn@^8.8.1: +acorn@^8.0.0, acorn@^8.0.4, acorn@^8.1.0, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0, acorn@^8.8.1: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== @@ -4186,6 +4170,11 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +astring@^1.8.0: + version "1.8.4" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.8.4.tgz#6d4c5d8de7be2ead9e4a3cc0e2efb8d759378904" + integrity sha512-97a+l2LBU3Op3bBQEff79i/E4jMD2ZLFD8rHx9B6mXyB2uQwhJQYfiDqUwtfjF4QA1F2qs//N6Cw8LetMbQjcw== + async@^3.2.3: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" @@ -4273,14 +4262,6 @@ babel-loader@^9.1.2: find-cache-dir "^3.3.2" schema-utils "^4.0.0" -babel-plugin-apply-mdx-type-prop@1.6.22: - version "1.6.22" - resolved "https://registry.yarnpkg.com/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz#d216e8fd0de91de3f1478ef3231e05446bc8705b" - integrity sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ== - dependencies: - "@babel/helper-plugin-utils" "7.10.4" - "@mdx-js/util" "1.6.22" - babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -4288,13 +4269,6 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" -babel-plugin-extract-import-names@1.6.22: - version "1.6.22" - resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc" - integrity sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ== - dependencies: - "@babel/helper-plugin-utils" "7.10.4" - babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" @@ -4366,11 +4340,6 @@ babel-preset-jest@^29.5.0: babel-plugin-jest-hoist "^29.5.0" babel-preset-current-node-syntax "^1.0.0" -bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== - bail@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" @@ -4714,7 +4683,7 @@ camel-case@^4.1.2: pascal-case "^3.1.2" tslib "^2.0.3" -camelcase-css@2.0.1, camelcase-css@^2.0.1: +camelcase-css@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== @@ -4763,6 +4732,11 @@ ccount@^1.0.0: resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== +ccount@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" + integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== + chainsaw@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" @@ -4810,21 +4784,41 @@ character-entities-html4@^1.0.0: resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.4.tgz#0e64b0a3753ddbf1fdc044c5fd01d0199a02e125" integrity sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g== +character-entities-html4@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" + integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== + character-entities-legacy@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== +character-entities-legacy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" + integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== + character-entities@^1.0.0: version "1.2.4" resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== +character-entities@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" + integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== + character-reference-invalid@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== +character-reference-invalid@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" + integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -6160,7 +6154,7 @@ debug@2.6.9, debug@^2.6.0: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -6197,6 +6191,13 @@ decimal.js@^10.4.2: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== +decode-named-character-reference@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" + integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== + dependencies: + character-entities "^2.0.0" + decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" @@ -6335,18 +6336,16 @@ deprecation@^2.0.0, deprecation@^2.3.1: resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +dequal@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detab@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43" - integrity sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g== - dependencies: - repeat-string "^1.5.4" - detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" @@ -6396,6 +6395,11 @@ diff-sequences@^29.4.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== +diff@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" + integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -6789,6 +6793,11 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + escodegen@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" @@ -7061,11 +7070,64 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-util-attach-comments@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-2.1.1.tgz#ee44f4ff6890ee7dfb3237ac7810154c94c63f84" + integrity sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w== + dependencies: + "@types/estree" "^1.0.0" + +estree-util-build-jsx@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-2.2.2.tgz#32f8a239fb40dc3f3dca75bb5dcf77a831e4e47b" + integrity sha512-m56vOXcOBuaF+Igpb9OPAy7f9w9OIkb5yhjsZuaPm7HoGi4oTOQi0h2+yZ+AtKklYFZ+rPC4n0wYCJCEU1ONqg== + dependencies: + "@types/estree-jsx" "^1.0.0" + estree-util-is-identifier-name "^2.0.0" + estree-walker "^3.0.0" + +estree-util-is-identifier-name@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.1.0.tgz#fb70a432dcb19045e77b05c8e732f1364b4b49b2" + integrity sha512-bEN9VHRyXAUOjkKVQVvArFym08BTWB0aJPppZZr0UNyAqWsLaVfAqP7hbaTJjzHifmB5ebnR8Wm7r7yGN/HonQ== + +estree-util-to-js@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/estree-util-to-js/-/estree-util-to-js-1.2.0.tgz#0f80d42443e3b13bd32f7012fffa6f93603f4a36" + integrity sha512-IzU74r1PK5IMMGZXUVZbmiu4A1uhiPgW5hm1GjcOfr4ZzHaMPpLNJjR7HjXiIOzi25nZDrgFTobHTkV5Q6ITjA== + dependencies: + "@types/estree-jsx" "^1.0.0" + astring "^1.8.0" + source-map "^0.7.0" + +estree-util-value-to-estree@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/estree-util-value-to-estree/-/estree-util-value-to-estree-2.1.0.tgz#a10cdb500ee002bec36e13f2cd8c7838e6347dbe" + integrity sha512-fcAWmZilY1+tEt7GSeLZoHDvp2NNgLkJznBRYkEpaholas41d+Y0zd/Acch7+qzZdxLtxLi+m04KjHFJSoMa6A== + dependencies: + "@types/estree" "^1.0.0" + is-plain-obj "^4.0.0" + +estree-util-visit@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-1.2.1.tgz#8bc2bc09f25b00827294703835aabee1cc9ec69d" + integrity sha512-xbgqcrkIVbIG+lI/gzbvd9SGTJL4zqJKBFttUl5pP27KhAjtMKbX/mQXJ7qgyXpMgVy/zvpm0xoQQaGL8OloOw== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/unist" "^2.0.0" + estree-walker@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== +estree-walker@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -7639,7 +7701,7 @@ gensequence@^5.0.2: resolved "https://registry.yarnpkg.com/gensequence/-/gensequence-5.0.2.tgz#f065be2f9a5b2967b9cad7f33b2d79ce1f22dc82" integrity sha512-JlKEZnFc6neaeSVlkzBGGgkIoIaSxMgvdamRoPN8r3ozm2r9dusqxeKqYQ7lhzmj2UhFQP8nkyfCaiLQxiLrDA== -gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: +gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== @@ -8030,19 +8092,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hast-to-hyperscript@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" - integrity sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA== - dependencies: - "@types/unist" "^2.0.3" - comma-separated-tokens "^1.0.0" - property-information "^5.3.0" - space-separated-tokens "^1.0.0" - style-to-object "^0.3.0" - unist-util-is "^4.0.0" - web-namespaces "^1.0.0" - hast-util-from-parse5@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz#554e34abdeea25ac76f5bd950a1f0180e0b3bc2a" @@ -8093,21 +8142,26 @@ hast-util-parse-selector@^3.0.0: dependencies: "@types/hast" "^2.0.0" -hast-util-raw@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-6.0.1.tgz#973b15930b7529a7b66984c98148b46526885977" - integrity sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig== +hast-util-to-estree@^2.0.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-2.3.2.tgz#11ab0cd2e70ecf0305151af56e636b1cdfbba0bf" + integrity sha512-YYDwATNdnvZi3Qi84iatPIl1lWpXba1MeNrNbDfJfVzEBZL8uUmtR7mt7bxKBC8kuAuvb0bkojXYZzsNHyHCLg== dependencies: + "@types/estree" "^1.0.0" + "@types/estree-jsx" "^1.0.0" "@types/hast" "^2.0.0" - hast-util-from-parse5 "^6.0.0" - hast-util-to-parse5 "^6.0.0" - html-void-elements "^1.0.0" - parse5 "^6.0.0" - unist-util-position "^3.0.0" - vfile "^4.0.0" - web-namespaces "^1.0.0" - xtend "^4.0.0" - zwitch "^1.0.0" + "@types/unist" "^2.0.0" + comma-separated-tokens "^2.0.0" + estree-util-attach-comments "^2.0.0" + estree-util-is-identifier-name "^2.0.0" + hast-util-whitespace "^2.0.0" + mdast-util-mdx-expression "^1.0.0" + mdast-util-mdxjs-esm "^1.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^0.4.1" + unist-util-position "^4.0.0" + zwitch "^2.0.0" hast-util-to-html@^7.1.1: version "7.1.3" @@ -8125,17 +8179,6 @@ hast-util-to-html@^7.1.1: unist-util-is "^4.0.0" xtend "^4.0.0" -hast-util-to-parse5@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz#1ec44650b631d72952066cea9b1445df699f8479" - integrity sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ== - dependencies: - hast-to-hyperscript "^9.0.0" - property-information "^5.0.0" - web-namespaces "^1.0.0" - xtend "^4.0.0" - zwitch "^1.0.0" - hast-util-to-string@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz#9b24c114866bdb9478927d7e9c36a485ac728378" @@ -8156,6 +8199,11 @@ hast-util-whitespace@^1.0.0: resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz#e4fe77c4a9ae1cb2e6c25e02df0043d0164f6e41" integrity sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A== +hast-util-whitespace@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" + integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== + hastscript@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" @@ -8167,7 +8215,7 @@ hastscript@^6.0.0: property-information "^5.0.0" space-separated-tokens "^1.0.0" -hastscript@^7.0.0: +hastscript@^7.0.0, hastscript@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-7.2.0.tgz#0eafb7afb153d047077fa2a833dc9b7ec604d10b" integrity sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw== @@ -8662,11 +8710,16 @@ ipaddr.js@^2.0.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== -is-alphabetical@1.0.4, is-alphabetical@^1.0.0: +is-alphabetical@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== +is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + is-alphanumeric@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4" @@ -8680,6 +8733,14 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" +is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -8772,6 +8833,11 @@ is-decimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== +is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -8814,6 +8880,11 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== +is-hexadecimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" + integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== + is-installed-globally@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -8889,11 +8960,6 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== -is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - is-plain-obj@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" @@ -8926,6 +8992,13 @@ is-promise@^4.0.0: resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== +is-reference@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.1.tgz#d400f4260f7e55733955e60d361d827eb4d3b831" + integrity sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w== + dependencies: + "@types/estree" "*" + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -9754,6 +9827,13 @@ just-diff@^5.0.1: resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-5.2.0.tgz#60dca55891cf24cd4a094e33504660692348a241" integrity sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw== +katex@^0.13.0: + version "0.13.24" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.24.tgz#fe55455eb455698cb24b911a353d16a3c855d905" + integrity sha512-jZxYuKCma3VS5UuxOx/rFV1QyGSl3Uy/i0kTJF3HgQ5xMinCQVF8Zd4bMY/9aI9b9A2pjIBOsjSSm68ykTAr8w== + dependencies: + commander "^8.0.0" + katex@^0.15.0: version "0.15.6" resolved "https://registry.yarnpkg.com/katex/-/katex-0.15.6.tgz#c4e2f6ced2ac4de1ef6f737fe7c67d3026baa0e5" @@ -9788,6 +9868,11 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kleur@^4.0.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + klona@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" @@ -10137,12 +10222,12 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash.uniq@4.5.0, lodash.uniq@^4.5.0: +lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10170,6 +10255,11 @@ longest-streak@^2.0.1: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== +longest-streak@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" + integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -10296,6 +10386,11 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== +markdown-extensions@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-1.1.1.tgz#fea03b539faeaee9b4ef02a3769b455b189f7fc3" + integrity sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q== + markdown-table@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" @@ -10303,18 +10398,16 @@ markdown-table@^2.0.0: dependencies: repeat-string "^1.0.0" +markdown-table@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd" + integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw== + mathml-tag-names@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -mdast-squeeze-paragraphs@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97" - integrity sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ== - dependencies: - unist-util-remove "^2.0.0" - mdast-util-compact@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz#cabc69a2f43103628326f35b1acf735d55c99490" @@ -10329,19 +10422,181 @@ mdast-util-definitions@^4.0.0: dependencies: unist-util-visit "^2.0.0" -mdast-util-to-hast@10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb" - integrity sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA== +mdast-util-definitions@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" + integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA== dependencies: "@types/mdast" "^3.0.0" "@types/unist" "^2.0.0" - mdast-util-definitions "^4.0.0" - mdurl "^1.0.0" - unist-builder "^2.0.0" - unist-util-generated "^1.0.0" - unist-util-position "^3.0.0" - unist-util-visit "^2.0.0" + unist-util-visit "^4.0.0" + +mdast-util-directive@^2.0.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/mdast-util-directive/-/mdast-util-directive-2.2.4.tgz#e397ed699ec83938cb4a48dc1cec3ae69cbd7aa3" + integrity sha512-sK3ojFP+jpj1n7Zo5ZKvoxP1MvLyzVG63+gm40Z/qI00avzdPCYxt7RBMgofwAva9gBjbDBWVRB/i+UD+fUCzQ== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + mdast-util-from-markdown "^1.3.0" + mdast-util-to-markdown "^1.5.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-visit-parents "^5.1.3" + +mdast-util-find-and-replace@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz#cc2b774f7f3630da4bd592f61966fecade8b99b1" + integrity sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw== + dependencies: + "@types/mdast" "^3.0.0" + escape-string-regexp "^5.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.0.0" + +mdast-util-from-markdown@^1.0.0, mdast-util-from-markdown@^1.1.0, mdast-util-from-markdown@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz#0214124154f26154a2b3f9d401155509be45e894" + integrity sha512-HN3W1gRIuN/ZW295c7zi7g9lVBllMgZE40RxCX37wrTPWXCWtpvOZdfnuK+1WNpvZje6XuJeI3Wnb4TJEUem+g== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + decode-named-character-reference "^1.0.0" + mdast-util-to-string "^3.1.0" + micromark "^3.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-decode-string "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-stringify-position "^3.0.0" + uvu "^0.5.0" + +mdast-util-gfm-autolink-literal@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz#67a13abe813d7eba350453a5333ae1bc0ec05c06" + integrity sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA== + dependencies: + "@types/mdast" "^3.0.0" + ccount "^2.0.0" + mdast-util-find-and-replace "^2.0.0" + micromark-util-character "^1.0.0" + +mdast-util-gfm-footnote@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz#ce5e49b639c44de68d5bf5399877a14d5020424e" + integrity sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.3.0" + micromark-util-normalize-identifier "^1.0.0" + +mdast-util-gfm-strikethrough@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz#5470eb105b483f7746b8805b9b989342085795b7" + integrity sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.3.0" + +mdast-util-gfm-table@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz#3552153a146379f0f9c4c1101b071d70bbed1a46" + integrity sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg== + dependencies: + "@types/mdast" "^3.0.0" + markdown-table "^3.0.0" + mdast-util-from-markdown "^1.0.0" + mdast-util-to-markdown "^1.3.0" + +mdast-util-gfm-task-list-item@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz#b280fcf3b7be6fd0cc012bbe67a59831eb34097b" + integrity sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.3.0" + +mdast-util-gfm@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz#e92f4d8717d74bdba6de57ed21cc8b9552e2d0b6" + integrity sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg== + dependencies: + mdast-util-from-markdown "^1.0.0" + mdast-util-gfm-autolink-literal "^1.0.0" + mdast-util-gfm-footnote "^1.0.0" + mdast-util-gfm-strikethrough "^1.0.0" + mdast-util-gfm-table "^1.0.0" + mdast-util-gfm-task-list-item "^1.0.0" + mdast-util-to-markdown "^1.0.0" + +mdast-util-math@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-math/-/mdast-util-math-2.0.2.tgz#19a06a81f31643f48cc805e7c31edb7ce739242c" + integrity sha512-8gmkKVp9v6+Tgjtq6SYx9kGPpTf6FVYRa53/DLh479aldR9AyP48qeVOgNZ5X7QUK7nOy4yw7vg6mbiGcs9jWQ== + dependencies: + "@types/mdast" "^3.0.0" + longest-streak "^3.0.0" + mdast-util-to-markdown "^1.3.0" + +mdast-util-mdx-expression@^1.0.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.3.2.tgz#d027789e67524d541d6de543f36d51ae2586f220" + integrity sha512-xIPmR5ReJDu/DHH1OoIT1HkuybIfRGYRywC+gJtI7qHjCJp/M9jrmBEJW22O8lskDWm562BX2W8TiAwRTb0rKA== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + mdast-util-to-markdown "^1.0.0" + +mdast-util-mdx-jsx@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.1.2.tgz#694a46164db10c0e9d674a3772b8748dfddd0817" + integrity sha512-o9vBCYQK5ZLGEj3tCGISJGjvafyHRVJlZmfJzSE7xjiogSzIeph/Z4zMY65q4WGRMezQBeAwPlrdymDYYYx0tA== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + ccount "^2.0.0" + mdast-util-from-markdown "^1.1.0" + mdast-util-to-markdown "^1.3.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-remove-position "^4.0.0" + unist-util-stringify-position "^3.0.0" + vfile-message "^3.0.0" + +mdast-util-mdx@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-2.0.1.tgz#49b6e70819b99bb615d7223c088d295e53bb810f" + integrity sha512-38w5y+r8nyKlGvNjSEqWrhG0w5PmnRA+wnBvm+ulYCct7nsGYhFVb0lljS9bQav4psDAS1eGkP2LMVcZBi/aqw== + dependencies: + mdast-util-from-markdown "^1.0.0" + mdast-util-mdx-expression "^1.0.0" + mdast-util-mdx-jsx "^2.0.0" + mdast-util-mdxjs-esm "^1.0.0" + mdast-util-to-markdown "^1.0.0" + +mdast-util-mdxjs-esm@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.3.1.tgz#645d02cd607a227b49721d146fd81796b2e2d15b" + integrity sha512-SXqglS0HrEvSdUEfoXFtcg7DRl7S2cwOXc7jkuusG472Mmjag34DUDeOJUZtl+BVnyeO1frIgVpHlNRWc2gk/w== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + mdast-util-to-markdown "^1.0.0" + +mdast-util-phrasing@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz#c7c21d0d435d7fb90956038f02e8702781f95463" + integrity sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg== + dependencies: + "@types/mdast" "^3.0.0" + unist-util-is "^5.0.0" mdast-util-to-hast@^10.2.0: version "10.2.0" @@ -10357,10 +10612,40 @@ mdast-util-to-hast@^10.2.0: unist-util-position "^3.0.0" unist-util-visit "^2.0.0" -mdast-util-to-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" - integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== +mdast-util-to-hast@^12.1.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49" + integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-definitions "^5.0.0" + micromark-util-sanitize-uri "^1.1.0" + trim-lines "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + +mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0, mdast-util-to-markdown@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz#c13343cb3fc98621911d33b5cd42e7d0731171c6" + integrity sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^3.0.0" + mdast-util-to-string "^3.0.0" + micromark-util-decode-string "^1.0.0" + unist-util-visit "^4.0.0" + zwitch "^2.0.0" + +mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz#db859050d79d48cf9896d294de06f3ede7474d16" + integrity sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA== + dependencies: + "@types/mdast" "^3.0.0" mdn-data@2.0.14: version "2.0.14" @@ -10466,6 +10751,397 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" + integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-factory-destination "^1.0.0" + micromark-factory-label "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-factory-title "^1.0.0" + micromark-factory-whitespace "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-html-tag-name "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + +micromark-extension-directive@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/micromark-extension-directive/-/micromark-extension-directive-2.1.2.tgz#5445bc7676e72e8d23f47313920a65f574269be3" + integrity sha512-brqLEztt14/73snVXYsq9Cv6ng67O+Sy69ZuM0s8ZhN/GFI9rnyXyj0Y0DaCwi648vCImv7/U1H5TzR7wMv5jw== + dependencies: + micromark-factory-space "^1.0.0" + micromark-factory-whitespace "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + parse-entities "^4.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-autolink-literal@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz#dc589f9c37eaff31a175bab49f12290edcf96058" + integrity sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-footnote@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz#cbfd8873b983e820c494498c6dac0105920818d5" + integrity sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg== + dependencies: + micromark-core-commonmark "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-strikethrough@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz#162232c284ffbedd8c74e59c1525bda217295e18" + integrity sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-table@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz#7b708b728f8dc4d95d486b9e7a2262f9cddbcbb4" + integrity sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-tagfilter@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz#fb2e303f7daf616db428bb6a26e18fda14a90a4d" + integrity sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA== + dependencies: + micromark-util-types "^1.0.0" + +micromark-extension-gfm-task-list-item@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz#7683641df5d4a09795f353574d7f7f66e47b7fc4" + integrity sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz#40f3209216127a96297c54c67f5edc7ef2d1a2a2" + integrity sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA== + dependencies: + micromark-extension-gfm-autolink-literal "^1.0.0" + micromark-extension-gfm-footnote "^1.0.0" + micromark-extension-gfm-strikethrough "^1.0.0" + micromark-extension-gfm-table "^1.0.0" + micromark-extension-gfm-tagfilter "^1.0.0" + micromark-extension-gfm-task-list-item "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-extension-math@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-extension-math/-/micromark-extension-math-2.0.2.tgz#bb7d28b907b17f1813dd3d0df2a6df6bb1a4d0e1" + integrity sha512-cFv2B/E4pFPBBFuGgLHkkNiFAIQv08iDgPH2HCuR2z3AUgMLecES5Cq7AVtwOtZeRrbA80QgMUk8VVW0Z+D2FA== + dependencies: + "@types/katex" "^0.11.0" + katex "^0.13.0" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-mdx-expression@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.4.tgz#33fe2c6ee214738255de175a084281c11894ddda" + integrity sha512-TCgLxqW6ReQ3AJgtj1P0P+8ZThBTloLbeb7jNaqr6mCOLDpxUiBFE/9STgooMZttEwOQu5iEcCCa3ZSDhY9FGw== + dependencies: + micromark-factory-mdx-expression "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-events-to-acorn "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-mdx-jsx@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz#9f196be5f65eb09d2a49b237a7b3398bba2999be" + integrity sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA== + dependencies: + "@types/acorn" "^4.0.0" + estree-util-is-identifier-name "^2.0.0" + micromark-factory-mdx-expression "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + vfile-message "^3.0.0" + +micromark-extension-mdx-md@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.0.tgz#382f5df9ee3706dd120b51782a211f31f4760d22" + integrity sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw== + dependencies: + micromark-util-types "^1.0.0" + +micromark-extension-mdxjs-esm@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.3.tgz#630d9dc9db2c2fd470cac8c1e7a824851267404d" + integrity sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A== + dependencies: + micromark-core-commonmark "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-events-to-acorn "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-position-from-estree "^1.1.0" + uvu "^0.5.0" + vfile-message "^3.0.0" + +micromark-extension-mdxjs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz#772644e12fc8299a33e50f59c5aa15727f6689dd" + integrity sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ== + dependencies: + acorn "^8.0.0" + acorn-jsx "^5.0.0" + micromark-extension-mdx-expression "^1.0.0" + micromark-extension-mdx-jsx "^1.0.0" + micromark-extension-mdx-md "^1.0.0" + micromark-extension-mdxjs-esm "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-destination@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" + integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-label@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" + integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-mdx-expression@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.7.tgz#e38298dc1f7eaf6ba1d9f210531ceae17155c00f" + integrity sha512-QAdFbkQagTZ/eKb8zDGqmjvgevgJH3+aQpvvKrXWxNJp3o8/l2cAbbrBd0E04r0Gx6nssPpqWIjnbHFvZu5qsQ== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-events-to-acorn "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-position-from-estree "^1.0.0" + uvu "^0.5.0" + vfile-message "^3.0.0" + +micromark-factory-space@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" + integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-title@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" + integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-whitespace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" + integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-character@^1.0.0, micromark-util-character@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" + integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== + dependencies: + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-chunked@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" + integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-classify-character@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" + integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-combine-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" + integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-decode-numeric-character-reference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" + integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-decode-string@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" + integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-encode@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" + integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== + +micromark-util-events-to-acorn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.1.tgz#d5b9dfbc589ece7917de24de0a57b909c0d36583" + integrity sha512-mkg3BaWlw6ZTkQORrKVBW4o9ICXPxLtGz51vml5mQpKFdo9vqIX68CAx5JhTOdjQyAHH7JFmm4rh8toSPQZUmg== + dependencies: + "@types/acorn" "^4.0.0" + "@types/estree" "^1.0.0" + estree-util-visit "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + vfile-location "^4.0.0" + vfile-message "^3.0.0" + +micromark-util-html-tag-name@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz#eb227118befd51f48858e879b7a419fc0df20497" + integrity sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA== + +micromark-util-normalize-identifier@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" + integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-resolve-all@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" + integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== + dependencies: + micromark-util-types "^1.0.0" + +micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz#f12e07a85106b902645e0364feb07cf253a85aee" + integrity sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-subtokenize@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" + integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-util-symbol@^1.0.0, micromark-util-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" + integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== + +micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" + integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== + +micromark@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.1.0.tgz#eeba0fe0ac1c9aaef675157b52c166f125e89f62" + integrity sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + micromark-core-commonmark "^1.0.1" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -10699,6 +11375,11 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + mrmime@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" @@ -11572,6 +12253,20 @@ parse-entities@^2.0.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" +parse-entities@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.1.tgz#4e2a01111fb1c986549b944af39eeda258fc9e4e" + integrity sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w== + dependencies: + "@types/unist" "^2.0.0" + character-entities "^2.0.0" + character-entities-legacy "^3.0.0" + character-reference-invalid "^2.0.0" + decode-named-character-reference "^1.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + is-hexadecimal "^2.0.0" + parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -11728,6 +12423,15 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== +periscopic@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.1.0.tgz#7e9037bf51c5855bd33b48928828db4afa79d97a" + integrity sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^3.0.0" + is-reference "^3.0.0" + picocolors@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" @@ -12259,7 +12963,7 @@ prop-types@^15.0.0, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2, object-assign "^4.1.1" react-is "^16.13.1" -property-information@^5.0.0, property-information@^5.3.0, property-information@^5.5.0: +property-information@^5.0.0, property-information@^5.5.0: version "5.6.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== @@ -13000,6 +13704,25 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== +remark-comment@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/remark-comment/-/remark-comment-1.0.0.tgz#befe2fd5dde688d641542cd1206130e00b79a337" + integrity sha512-k8YPo5MGvl8l4gGxOH6Zk4Fa2AhDACN5eqKnKZcHDORZQS15hlnezlBHj2lqyDiqzApNmYOMTibkEJbMSKU25w== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.1.0" + micromark-util-symbol "^1.0.1" + +remark-directive@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/remark-directive/-/remark-directive-2.0.1.tgz#1c32d9df8d839a75ba3478112d21fe883635b48e" + integrity sha512-oosbsUAkU/qmUE78anLaJePnPis4ihsE7Agp0T/oqTzvTea8pOiaYEtfInU/+xMOVTS9PN5AhGOiaIVe4GD8gw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-directive "^2.0.0" + micromark-extension-directive "^2.0.0" + unified "^10.0.0" + remark-emoji@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/remark-emoji/-/remark-emoji-2.2.0.tgz#1c702090a1525da5b80e15a8f963ef2c8236cac7" @@ -13009,31 +13732,44 @@ remark-emoji@^2.2.0: node-emoji "^1.10.0" unist-util-visit "^2.0.3" -remark-footnotes@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" - integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== - -remark-math@^3.0.1: +remark-gfm@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/remark-math/-/remark-math-3.0.1.tgz#85a02a15b15cad34b89a27244d4887b3a95185bb" - integrity sha512-epT77R/HK0x7NqrWHdSV75uNLwn8g9qTyMqCRCDujL0vj/6T6+yhdrR7mjELWtkse+Fw02kijAaBuVcHBor1+Q== - -remark-mdx@1.6.22, remark-mdx@^1.6.21: - version "1.6.22" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd" - integrity sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ== + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" + integrity sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig== dependencies: - "@babel/core" "7.12.9" - "@babel/helper-plugin-utils" "7.10.4" - "@babel/plugin-proposal-object-rest-spread" "7.12.1" - "@babel/plugin-syntax-jsx" "7.12.1" - "@mdx-js/util" "1.6.22" - is-alphabetical "1.0.4" - remark-parse "8.0.3" - unified "9.2.0" + "@types/mdast" "^3.0.0" + mdast-util-gfm "^2.0.0" + micromark-extension-gfm "^2.0.0" + unified "^10.0.0" -remark-parse@8.0.3, remark-parse@^8.0.0, remark-parse@^8.0.2: +remark-math@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/remark-math/-/remark-math-5.1.1.tgz#459e798d978d4ca032e745af0bac81ddcdf94964" + integrity sha512-cE5T2R/xLVtfFI4cCePtiRn+e6jKMtFDR3P8V3qpv8wpKjwvHoBA4eJzvX+nVrnlNy0911bdGmuspCSwetfYHw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-math "^2.0.0" + micromark-extension-math "^2.0.0" + unified "^10.0.0" + +remark-mdx@^2.0.0, remark-mdx@^2.1.5: + version "2.3.0" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-2.3.0.tgz#efe678025a8c2726681bde8bf111af4a93943db4" + integrity sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g== + dependencies: + mdast-util-mdx "^2.0.0" + micromark-extension-mdxjs "^1.0.0" + +remark-parse@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" + integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + unified "^10.0.0" + +remark-parse@^8.0.2: version "8.0.3" resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1" integrity sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q== @@ -13055,6 +13791,16 @@ remark-parse@8.0.3, remark-parse@^8.0.0, remark-parse@^8.0.2: vfile-location "^3.0.0" xtend "^4.0.1" +remark-rehype@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" + integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-hast "^12.1.0" + unified "^10.0.0" + remark-rehype@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-8.1.0.tgz#610509a043484c1e697437fa5eb3fd992617c945" @@ -13062,14 +13808,16 @@ remark-rehype@^8.1.0: dependencies: mdast-util-to-hast "^10.2.0" -remark-squeeze-paragraphs@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead" - integrity sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw== +remark-stringify@^10.0.0: + version "10.0.2" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-10.0.2.tgz#50414a6983f5008eb9e72eed05f980582d1f69d7" + integrity sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw== dependencies: - mdast-squeeze-paragraphs "^4.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.0.0" + unified "^10.0.0" -remark-stringify@^8.0.0, remark-stringify@^8.1.0: +remark-stringify@^8.1.0: version "8.1.1" resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-8.1.1.tgz#e2a9dc7a7bf44e46a155ec78996db896780d8ce5" integrity sha512-q4EyPZT3PcA3Eq7vPpT6bIdokXzFGp9i85igjmhRyXWmPs0Y6/d2FYwUNotKAWyLch7g0ASZJn/KHHcHZQ163A== @@ -13089,14 +13837,15 @@ remark-stringify@^8.0.0, remark-stringify@^8.1.0: unherit "^1.0.4" xtend "^4.0.1" -remark@^12.0.1: - version "12.0.1" - resolved "https://registry.yarnpkg.com/remark/-/remark-12.0.1.tgz#f1ddf68db7be71ca2bad0a33cd3678b86b9c709f" - integrity sha512-gS7HDonkdIaHmmP/+shCPejCEEW+liMp/t/QwmF0Xt47Rpuhl32lLtDV1uKWvGoq+kxr5jSgg5oAIpGuyULjUw== +remark@^14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/remark/-/remark-14.0.2.tgz#4a1833f7441a5c29e44b37bb1843fb820797b40f" + integrity sha512-A3ARm2V4BgiRXaUo5K0dRvJ1lbogrbXnhkJRmD0yw092/Yl0kOCZt1k9ZeElEwkZsWGsMumz6qL5MfNJH9nOBA== dependencies: - remark-parse "^8.0.0" - remark-stringify "^8.0.0" - unified "^9.0.0" + "@types/mdast" "^3.0.0" + remark-parse "^10.0.0" + remark-stringify "^10.0.0" + unified "^10.0.0" renderkid@^3.0.0: version "3.0.0" @@ -13173,7 +13922,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.1.tgz#cee884cd4e3f355660e501fa3276b27d7ffe5a20" integrity sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw== -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -13308,6 +14057,13 @@ rxjs@^7.5.5, rxjs@^7.8.0: dependencies: tslib "^2.1.0" +sade@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -13416,7 +14172,7 @@ semver-diff@^4.0.0: dependencies: semver "^7.3.5" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -13762,17 +14518,12 @@ source-map-support@^0.5.16, source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3: +source-map@^0.7.0, source-map@^0.7.3: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== @@ -14015,6 +14766,14 @@ stringify-entities@^3.0.0, stringify-entities@^3.0.1: character-entities-legacy "^1.0.0" xtend "^4.0.0" +stringify-entities@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.3.tgz#cfabd7039d22ad30f3cc435b0ca2c1574fc88ef8" + integrity sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g== + dependencies: + character-entities-html4 "^2.0.0" + character-entities-legacy "^3.0.0" + stringify-object@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" @@ -14099,10 +14858,10 @@ style-search@^0.1.0: resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== -style-to-object@0.3.0, style-to-object@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" - integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== +style-to-object@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.1.tgz#53cf856f7cf7f172d72939d9679556469ba5de37" + integrity sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw== dependencies: inline-style-parser "0.1.1" @@ -14551,6 +15310,11 @@ treeverse@^2.0.0: resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-2.0.0.tgz#036dcef04bc3fd79a9b79a68d4da03e882d8a9ca" integrity sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A== +trim-lines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" + integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== + trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" @@ -14566,11 +15330,6 @@ trim@0.0.1: resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" integrity sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ== -trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== - trough@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" @@ -14780,19 +15539,7 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== -unified@9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8" - integrity sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" - -unified@^10.0.0: +unified@^10.0.0, unified@^10.1.2: version "10.1.2" resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== @@ -14805,18 +15552,6 @@ unified@^10.0.0: trough "^2.0.0" vfile "^5.0.0" -unified@^9.0.0, unified@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.2.tgz#67649a1abfc3ab85d2969502902775eb03146975" - integrity sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" - unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -14859,7 +15594,7 @@ unique-string@^3.0.0: dependencies: crypto-random-string "^4.0.0" -unist-builder@2.0.3, unist-builder@^2.0.0, unist-builder@^2.0.3: +unist-builder@^2.0.0, unist-builder@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== @@ -14877,6 +15612,11 @@ unist-util-generated@^1.0.0: resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== +unist-util-generated@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" + integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A== + unist-util-is@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" @@ -14889,11 +15629,25 @@ unist-util-is@^5.0.0: dependencies: "@types/unist" "^2.0.0" +unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.2.tgz#8ac2480027229de76512079e377afbcabcfcce22" + integrity sha512-poZa0eXpS+/XpoQwGwl79UUdea4ol2ZuCYguVaJS4qzIOMDzbqz8a3erUCOmubSZkaOuGamb3tX790iwOIROww== + dependencies: + "@types/unist" "^2.0.0" + unist-util-position@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== +unist-util-position@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.4.tgz#93f6d8c7d6b373d9b825844645877c127455f037" + integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-remove-position@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" @@ -14916,13 +15670,6 @@ unist-util-remove-position@^4.0.0: "@types/unist" "^2.0.0" unist-util-visit "^4.0.0" -unist-util-remove@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-2.1.0.tgz#b0b4738aa7ee445c402fda9328d604a02d010588" - integrity sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q== - dependencies: - unist-util-is "^4.0.0" - unist-util-stringify-position@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" @@ -14945,7 +15692,7 @@ unist-util-visit-parents@^3.0.0: "@types/unist" "^2.0.0" unist-util-is "^4.0.0" -unist-util-visit-parents@^5.1.1: +unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1, unist-util-visit-parents@^5.1.3: version "5.1.3" resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb" integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg== @@ -14953,7 +15700,7 @@ unist-util-visit-parents@^5.1.1: "@types/unist" "^2.0.0" unist-util-is "^5.0.0" -unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.3: +unist-util-visit@^2.0.0, unist-util-visit@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q== @@ -15121,6 +15868,16 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +uvu@^0.5.0: + version "0.5.6" + resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df" + integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA== + dependencies: + dequal "^2.0.0" + diff "^5.0.0" + kleur "^4.0.3" + sade "^1.7.3" + v8-compile-cache@2.3.0, v8-compile-cache@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -15929,7 +16686,7 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zwitch@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" - integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== +zwitch@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==