diff --git a/packages/docusaurus-mdx-loader/src/processor.ts b/packages/docusaurus-mdx-loader/src/processor.ts index 512cd453bfbb..6865f721a999 100644 --- a/packages/docusaurus-mdx-loader/src/processor.ts +++ b/packages/docusaurus-mdx-loader/src/processor.ts @@ -165,6 +165,7 @@ async function createProcessorFactory() { const mdxProcessor = createMdxProcessor({ ...processorOptions, + remarkRehypeOptions: options.markdownConfig.remarkRehypeOptions, format, }); diff --git a/packages/docusaurus-types/package.json b/packages/docusaurus-types/package.json index bc03eb68d218..0c220e5d4a32 100644 --- a/packages/docusaurus-types/package.json +++ b/packages/docusaurus-types/package.json @@ -13,6 +13,7 @@ }, "license": "MIT", "dependencies": { + "@mdx-js/mdx": "^3.0.0", "@types/history": "^4.7.11", "@types/react": "*", "commander": "^5.1.0", diff --git a/packages/docusaurus-types/src/config.d.ts b/packages/docusaurus-types/src/config.d.ts index 0d872e4001c7..11cf226a7fab 100644 --- a/packages/docusaurus-types/src/config.d.ts +++ b/packages/docusaurus-types/src/config.d.ts @@ -10,6 +10,11 @@ import type {Required as RequireKeys, DeepPartial} from 'utility-types'; import type {I18nConfig} from './i18n'; import type {PluginConfig, PresetConfig, HtmlTagObject} from './plugin'; +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +import type {ProcessorOptions} from '@mdx-js/mdx'; + +export type RemarkRehypeOptions = ProcessorOptions['remarkRehypeOptions']; + export type ReportingSeverity = 'ignore' | 'log' | 'warn' | 'throw'; export type ThemeConfig = { @@ -91,6 +96,12 @@ export type MarkdownConfig = { * See also https://github.com/facebook/docusaurus/issues/4029 */ mdx1Compat: MDX1CompatOptions; + + /** + * Ability to provide custom remark-rehype options + * See also https://github.com/remarkjs/remark-rehype#options + */ + remarkRehypeOptions: RemarkRehypeOptions; }; /** diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index 925207b6366f..ea76af81408b 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -69,6 +69,9 @@ describe('normalizeConfig', () => { admonitions: false, headingIds: true, }, + remarkRehypeOptions: { + footnoteLabel: 'Pied de page', + }, }, }; const normalizedConfig = normalizeConfig(userConfig); @@ -514,6 +517,11 @@ describe('markdown', () => { admonitions: true, headingIds: false, }, + remarkRehypeOptions: { + footnoteLabel: 'Notes de bas de page', + // @ts-expect-error: we don't validate it on purpose + anyKey: 'heck we accept it on purpose', + }, }; expect( normalizeConfig({ diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 193b8eb6a73d..c020a09cae9f 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -39,6 +39,7 @@ export const DEFAULT_MARKDOWN_CONFIG: MarkdownConfig = { admonitions: true, headingIds: true, }, + remarkRehypeOptions: undefined, }; export const DEFAULT_CONFIG: Pick< @@ -307,6 +308,11 @@ export const ConfigSchema = Joi.object({ DEFAULT_CONFIG.markdown.mdx1Compat.headingIds, ), }).default(DEFAULT_CONFIG.markdown.mdx1Compat), + remarkRehypeOptions: + // add proper external options validation? + // Not sure if it's a good idea, validation is likely to become stale + // See https://github.com/remarkjs/remark-rehype#options + Joi.object().unknown(), }).default(DEFAULT_CONFIG.markdown), }).messages({ 'docusaurus.configValidationWarning': diff --git a/website/docs/api/docusaurus.config.js.mdx b/website/docs/api/docusaurus.config.js.mdx index 48cd331e407e..69a88129a642 100644 --- a/website/docs/api/docusaurus.config.js.mdx +++ b/website/docs/api/docusaurus.config.js.mdx @@ -436,6 +436,7 @@ type MarkdownConfig = { preprocessor?: MarkdownPreprocessor; parseFrontMatter?: ParseFrontMatter; mdx1Compat: MDX1CompatOptions; + remarkRehypeOptions: object; // https://github.com/remarkjs/remark-rehype#options }; ``` @@ -475,6 +476,7 @@ export default { | `preprocessor` | `MarkdownPreprocessor` | `undefined` | Gives you the ability to alter the Markdown content string before parsing. Use it as a last-resort escape hatch or workaround: it is almost always better to implement a Remark/Rehype plugin. | | `parseFrontMatter` | `ParseFrontMatter` | `undefined` | Gives you the ability to provide your own front matter parser, or to enhance the default parser. Read our [front matter guide](../guides/markdown-features/markdown-features-intro.mdx#front-matter) for details. | | `mdx1Compat` | `MDX1CompatOptions` | `{comments: true, admonitions: true, headingIds: true}` | Compatibility options to make it easier to upgrade to Docusaurus v3+. | +| `remarkRehypeOptions` | `object` | `undefined` | Makes it possible to pass custom [`remark-rehype` options](https://github.com/remarkjs/remark-rehype#options). | ```mdx-code-block diff --git a/website/docusaurus.config.localized.json b/website/docusaurus.config.localized.json index 1c90178b80c2..4e8553a8d59e 100644 --- a/website/docusaurus.config.localized.json +++ b/website/docusaurus.config.localized.json @@ -2,5 +2,9 @@ "tagline": { "en": "Build optimized websites quickly, focus on your content", "fr": "Construisez rapidement des sites web optimisés, concentrez-vous sur votre contenu" + }, + "remarkRehypeOptions_footnotes": { + "en": "Footnotes", + "fr": "Notes de bas de page" } } diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index 3f88352dd6e5..afc8fb52b143 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -102,7 +102,7 @@ const TwitterSvg = const defaultLocale = 'en'; -function getLocalizedConfigValue(key: string) { +function getLocalizedConfigValue(key: keyof typeof ConfigLocalized) { const currentLocale = process.env.DOCUSAURUS_CURRENT_LOCALE ?? defaultLocale; const values = ConfigLocalized[key]; if (!values) { @@ -177,6 +177,9 @@ export default async function createConfigAsync() { mdx1Compat: { // comments: false, }, + remarkRehypeOptions: { + footnoteLabel: getLocalizedConfigValue('remarkRehypeOptions_footnotes'), + }, parseFrontMatter: async (params) => { const result = await params.defaultParseFrontMatter(params); return {