Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mdx): add siteConfig.markdown.format to configure the default content parser (MDX / CommonMark) #9097

Merged
merged 4 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
128 changes: 105 additions & 23 deletions packages/docusaurus-mdx-loader/src/__tests__/format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,126 @@ import {getFormat} from '../format';

describe('getFormat', () => {
it('uses frontMatter format over anything else', () => {
expect(getFormat({frontMatterFormat: 'md', filePath: 'xyz.md'})).toBe('md');
expect(getFormat({frontMatterFormat: 'md', filePath: 'xyz.mdx'})).toBe(
'md',
);
expect(getFormat({frontMatterFormat: 'mdx', filePath: 'xyz.md'})).toBe(
'mdx',
);
expect(getFormat({frontMatterFormat: 'mdx', filePath: 'xyz.mdx'})).toBe(
'mdx',
);
expect(
getFormat({
frontMatterFormat: 'md',
filePath: 'xyz.md',
markdownConfigFormat: 'mdx',
}),
).toBe('md');
expect(
getFormat({
frontMatterFormat: 'md',
filePath: 'xyz.mdx',
markdownConfigFormat: 'mdx',
}),
).toBe('md');
expect(
getFormat({
frontMatterFormat: 'mdx',
filePath: 'xyz.md',
markdownConfigFormat: 'md',
}),
).toBe('mdx');
expect(
getFormat({
frontMatterFormat: 'mdx',
filePath: 'xyz.mdx',
markdownConfigFormat: 'md',
}),
).toBe('mdx');
});

it('detects appropriate format from file extension', () => {
expect(getFormat({frontMatterFormat: 'detect', filePath: 'xyz.md'})).toBe(
'md',
);
it('supports "detects" for front matter', () => {
expect(
getFormat({
frontMatterFormat: 'detect',
filePath: 'xyz.md',
markdownConfigFormat: 'mdx',
}),
).toBe('md');
expect(
getFormat({frontMatterFormat: 'detect', filePath: 'xyz.markdown'}),
getFormat({
frontMatterFormat: 'detect',
filePath: 'xyz.markdown',
markdownConfigFormat: 'mdx',
}),
).toBe('md');

expect(
getFormat({frontMatterFormat: 'detect', filePath: 'folder/xyz.md'}),
getFormat({
frontMatterFormat: 'detect',
filePath: 'folder/xyz.md',
markdownConfigFormat: 'mdx',
}),
).toBe('md');
expect(
getFormat({frontMatterFormat: 'detect', filePath: 'folder/xyz.markdown'}),
getFormat({
frontMatterFormat: 'detect',
filePath: 'folder/xyz.markdown',
markdownConfigFormat: 'mdx',
}),
).toBe('md');
expect(getFormat({frontMatterFormat: 'detect', filePath: 'xyz.mdx'})).toBe(
'mdx',
);
expect(
getFormat({frontMatterFormat: 'detect', filePath: 'folder/xyz.mdx'}),
getFormat({
frontMatterFormat: 'detect',
filePath: 'xyz.mdx',
markdownConfigFormat: 'md',
}),
).toBe('mdx');
expect(
getFormat({
frontMatterFormat: 'detect',
filePath: 'folder/xyz.mdx',
markdownConfigFormat: 'md',
}),
).toBe('mdx');

expect(
getFormat({frontMatterFormat: 'detect', filePath: 'xyz.unknown'}),
getFormat({
frontMatterFormat: 'detect',
filePath: 'xyz.unknown',
markdownConfigFormat: 'md',
}),
).toBe('mdx');
expect(
getFormat({frontMatterFormat: 'detect', filePath: 'folder/xyz.unknown'}),
getFormat({
frontMatterFormat: 'detect',
filePath: 'folder/xyz.unknown',
markdownConfigFormat: 'md',
}),
).toBe('mdx');
});

it('fallbacks to markdown config format when front matter undefined', () => {
expect(
getFormat({
frontMatterFormat: undefined,
filePath: 'xyz.md',
markdownConfigFormat: 'mdx',
}),
).toBe('mdx');
expect(
getFormat({
frontMatterFormat: undefined,
filePath: 'xyz.mdx',
markdownConfigFormat: 'md',
}),
).toBe('md');

expect(
getFormat({
frontMatterFormat: undefined,
filePath: 'xyz.md',
markdownConfigFormat: 'detect',
}),
).toBe('md');
expect(
getFormat({
frontMatterFormat: undefined,
filePath: 'xyz.mdx',
markdownConfigFormat: 'detect',
}),
).toBe('mdx');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,18 @@ describe('MDX front matter schema', () => {
describe('validateDocFrontMatter format', () => {
testField({
prefix: 'format',
validFrontMatters: [{format: 'md'}, {format: 'mdx'}],
validFrontMatters: [
{},
{format: undefined},
{format: 'detect'},
{format: 'md'},
{format: 'mdx'},
],
invalidFrontMatters: [
[{format: 'xdm'}, '"format" must be one of [md, mdx, detect]'],
[{format: ''}, '"format" must be one of [md, mdx, detect]'],
[{format: null}, '"format" must be one of [md, mdx, detect]'],
[{unknownAttribute: 'mdx'}, '"unknownAttribute" is not allowed'],
],
});
});
24 changes: 17 additions & 7 deletions packages/docusaurus-mdx-loader/src/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import path from 'path';
import type {MDXFrontMatter} from './frontMatter';
import type {Format, FormatInput} from './index';

// Copied from https://mdxjs.com/packages/mdx/#optionsmdextensions
// Although we are likely to only use .md / .mdx anyway...
Expand All @@ -21,20 +22,29 @@ const mdFormatExtensions = [
'.ron',
];

function isMDFormat(filepath: string) {
return mdFormatExtensions.includes(path.extname(filepath));
function getExtensionFormat(filepath: string): Format {
const isMDFormat = mdFormatExtensions.includes(path.extname(filepath));
// Bias toward mdx if unknown extension
return isMDFormat ? 'md' : 'mdx';
}

export function getFormat({
filePath,
frontMatterFormat,
markdownConfigFormat,
}: {
filePath: string;
frontMatterFormat: MDXFrontMatter['format'];
}): 'md' | 'mdx' {
if (frontMatterFormat !== 'detect') {
return frontMatterFormat;
markdownConfigFormat: FormatInput;
}): Format {
if (frontMatterFormat) {
if (frontMatterFormat !== 'detect') {
return frontMatterFormat;
}
return getExtensionFormat(filePath);
}
// Bias toward mdx if unknown extension
return isMDFormat(filePath) ? 'md' : 'mdx';
if (markdownConfigFormat !== 'detect') {
return markdownConfigFormat;
}
return getExtensionFormat(filePath);
}
10 changes: 5 additions & 5 deletions packages/docusaurus-mdx-loader/src/frontMatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ import {
validateFrontMatter,
} from '@docusaurus/utils-validation';

import type {FormatInput} from './index';

export type MDXFrontMatter = {
format: 'md' | 'mdx' | 'detect';
format?: FormatInput;
};

export const DefaultMDXFrontMatter: MDXFrontMatter = {
format: 'detect',
format: undefined,
};

const MDXFrontMatterSchema = Joi.object<MDXFrontMatter>({
format: Joi.string()
.equal('md', 'mdx', 'detect')
.default(DefaultMDXFrontMatter.format),
format: Joi.string().equal('md', 'mdx', 'detect').optional(),
}).default(DefaultMDXFrontMatter);

export function validateMDXFrontMatter(frontMatter: unknown): MDXFrontMatter {
Expand Down
4 changes: 4 additions & 0 deletions packages/docusaurus-mdx-loader/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export default mdxLoader;

export type TOCItem = TOCItemImported;

export type Format = 'md' | 'mdx';

export type FormatInput = Format | 'detect';

export type LoadedMDXContent<FrontMatter, Metadata, Assets = undefined> = {
/** As verbatim declared in the MDX document. */
readonly frontMatter: FrontMatter;
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus-mdx-loader/src/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ export async function createProcessorCached({
const format = getFormat({
filePath,
frontMatterFormat: mdxFrontMatter.format,
markdownConfigFormat: reqOptions.markdownConfig.format,
});

return format === 'md' ? compilers.mdProcessor : compilers.mdxProcessor;
Expand Down
35 changes: 29 additions & 6 deletions packages/docusaurus-types/src/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,34 @@ export type ThemeConfig = {
[key: string]: unknown;
};

export type MarkdownPreprocessor = (args: {
filePath: string;
fileContent: string;
}) => string;

export type MDX1CompatOptions = {
comments: boolean;
admonitions: boolean;
headingIds: boolean;
};

export type MarkdownConfig = {
/**
* The Markdown format to use by default.
*
* This is the format passed down to the MDX compiler, impacting the way the
* content is parsed.
*
* Possible values:
* - `'mdx'`: use the MDX format (JSX support)
* - `'md'`: use the CommonMark format (no JSX support)
* - `'detect'`: select the format based on file extension (.md / .mdx)
*
* @see https://mdxjs.com/packages/mdx/#optionsformat
* @default 'mdx'
*/
format: 'mdx' | 'md' | 'detect';

/**
* Allow mermaid language code blocks to be rendered into Mermaid diagrams:
*
Expand All @@ -35,17 +62,13 @@ export type MarkdownConfig = {
*
* @param args
*/
preprocessor?: (args: {filePath: string; fileContent: string}) => string;
preprocessor?: MarkdownPreprocessor;

/**
* 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;
};
mdx1Compat: MDX1CompatOptions;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ exports[`loadSiteConfig website with .cjs siteConfig 1`] = `
"path": "i18n",
},
"markdown": {
"format": "mdx",
"mdx1Compat": {
"admonitions": true,
"comments": true,
Expand Down Expand Up @@ -64,6 +65,7 @@ exports[`loadSiteConfig website with valid async config 1`] = `
"path": "i18n",
},
"markdown": {
"format": "mdx",
"mdx1Compat": {
"admonitions": true,
"comments": true,
Expand Down Expand Up @@ -113,6 +115,7 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = `
"path": "i18n",
},
"markdown": {
"format": "mdx",
"mdx1Compat": {
"admonitions": true,
"comments": true,
Expand Down Expand Up @@ -162,6 +165,7 @@ exports[`loadSiteConfig website with valid config creator function 1`] = `
"path": "i18n",
},
"markdown": {
"format": "mdx",
"mdx1Compat": {
"admonitions": true,
"comments": true,
Expand Down Expand Up @@ -214,6 +218,7 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = `
"path": "i18n",
},
"markdown": {
"format": "mdx",
"mdx1Compat": {
"admonitions": true,
"comments": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ exports[`load loads props for site with custom i18n path 1`] = `
"path": "i18n",
},
"markdown": {
"format": "mdx",
"mdx1Compat": {
"admonitions": true,
"comments": true,
Expand Down