mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-27 21:48:41 +02:00
feat(core): add siteConfig.markdown.emoji
config option to disable remark-emoji
(#11282)
This commit is contained in:
parent
96c38d5fdd
commit
e14caf1f78
7 changed files with 87 additions and 9 deletions
|
@ -95,7 +95,7 @@ async function createProcessorFactory() {
|
||||||
headings,
|
headings,
|
||||||
{anchorsMaintainCase: options.markdownConfig.anchors.maintainCase},
|
{anchorsMaintainCase: options.markdownConfig.anchors.maintainCase},
|
||||||
],
|
],
|
||||||
emoji,
|
...(options.markdownConfig.emoji ? [emoji] : []),
|
||||||
toc,
|
toc,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
10
packages/docusaurus-types/src/markdown.d.ts
vendored
10
packages/docusaurus-types/src/markdown.d.ts
vendored
|
@ -136,6 +136,16 @@ export type MarkdownConfig = {
|
||||||
*/
|
*/
|
||||||
mermaid: boolean;
|
mermaid: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow remark-emoji to convert emoji shortcodes to Unicode emoji.
|
||||||
|
* - `true` (default): enables the remark-emoji plugin to convert shortcodes
|
||||||
|
* - `false`: disables the remark-emoji plugin
|
||||||
|
*
|
||||||
|
* @see https://github.com/rhysd/remark-emoji
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
emoji: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives opportunity to preprocess the MDX string content before compiling.
|
* Gives opportunity to preprocess the MDX string content before compiling.
|
||||||
* A good escape hatch that can be used to handle edge cases.
|
* A good escape hatch that can be used to handle edge cases.
|
||||||
|
|
|
@ -41,6 +41,7 @@ exports[`loadSiteConfig website with .cjs siteConfig 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -119,6 +120,7 @@ exports[`loadSiteConfig website with ts + js config 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -197,6 +199,7 @@ exports[`loadSiteConfig website with valid JS CJS config 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -275,6 +278,7 @@ exports[`loadSiteConfig website with valid JS ESM config 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -353,6 +357,7 @@ exports[`loadSiteConfig website with valid TypeScript CJS config 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -431,6 +436,7 @@ exports[`loadSiteConfig website with valid TypeScript ESM config 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -509,6 +515,7 @@ exports[`loadSiteConfig website with valid async config 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -589,6 +596,7 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -669,6 +677,7 @@ exports[`loadSiteConfig website with valid config creator function 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
@ -752,6 +761,7 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
|
|
@ -125,6 +125,7 @@ exports[`load loads props for site with custom i18n path 1`] = `
|
||||||
"anchors": {
|
"anchors": {
|
||||||
"maintainCase": false,
|
"maintainCase": false,
|
||||||
},
|
},
|
||||||
|
"emoji": true,
|
||||||
"format": "mdx",
|
"format": "mdx",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"onBrokenMarkdownImages": "throw",
|
"onBrokenMarkdownImages": "throw",
|
||||||
|
|
|
@ -17,17 +17,17 @@ import {
|
||||||
DEFAULT_STORAGE_CONFIG,
|
DEFAULT_STORAGE_CONFIG,
|
||||||
validateConfig,
|
validateConfig,
|
||||||
} from '../configValidation';
|
} from '../configValidation';
|
||||||
import type {
|
|
||||||
MarkdownConfig,
|
|
||||||
MarkdownHooks,
|
|
||||||
} from '@docusaurus/types/src/markdown';
|
|
||||||
import type {
|
import type {
|
||||||
FasterConfig,
|
FasterConfig,
|
||||||
FutureConfig,
|
FutureConfig,
|
||||||
FutureV4Config,
|
FutureV4Config,
|
||||||
StorageConfig,
|
StorageConfig,
|
||||||
} from '@docusaurus/types/src/config';
|
MarkdownConfig,
|
||||||
import type {Config, DocusaurusConfig, PluginConfig} from '@docusaurus/types';
|
MarkdownHooks,
|
||||||
|
Config,
|
||||||
|
DocusaurusConfig,
|
||||||
|
PluginConfig,
|
||||||
|
} from '@docusaurus/types';
|
||||||
import type {DeepPartial} from 'utility-types';
|
import type {DeepPartial} from 'utility-types';
|
||||||
|
|
||||||
const baseConfig = {
|
const baseConfig = {
|
||||||
|
@ -36,7 +36,7 @@ const baseConfig = {
|
||||||
url: 'https://mysite.com',
|
url: 'https://mysite.com',
|
||||||
} as Config;
|
} as Config;
|
||||||
|
|
||||||
const normalizeConfig = (config: DeepPartial<Config>) =>
|
const normalizeConfig = (config: DeepPartial<Config>): DocusaurusConfig =>
|
||||||
validateConfig({...baseConfig, ...config}, 'docusaurus.config.js');
|
validateConfig({...baseConfig, ...config}, 'docusaurus.config.js');
|
||||||
|
|
||||||
describe('normalizeConfig', () => {
|
describe('normalizeConfig', () => {
|
||||||
|
@ -99,6 +99,7 @@ describe('normalizeConfig', () => {
|
||||||
markdown: {
|
markdown: {
|
||||||
format: 'md',
|
format: 'md',
|
||||||
mermaid: true,
|
mermaid: true,
|
||||||
|
emoji: false,
|
||||||
parseFrontMatter: async (params) =>
|
parseFrontMatter: async (params) =>
|
||||||
params.defaultParseFrontMatter(params),
|
params.defaultParseFrontMatter(params),
|
||||||
preprocessor: ({fileContent}) => fileContent,
|
preprocessor: ({fileContent}) => fileContent,
|
||||||
|
@ -366,7 +367,9 @@ describe('onBrokenLinks', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('markdown', () => {
|
describe('markdown', () => {
|
||||||
function normalizeMarkdown(markdown: DeepPartial<MarkdownConfig>) {
|
function normalizeMarkdown(
|
||||||
|
markdown: DeepPartial<MarkdownConfig>,
|
||||||
|
): MarkdownConfig {
|
||||||
return normalizeConfig({markdown}).markdown;
|
return normalizeConfig({markdown}).markdown;
|
||||||
}
|
}
|
||||||
it('accepts undefined object', () => {
|
it('accepts undefined object', () => {
|
||||||
|
@ -381,6 +384,7 @@ describe('markdown', () => {
|
||||||
const markdown: Config['markdown'] = {
|
const markdown: Config['markdown'] = {
|
||||||
format: 'md',
|
format: 'md',
|
||||||
mermaid: true,
|
mermaid: true,
|
||||||
|
emoji: false,
|
||||||
parseFrontMatter: async (params) =>
|
parseFrontMatter: async (params) =>
|
||||||
params.defaultParseFrontMatter(params),
|
params.defaultParseFrontMatter(params),
|
||||||
preprocessor: ({fileContent}) => fileContent,
|
preprocessor: ({fileContent}) => fileContent,
|
||||||
|
@ -476,6 +480,54 @@ describe('markdown', () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('emoji', () => {
|
||||||
|
it('accepts emoji boolean true', () => {
|
||||||
|
expect(
|
||||||
|
normalizeMarkdown({
|
||||||
|
emoji: true,
|
||||||
|
}).emoji,
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts emoji boolean false', () => {
|
||||||
|
expect(
|
||||||
|
normalizeMarkdown({
|
||||||
|
emoji: false,
|
||||||
|
}).emoji,
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('defaults emoji to true when undefined', () => {
|
||||||
|
expect(normalizeMarkdown({}).emoji).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throw for string emoji value', () => {
|
||||||
|
expect(() =>
|
||||||
|
normalizeMarkdown({
|
||||||
|
// @ts-expect-error: bad value
|
||||||
|
emoji: 'yes',
|
||||||
|
}),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(`
|
||||||
|
""markdown.emoji" must be a boolean
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throw for number emoji value', () => {
|
||||||
|
expect(() =>
|
||||||
|
normalizeConfig({
|
||||||
|
markdown: {
|
||||||
|
// @ts-expect-error: bad value
|
||||||
|
emoji: 1,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(`
|
||||||
|
""markdown.emoji" must be a boolean
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('hooks', () => {
|
describe('hooks', () => {
|
||||||
function normalizeHooks(hooks: DeepPartial<MarkdownHooks>): MarkdownHooks {
|
function normalizeHooks(hooks: DeepPartial<MarkdownHooks>): MarkdownHooks {
|
||||||
return normalizeMarkdown({
|
return normalizeMarkdown({
|
||||||
|
|
|
@ -91,6 +91,7 @@ export const DEFAULT_MARKDOWN_HOOKS: MarkdownHooks = {
|
||||||
export const DEFAULT_MARKDOWN_CONFIG: MarkdownConfig = {
|
export const DEFAULT_MARKDOWN_CONFIG: MarkdownConfig = {
|
||||||
format: 'mdx', // TODO change this to "detect" in Docusaurus v4?
|
format: 'mdx', // TODO change this to "detect" in Docusaurus v4?
|
||||||
mermaid: false,
|
mermaid: false,
|
||||||
|
emoji: true,
|
||||||
preprocessor: undefined,
|
preprocessor: undefined,
|
||||||
parseFrontMatter: DEFAULT_PARSE_FRONT_MATTER,
|
parseFrontMatter: DEFAULT_PARSE_FRONT_MATTER,
|
||||||
mdx1Compat: {
|
mdx1Compat: {
|
||||||
|
@ -435,6 +436,7 @@ export const ConfigSchema = Joi.object<DocusaurusConfig>({
|
||||||
() => DEFAULT_CONFIG.markdown.parseFrontMatter,
|
() => DEFAULT_CONFIG.markdown.parseFrontMatter,
|
||||||
),
|
),
|
||||||
mermaid: Joi.boolean().default(DEFAULT_CONFIG.markdown.mermaid),
|
mermaid: Joi.boolean().default(DEFAULT_CONFIG.markdown.mermaid),
|
||||||
|
emoji: Joi.boolean().default(DEFAULT_CONFIG.markdown.emoji),
|
||||||
preprocessor: Joi.function()
|
preprocessor: Joi.function()
|
||||||
.arity(1)
|
.arity(1)
|
||||||
.optional()
|
.optional()
|
||||||
|
|
|
@ -541,6 +541,7 @@ type MarkdownHooks = {
|
||||||
type MarkdownConfig = {
|
type MarkdownConfig = {
|
||||||
format: 'mdx' | 'md' | 'detect';
|
format: 'mdx' | 'md' | 'detect';
|
||||||
mermaid: boolean;
|
mermaid: boolean;
|
||||||
|
emoji: boolean;
|
||||||
preprocessor?: MarkdownPreprocessor;
|
preprocessor?: MarkdownPreprocessor;
|
||||||
parseFrontMatter?: ParseFrontMatter;
|
parseFrontMatter?: ParseFrontMatter;
|
||||||
mdx1Compat: MDX1CompatOptions;
|
mdx1Compat: MDX1CompatOptions;
|
||||||
|
@ -557,6 +558,7 @@ export default {
|
||||||
markdown: {
|
markdown: {
|
||||||
format: 'mdx',
|
format: 'mdx',
|
||||||
mermaid: true,
|
mermaid: true,
|
||||||
|
emoji: true,
|
||||||
preprocessor: ({filePath, fileContent}) => {
|
preprocessor: ({filePath, fileContent}) => {
|
||||||
return fileContent.replaceAll('{{MY_VAR}}', 'MY_VALUE');
|
return fileContent.replaceAll('{{MY_VAR}}', 'MY_VALUE');
|
||||||
},
|
},
|
||||||
|
@ -590,6 +592,7 @@ export default {
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `format` | `'mdx' \| 'md' \| 'detect'` | `'mdx'` | The default parser format to use for Markdown content. Using 'detect' will select the appropriate format automatically based on file extensions: `.md` vs `.mdx`. |
|
| `format` | `'mdx' \| 'md' \| 'detect'` | `'mdx'` | The default parser format to use for Markdown content. Using 'detect' will select the appropriate format automatically based on file extensions: `.md` vs `.mdx`. |
|
||||||
| `mermaid` | `boolean` | `false` | When `true`, allows Docusaurus to render Markdown code blocks with `mermaid` language as Mermaid diagrams. |
|
| `mermaid` | `boolean` | `false` | When `true`, allows Docusaurus to render Markdown code blocks with `mermaid` language as Mermaid diagrams. |
|
||||||
|
| `emoji` | `boolean` | `true` | When `true`, allows Docusaurus to render emoji shortcodes (e.g., `:+1:`) as Unicode emoji (👍). When `false`, emoji shortcodes are left as-is. |
|
||||||
| `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. |
|
| `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. |
|
| `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+. |
|
| `mdx1Compat` | `MDX1CompatOptions` | `{comments: true, admonitions: true, headingIds: true}` | Compatibility options to make it easier to upgrade to Docusaurus v3+. |
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue