Skip to content

Commit

Permalink
feat(mdx-loader): Remark plugin to report unused MDX / Markdown direc…
Browse files Browse the repository at this point in the history
…tives (#9394)

Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
  • Loading branch information
OzakIOne and slorber committed Oct 24, 2023
1 parent 56cc8e8 commit c6762a2
Show file tree
Hide file tree
Showing 19 changed files with 506 additions and 26 deletions.
2 changes: 2 additions & 0 deletions argos/playwright.config.ts
Expand Up @@ -14,6 +14,8 @@ import type {PlaywrightTestConfig} from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: './tests',

timeout: 60000,

reporter: [['list'], ['@argos-ci/playwright/reporter']],

// Run website production built
Expand Down
8 changes: 6 additions & 2 deletions argos/tests/screenshot.spec.ts
Expand Up @@ -36,8 +36,12 @@ function isBlacklisted(pathname: string) {
}
// Some paths explicitly blacklisted
const BlacklistedPathnames: string[] = [
'/feature-requests', // Flaky because of Canny widget
'/community/canary', // Flaky because of dynamic canary version fetched from npm
// Flaky because of Canny widget
'/feature-requests',
// Flaky because of dynamic canary version fetched from npm
'/community/canary',
// Long blog post with many image carousels, often timeouts
'/blog/2022/08/01/announcing-docusaurus-2.0',
];

return (
Expand Down
4 changes: 4 additions & 0 deletions packages/docusaurus-mdx-loader/src/loader.ts
Expand Up @@ -11,6 +11,7 @@ import {
parseFrontMatter,
escapePath,
getFileLoaderUtils,
getWebpackLoaderCompilerName,
} from '@docusaurus/utils';
import stringifyObject from 'stringify-object';
import preprocessor from './preprocessor';
Expand Down Expand Up @@ -134,10 +135,12 @@ export async function mdxLoader(
this: LoaderContext<Options>,
fileString: string,
): Promise<void> {
const compilerName = getWebpackLoaderCompilerName(this);
const callback = this.async();
const filePath = this.resourcePath;
const reqOptions: Options = this.getOptions();
const {query} = this;

ensureMarkdownConfig(reqOptions);

const {frontMatter} = parseFrontMatter(fileString);
Expand Down Expand Up @@ -165,6 +168,7 @@ export async function mdxLoader(
content: preprocessedContent,
filePath,
frontMatter,
compilerName,
});
} catch (errorUnknown) {
const error = errorUnknown as Error;
Expand Down
8 changes: 7 additions & 1 deletion packages/docusaurus-mdx-loader/src/processor.ts
Expand Up @@ -15,8 +15,10 @@ import details from './remark/details';
import head from './remark/head';
import mermaid from './remark/mermaid';
import transformAdmonitions from './remark/admonitions';
import unusedDirectivesWarning from './remark/unusedDirectives';
import codeCompatPlugin from './remark/mdx1Compat/codeCompatPlugin';
import {getFormat} from './format';
import type {WebpackCompilerName} from '@docusaurus/utils';
import type {MDXFrontMatter} from './frontMatter';
import type {Options} from './loader';
import type {AdmonitionOptions} from './remark/admonitions';
Expand All @@ -37,10 +39,12 @@ type SimpleProcessor = {
content,
filePath,
frontMatter,
compilerName,
}: {
content: string;
filePath: string;
frontMatter: {[key: string]: unknown};
compilerName: WebpackCompilerName;
}) => Promise<SimpleProcessorResult>;
};

Expand Down Expand Up @@ -123,6 +127,7 @@ async function createProcessorFactory() {
gfm,
options.markdownConfig.mdx1Compat.comments ? comment : null,
...(options.remarkPlugins ?? []),
unusedDirectivesWarning,
].filter((plugin): plugin is MDXPlugin => Boolean(plugin));

// codeCompatPlugin needs to be applied last after user-provided plugins
Expand Down Expand Up @@ -167,12 +172,13 @@ async function createProcessorFactory() {
});

return {
process: async ({content, filePath, frontMatter}) => {
process: async ({content, filePath, frontMatter, compilerName}) => {
const vfile = new VFile({
value: content,
path: filePath,
data: {
frontMatter,
compilerName,
},
});
return mdxProcessor.process(vfile).then((result) => ({
Expand Down
Expand Up @@ -35,6 +35,7 @@ const plugin: Plugin = function plugin(
const {toString} = await import('mdast-util-to-string');
visit(root, 'heading', (headingNode: Heading, index, parent) => {
if (headingNode.depth === 1) {
vfile.data.compilerName;
vfile.data.contentTitle = toString(headingNode);
if (removeContentTitle) {
parent!.children.splice(index, 1);
Expand Down
6 changes: 4 additions & 2 deletions packages/docusaurus-mdx-loader/src/remark/mermaid/index.ts
Expand Up @@ -6,6 +6,8 @@
*/

import visit from 'unist-util-visit';
import {transformNode} from '../utils';

// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Code} from 'mdast';
Expand All @@ -16,10 +18,10 @@ import type {Code} from 'mdast';
// by theme-mermaid itself
export default function plugin(): Transformer {
return (root) => {
visit(root, 'code', (node: Code, index, parent) => {
visit(root, 'code', (node: Code) => {
if (node.lang === 'mermaid') {
// TODO migrate to mdxJsxFlowElement? cf admonitions
parent!.children.splice(index, 1, {
transformNode(node, {
type: 'mermaidCodeBlock',
data: {
hName: 'mermaid',
Expand Down
Expand Up @@ -20,7 +20,7 @@ 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';
import {assetRequireAttributeValue, transformNode} 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
Expand Down Expand Up @@ -110,14 +110,12 @@ ${(err as Error).message}`;
}
}

Object.keys(jsxNode).forEach(
(key) => delete jsxNode[key as keyof typeof jsxNode],
);

jsxNode.type = 'mdxJsxTextElement';
jsxNode.name = 'img';
jsxNode.attributes = attributes;
jsxNode.children = [];
transformNode(jsxNode, {
type: 'mdxJsxTextElement',
name: 'img',
attributes,
children: [],
});
}

async function ensureImageFileExist(imagePath: string, sourceFilePath: string) {
Expand Down
Expand Up @@ -17,7 +17,7 @@ import {
} from '@docusaurus/utils';
import visit from 'unist-util-visit';
import escapeHtml from 'escape-html';
import {assetRequireAttributeValue} from '../utils';
import {assetRequireAttributeValue, transformNode} 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
Expand Down Expand Up @@ -90,14 +90,12 @@ async function toAssetRequireNode(

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;
transformNode(jsxNode, {
type: 'mdxJsxTextElement',
name: 'a',
attributes,
children,
});
}

async function ensureAssetFileExist(assetPath: string, sourceFilePath: string) {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

@@ -0,0 +1,86 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`directives remark plugin - client compiler default behavior for container directives: console 1`] = `
[
[
"[WARNING] Docusaurus found 1 unused Markdown directives in file "packages/docusaurus-mdx-loader/src/remark/unusedDirectives/__tests__/__fixtures__/containerDirectives.md"
- :::unusedDirective (7:1)
Your content might render in an unexpected way. Visit https://github.com/facebook/docusaurus/pull/9394 to find out why and how to fix it.",
],
]
`;

exports[`directives remark plugin - client compiler default behavior for container directives: result 1`] = `
"<admonition type="danger"><p>Take care of snowstorms...</p></admonition>
<div><p>unused directive content</p></div>
<p>:::NotAContainerDirective with a phrase after</p>
<p>:::</p>
<p>Phrase before :::NotAContainerDirective</p>
<p>:::</p>"
`;

exports[`directives remark plugin - client compiler default behavior for leaf directives: console 1`] = `
[
[
"[WARNING] Docusaurus found 1 unused Markdown directives in file "packages/docusaurus-mdx-loader/src/remark/unusedDirectives/__tests__/__fixtures__/leafDirectives.md"
- ::unusedLeafDirective (1:1)
Your content might render in an unexpected way. Visit https://github.com/facebook/docusaurus/pull/9394 to find out why and how to fix it.",
],
]
`;

exports[`directives remark plugin - client compiler default behavior for leaf directives: result 1`] = `
"<div></div>
<p>Leaf directive in a phrase ::NotALeafDirective</p>
<p>::NotALeafDirective with a phrase after</p>"
`;

exports[`directives remark plugin - client compiler default behavior for text directives: console 1`] = `
[
[
"[WARNING] Docusaurus found 2 unused Markdown directives in file "packages/docusaurus-mdx-loader/src/remark/unusedDirectives/__tests__/__fixtures__/textDirectives.md"
- :textDirective3 (9:7)
- :textDirective4 (11:7)
Your content might render in an unexpected way. Visit https://github.com/facebook/docusaurus/pull/9394 to find out why and how to fix it.",
],
]
`;

exports[`directives remark plugin - client compiler default behavior for text directives: result 1`] = `
"<p>Simple: textDirective1</p>
<pre><code class="language-sh">Simple: textDirectiveCode
</code></pre>
<p>Simple:textDirective2</p>
<p>Simple<div>label</div></p>
<p>Simple<div></div></p>
<p>Simple:textDirective5</p>
<pre><code class="language-sh">Simple:textDirectiveCode
</code></pre>"
`;

exports[`directives remark plugin - server compiler default behavior for container directives: result 1`] = `
"<admonition type="danger"><p>Take care of snowstorms...</p></admonition>
<div><p>unused directive content</p></div>
<p>:::NotAContainerDirective with a phrase after</p>
<p>:::</p>
<p>Phrase before :::NotAContainerDirective</p>
<p>:::</p>"
`;

exports[`directives remark plugin - server compiler default behavior for leaf directives: result 1`] = `
"<div></div>
<p>Leaf directive in a phrase ::NotALeafDirective</p>
<p>::NotALeafDirective with a phrase after</p>"
`;

exports[`directives remark plugin - server compiler default behavior for text directives: result 1`] = `
"<p>Simple: textDirective1</p>
<pre><code class="language-sh">Simple: textDirectiveCode
</code></pre>
<p>Simple:textDirective2</p>
<p>Simple<div>label</div></p>
<p>Simple<div></div></p>
<p>Simple:textDirective5</p>
<pre><code class="language-sh">Simple:textDirectiveCode
</code></pre>"
`;

0 comments on commit c6762a2

Please sign in to comment.