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-loader): Remark plugin to report unused MDX / Markdown directives #9394

Merged
merged 27 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1c2b05b
wip: unused directives plugin
OzakIOne Oct 11, 2023
2f6cddb
wip: parse tree from root
OzakIOne Oct 12, 2023
0478dd8
wip: unit test mock
OzakIOne Oct 12, 2023
f934f84
wip: better error log
OzakIOne Oct 12, 2023
ea124d3
Merge branch 'main' into ozaki/mdx-unused-directives
slorber Oct 12, 2023
cefc3e4
prevent duplicate logging of unused directives in prod build
slorber Oct 12, 2023
f87a0b4
fix TS vfile datamap issue
slorber Oct 12, 2023
3ea1c74
wip: add text & leaf tests
OzakIOne Oct 12, 2023
6a0337a
fix: include lines in path
OzakIOne Oct 13, 2023
e4e7255
remark unused directive tests should handle compilerName option
slorber Oct 13, 2023
1b59e60
wip: improve log messages
OzakIOne Oct 13, 2023
b21537e
Merge branch 'main' into ozaki/mdx-unused-directives
slorber Oct 23, 2023
59cb00f
update unused directives snapshots
slorber Oct 23, 2023
61b41ae
refactor unused directives
slorber Oct 23, 2023
cb54192
refactor unused directives
slorber Oct 23, 2023
10d4057
refactor unused directives
slorber Oct 23, 2023
b777c29
remove annoying eslint rule
slorber Oct 23, 2023
a142e60
change format of warning
slorber Oct 23, 2023
23f6cb9
refactor
slorber Oct 23, 2023
55a0abe
Implement unused simple text directive re-serialization
slorber Oct 24, 2023
5fb34ae
use transformNode everywhere
slorber Oct 24, 2023
764e9ab
eslint
slorber Oct 24, 2023
bfa8a90
eslint
slorber Oct 24, 2023
99f83b2
fix bug + add client/server output mismatch tests
slorber Oct 24, 2023
a85f049
increase playwright timeout
slorber Oct 24, 2023
d7cf972
Merge branch 'main' into ozaki/mdx-unused-directives
slorber Oct 24, 2023
65406ac
ignore playwright path
slorber Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions argos/playwright.config.ts
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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.

Original file line number Diff line number Diff line change
@@ -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>"
`;
Loading
Loading