Skip to content

Commit

Permalink
fix: support nested container syntax in list and component
Browse files Browse the repository at this point in the history
close #1513
  • Loading branch information
JounQin committed Jan 10, 2025
1 parent 5612c87 commit 7ef32df
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 30 deletions.
10 changes: 10 additions & 0 deletions e2e/fixtures/github-alert-mdxjs/doc/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@
> > Nested blockquote
> ![Image Alt Text](https://github.com/web-infra-dev/rspress/assets/39261479/999e7946-45ff-45d5-b9cd-594e634e0e5a)
1. Title
> [!INFO]
> This is a 'info' style block.
- Title
> [!WARNING]
> This is a 'warning' style block.
14 changes: 11 additions & 3 deletions e2e/tests/github-alert-mdxjs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ test.describe('github alert syntax in mdx-js', async () => {
}) => {
await page.goto(`http://localhost:${appPort}`);

const directives = await page.$$(
const topLevelDirectives = await page.$$(
'.rspress-doc > [class^="rspress-directive"]',
);
expect(directives.length).toEqual(7);

expect(topLevelDirectives.length).toEqual(8);

const listDirectives = await page.$$(
'.rspress-doc > ul > li > [class^="rspress-directive"]',
);
expect(listDirectives.length).toEqual(1);

const containerTypes = await Promise.all(
directives.map(async directive => {
[...topLevelDirectives, ...listDirectives].map(async directive => {
const className = await directive.getAttribute('class');
return className?.split(' ')[1];
}),
Expand All @@ -43,6 +49,8 @@ test.describe('github alert syntax in mdx-js', async () => {
'danger',
'info',
'details',
'info',
'warning',
]);
});
});
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"@types/html-to-text": "^9.0.4",
"@types/jest": "~29.5.14",
"@types/lodash-es": "^4.17.12",
"@types/mdast": "^4.0.4",
"@types/mdast": "^3.0.0",
"@types/node": "^18.11.17",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-api-docgen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"devDependencies": {
"@microsoft/api-extractor": "^7.48.1",
"@rslib/core": "0.2.2",
"@types/mdast": "^4.0.4",
"@types/mdast": "^3.0.0",
"@types/node": "^18.11.17",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
Expand Down
4 changes: 3 additions & 1 deletion packages/plugin-container-syntax/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
"devDependencies": {
"@microsoft/api-extractor": "^7.48.1",
"@rslib/core": "0.2.2",
"@types/mdast": "^4.0.4",
"@types/mdast": "^3.0.0",
"mdast-util-mdx-jsx": "^2.0.0",
"rehype-stringify": "^9.0.4",
"remark-mdx": "2.3.0",
"remark-parse": "^10.0.2",
"remark-rehype": "^10.1.0",
"unified": "^10.1.2"
Expand Down
16 changes: 14 additions & 2 deletions packages/plugin-container-syntax/src/remarkPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* In fact, the syntax is usually used in SSG Frameworks, such as VuePress/Docusaurus.
* So the plugin is used to solve the problem and support both syntaxes in above cases.
*/

/// <reference types="mdast-util-mdx-jsx" />
import type {
BlockContent,
Content,
Expand Down Expand Up @@ -114,12 +114,24 @@ const createContainer = (
* 2. If it is, crawl the next nodes, if there is a paragraph node, we need to check if it is the end of the container directive. If not, we need to push it to the children of the container directive node.
* 3. If we find the end of the container directive, we remove the visited node and insert the custom container directive node.
*/
function transformer(tree: Root) {
function transformer(tree: Parent) {
let i = 0;
try {
while (i < tree.children.length) {
const node = tree.children[i];

console.log(JSON.stringify(node, null, 2));

// The list ast must be traversed to find the container directive,
// especially for the unordered list whose ast is very different
if (node.type === 'list') {
for (const item of node.children) {
transformer(item);
}
} else if (node.type === 'mdxJsxFlowElement') {
transformer(node);
}

/**
* Support for Github Alerts
* > [!TIP]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,62 @@ exports[`remark-container > github alerts ~ note 1`] = `"<div class="rspress-dir
exports[`remark-container > github alerts ~ tip 1`] = `"<div class="rspress-directive tip"><div class="rspress-directive-title">TIP</div><div class="rspress-directive-content"><p><strong>Helpful advice for doing things better or more easily.</strong></p></div></div>"`;
exports[`remark-container > github alerts ~ warning 1`] = `"<div class="rspress-directive warning"><div class="rspress-directive-title">WARNING</div><div class="rspress-directive-content"><p>Use <code>dummy</code> instead of <code>demo</code></p></div></div>"`;
exports[`remark-container > nested in list - github alerts 1`] = `
"<ul>
<li>
<p>Title</p>
<div class="rspress-directive tip"><div class="rspress-directive-title">TIP</div><div class="rspress-directive-content"><p>This is a 'tip' style block.</p></div></div>
</li>
</ul>
<ol>
<li>Title</li>
</ol>
<div class="rspress-directive tip"><div class="rspress-directive-title">TIP</div><div class="rspress-directive-content"><p>This is a 'tip' style block.</p></div></div>"
`;
exports[`remark-container > nested in ordered list 1`] = `
"<ol>
<li>Title1</li>
</ol>
<div class="rspress-directive tip"><div class="rspress-directive-title">TIP</div><div class="rspress-directive-content"><p>
This is a tip.</p></div></div>
<ol start="2">
<li>Title2</li>
</ol>"
`;
exports[`remark-container > nested in ordered list inside mdx component 1`] = `
"<div><div><div><ol>
<li>Title1</li>
</ol><div class="rspress-directive tip"><div class="rspress-directive-title">TIP</div><div class="rspress-directive-content"><p>
This is a tip.</p></div></div><ol start="2">
<li>Title2</li>
</ol></div></div></div>"
`;
exports[`remark-container > nested in unordered list 1`] = `
"<ul>
<li>
<p>Title1</p>
<div class="rspress-directive tip"><div class="rspress-directive-title">TIP</div><div class="rspress-directive-content"><p>
This is a tip.</p></div></div>
</li>
<li>
<p>Title2</p>
</li>
</ul>"
`;
exports[`remark-container > nested in unordered list inside mdx component 1`] = `
"<div><div><div><ul>
<li>
<p>Title1</p>
<div class="rspress-directive tip"><div class="rspress-directive-title">TIP</div><div class="rspress-directive-content"><p>
This is a tip.</p></div></div>
</li>
<li>
<p>Title2</p>
</li>
</ul></div></div></div>"
`;
88 changes: 88 additions & 0 deletions packages/plugin-container-syntax/tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import rehypeStringify from 'rehype-stringify';
import remarkMdx from 'remark-mdx';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import { unified } from 'unified';
Expand All @@ -11,6 +12,9 @@ describe('remark-container', () => {
.use(remarkPluginContainer)
.use(remarkRehype)
.use(rehypeStringify);

const mdxProcessor = processor().use(remarkMdx);

test('No newline', () => {
const result = processor.processSync(`
:::tip
Expand Down Expand Up @@ -183,4 +187,88 @@ This is a details block.

expect(result.value).toMatchSnapshot();
});

test('nested in ordered list', () => {
const result = processor.processSync(`
1. Title1
:::tip
This is a tip.
:::
2. Title2
`);

expect(result.value).toMatchSnapshot();
});

test('nested in unordered list', () => {
const result = processor.processSync(`
- Title1
:::tip
This is a tip.
:::
- Title2
`);

expect(result.value).toMatchSnapshot();
});

test('nested in ordered list inside mdx component', () => {
const result = mdxProcessor.processSync(`
<div>
<div>
<div>
1. Title1
:::tip
This is a tip.
:::
2. Title2
</div>
</div>
</div>
`);

expect(result.value).toMatchSnapshot();
});

test('nested in unordered list inside mdx component', () => {
const result = mdxProcessor.processSync(`
<div>
<div>
<div>
- Title1
:::tip
This is a tip.
:::
- Title2
</div>
</div>
</div>
`);

expect(result.value).toMatchSnapshot();
});

test('nested in list - github alerts', () => {
const result = processor.processSync(`
- Title
> [!TIP]
> This is a 'tip' style block.
1. Title
> [!TIP]
> This is a 'tip' style block.
`);

expect(result.value).toMatchSnapshot();
});
});
2 changes: 1 addition & 1 deletion packages/plugin-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@types/babel__core": "^7.20.5",
"@types/babel__standalone": "^7.1.9",
"@types/babel__traverse": "^7.20.6",
"@types/mdast": "^4.0.4",
"@types/mdast": "^3.0.0",
"@types/node": "^18.11.17",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-preview/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
"devDependencies": {
"@types/lodash": "^4.17.14",
"@types/mdast": "^4.0.4",
"@types/mdast": "^3.0.0",
"@types/node": "^18.11.17",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/theme-default/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"@types/hast": "3.0.4",
"@types/jest": "~29.5.14",
"@types/lodash-es": "^4.17.12",
"@types/mdast": "^4.0.4",
"@types/mdast": "^3.0.0",
"@types/nprogress": "^0.2.3",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
Expand Down
Loading

0 comments on commit 7ef32df

Please sign in to comment.