Preserve code element node meta for rehype syntax highlighters (#5335)

This commit is contained in:
Bjorn Lu 2022-11-09 21:32:13 +08:00 committed by GitHub
parent dc00ca4648
commit dca762cf73
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 1 deletions

View file

@ -0,0 +1,5 @@
---
'@astrojs/mdx': patch
---
Preserve code element node `data.meta` in `properties.metastring` for rehype syntax highlighters, like `rehype-pretty-code``

View file

@ -39,6 +39,7 @@
"github-slugger": "^1.4.0", "github-slugger": "^1.4.0",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"kleur": "^4.1.4", "kleur": "^4.1.4",
"rehype-pretty-code": "^0.4.0",
"rehype-raw": "^6.1.1", "rehype-raw": "^6.1.1",
"remark-frontmatter": "^4.0.1", "remark-frontmatter": "^4.0.1",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",

View file

@ -11,6 +11,7 @@ import remarkSmartypants from 'remark-smartypants';
import type { Data, VFile } from 'vfile'; import type { Data, VFile } from 'vfile';
import { MdxOptions } from './index.js'; import { MdxOptions } from './index.js';
import rehypeCollectHeadings from './rehype-collect-headings.js'; import rehypeCollectHeadings from './rehype-collect-headings.js';
import rehypeMetaString from './rehype-meta-string.js';
import remarkPrism from './remark-prism.js'; import remarkPrism from './remark-prism.js';
import remarkShiki from './remark-shiki.js'; import remarkShiki from './remark-shiki.js';
import { jsToTreeNode } from './utils.js'; import { jsToTreeNode } from './utils.js';
@ -150,6 +151,8 @@ export function getRehypePlugins(
let rehypePlugins: PluggableList = [ let rehypePlugins: PluggableList = [
// getHeadings() is guaranteed by TS, so we can't allow user to override // getHeadings() is guaranteed by TS, so we can't allow user to override
rehypeCollectHeadings, rehypeCollectHeadings,
// ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters
rehypeMetaString,
// rehypeRaw allows custom syntax highlighters to work without added config // rehypeRaw allows custom syntax highlighters to work without added config
[rehypeRaw, { passThrough: nodeTypes }] as any, [rehypeRaw, { passThrough: nodeTypes }] as any,
]; ];

View file

@ -0,0 +1,17 @@
import { visit } from 'unist-util-visit';
/**
* Moves `data.meta` to `properties.metastring` for the `code` element node
* as `rehype-raw` strips `data` from all nodes, which may contain useful information.
* e.g. ```js {1:3} => metastring: "{1:3}"
*/
export default function rehypeMetaString() {
return function (tree: any) {
visit(tree, (node) => {
if (node.type === 'element' && node.tagName === 'code' && node.data?.meta) {
node.properties ??= {};
node.properties.metastring = node.data.meta;
}
});
};
}

View file

@ -1,6 +1,6 @@
# Syntax highlighting # Syntax highlighting
```astro ```astro {2}
--- ---
const handlesAstroSyntax = true const handlesAstroSyntax = true
--- ---

View file

@ -4,6 +4,7 @@ import { expect } from 'chai';
import { parseHTML } from 'linkedom'; import { parseHTML } from 'linkedom';
import { loadFixture } from '../../../astro/test/test-utils.js'; import { loadFixture } from '../../../astro/test/test-utils.js';
import shikiTwoslash from 'remark-shiki-twoslash'; import shikiTwoslash from 'remark-shiki-twoslash';
import rehypePrettyCode from 'rehype-pretty-code';
const FIXTURE_ROOT = new URL('./fixtures/mdx-syntax-hightlighting/', import.meta.url); const FIXTURE_ROOT = new URL('./fixtures/mdx-syntax-hightlighting/', import.meta.url);
@ -88,4 +89,31 @@ describe('MDX syntax highlighting', () => {
const twoslashCodeBlock = document.querySelector('pre.shiki'); const twoslashCodeBlock = document.querySelector('pre.shiki');
expect(twoslashCodeBlock).to.not.be.null; expect(twoslashCodeBlock).to.not.be.null;
}); });
it('supports custom highlighter - rehype-pretty-code', async () => {
const fixture = await loadFixture({
root: FIXTURE_ROOT,
markdown: {
syntaxHighlight: false,
},
integrations: [
mdx({
rehypePlugins: [
[
rehypePrettyCode,
{
onVisitHighlightedLine(node) {
node.properties.style = 'background-color:#000000';
},
},
],
],
}),
],
});
await fixture.build();
const html = await fixture.readFile('/index.html');
expect(html).to.include('style="background-color:#000000"')
});
}); });

View file

@ -2782,6 +2782,7 @@ importers:
mdast-util-to-string: ^3.1.0 mdast-util-to-string: ^3.1.0
mocha: ^9.2.2 mocha: ^9.2.2
reading-time: ^1.5.0 reading-time: ^1.5.0
rehype-pretty-code: ^0.4.0
rehype-raw: ^6.1.1 rehype-raw: ^6.1.1
remark-frontmatter: ^4.0.1 remark-frontmatter: ^4.0.1
remark-gfm: ^3.0.1 remark-gfm: ^3.0.1
@ -2802,6 +2803,7 @@ importers:
github-slugger: 1.5.0 github-slugger: 1.5.0
gray-matter: 4.0.3 gray-matter: 4.0.3
kleur: 4.1.5 kleur: 4.1.5
rehype-pretty-code: 0.4.0_shiki@0.11.1
rehype-raw: 6.1.1 rehype-raw: 6.1.1
remark-frontmatter: 4.0.1 remark-frontmatter: 4.0.1
remark-gfm: 3.0.1 remark-gfm: 3.0.1
@ -15280,6 +15282,10 @@ packages:
unist-util-visit-children: 1.1.4 unist-util-visit-children: 1.1.4
dev: false dev: false
/parse-numeric-range/1.3.0:
resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==}
dev: false
/parse-package-name/1.0.0: /parse-package-name/1.0.0:
resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==} resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==}
dev: true dev: true
@ -16210,6 +16216,16 @@ packages:
unified: 10.1.2 unified: 10.1.2
dev: false dev: false
/rehype-pretty-code/0.4.0_shiki@0.11.1:
resolution: {integrity: sha512-Bp91nfo4blpgCXlvGP1hsG+kRFfjqBVU09o1RFcnNA62u+iIzJiJRGzpfBj4FaItq7CEQL5ASGB7vLxN5xCvyA==}
engines: {node: ^12.16.0 || >=13.2.0}
peerDependencies:
shiki: '*'
dependencies:
parse-numeric-range: 1.3.0
shiki: 0.11.1
dev: false
/rehype-raw/6.1.1: /rehype-raw/6.1.1:
resolution: {integrity: sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==} resolution: {integrity: sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==}
dependencies: dependencies: