diff --git a/packages/astro/components/Markdown.astro b/packages/astro/components/Markdown.astro index f551b98ee..dbdb4e844 100644 --- a/packages/astro/components/Markdown.astro +++ b/packages/astro/components/Markdown.astro @@ -11,7 +11,7 @@ interface InternalProps extends Props { $scope: string; } -let { content, $scope } = Astro.props as InternalProps; +let { content, class: className } = Astro.props as InternalProps; let html = null; // If no content prop provided, use the slot. @@ -23,7 +23,7 @@ if(!content) { const { code: htmlContent } = await renderMarkdown(content, { mode: 'md', $: { - scopedClassName: $scope + scopedClassName: className } }); diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js index 512a85374..a12625429 100644 --- a/packages/astro/test/astro-markdown.test.js +++ b/packages/astro/test/astro-markdown.test.js @@ -45,7 +45,6 @@ describe('Astro Markdown', () => { expect($('pre')[1].children).to.have.lengthOf(0); }); - // This doesn't work because the markdown plugin doesn't have Prism support yet. it('Runs code blocks through syntax highlighter', async () => { const html = await fixture.readFile('/code/index.html'); const $ = cheerio.load(html); @@ -54,13 +53,13 @@ describe('Astro Markdown', () => { expect($('code span').length).greaterThan(0); }); - // Blocked by lack of syntax highlighting - it.skip('Scoped styles should not break syntax highlight', async () => { + it('Scoped styles should not break syntax highlight', async () => { const html = await fixture.readFile('/scopedStyles-code/index.html'); const $ = cheerio.load(html); // test 1:
 tag has scopedStyle class passed down
     expect($('pre').is('[class]')).to.equal(true);
+    expect($('pre').attr('class').split(' ').length).to.equal(2)
 
     // test 2: 
 tag has correct language
     expect($('pre').hasClass('language-js')).to.equal(true);
@@ -69,7 +68,7 @@ describe('Astro Markdown', () => {
     expect($('code').hasClass('language-js')).to.equal(true);
 
     // test 4: There are child spans in code blocks
-    expect($('code span').length).toBeGreaterThan(0);
+    expect($('code span').length).to.be.greaterThan(0);
   });
 
   it('Renders correctly when deeply nested on a page', async () => {
@@ -90,9 +89,8 @@ describe('Astro Markdown', () => {
     expect($('.c > h2').text()).to.equal('C');
   });
 
-  it.skip('Renders dynamic content though the content attribute', async () => {
+  it('Renders dynamic content though the content attribute', async () => {
     const html = await fixture.readFile('/external/index.html');
-    console.log(html)
     const $ = cheerio.load(html);
 
     // test 1: Rendered markdown content
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/external.astro b/packages/astro/test/fixtures/astro-markdown/src/pages/external.astro
index 7a6ff066b..cf4441c4c 100644
--- a/packages/astro/test/fixtures/astro-markdown/src/pages/external.astro
+++ b/packages/astro/test/fixtures/astro-markdown/src/pages/external.astro
@@ -5,7 +5,10 @@ const outer = `# Outer`;
 const inner = `## Inner`;
 ---
 
-
+ +
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro b/packages/astro/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro new file mode 100644 index 000000000..ca0558e6d --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro @@ -0,0 +1,21 @@ +--- +import { Markdown } from 'astro/components'; +import Layout from '../layouts/content.astro'; + +--- + + +
+ + ## Interesting Topic + + ```js + const thing = () => {}; + ``` + +
+
\ No newline at end of file diff --git a/packages/astro/test/fixtures/astro-markdown/src/skipped-pages/scopedStyles-code.astro b/packages/astro/test/fixtures/astro-markdown/src/skipped-pages/scopedStyles-code.astro deleted file mode 100644 index 46d1063f2..000000000 --- a/packages/astro/test/fixtures/astro-markdown/src/skipped-pages/scopedStyles-code.astro +++ /dev/null @@ -1,14 +0,0 @@ ---- -import { Markdown } from 'astro/components'; -import Layout from '../layouts/content.astro'; - ---- - - - ## Interesting Topic - - ```js - const thing = () => {}; - ``` - - \ No newline at end of file diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 090442352..b00127ab5 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -39,6 +39,7 @@ export const DEFAULT_REHYPE_PLUGINS = [ /** Shared utility for rendering markdown */ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOptions | null) { const { remarkPlugins = DEFAULT_REMARK_PLUGINS, rehypePlugins = DEFAULT_REHYPE_PLUGINS } = opts ?? {}; + const scopedClassName = opts?.$?.scopedClassName; const { headers, rehypeCollectHeaders } = createCollectHeaders(); await Promise.all([loadRemarkExpressions(), loadRemarkJsx()]); // Vite bug: dynamically import() these because of CJS interop (this will cache) @@ -47,7 +48,7 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp .use(markdown) .use([remarkJsx]) .use([remarkExpressions]) - .use([remarkPrism]) + .use([remarkPrism(scopedClassName)]) const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins)); const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins)); @@ -56,9 +57,9 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp parser.use([[plugin, opts]]); }); - // if (scopedClassName) { - // parser.use(scopedStyles(scopedClassName)); - // } + if (scopedClassName) { + parser.use([scopedStyles(scopedClassName)]); + } //parser.use(remarkCodeBlock); parser.use([[markdownToHtml as any, { allowDangerousHtml: true, passThrough: ['raw', 'mdxTextExpression', 'mdxJsxTextElement', 'mdxJsxFlowElement']}]]); diff --git a/packages/markdown/remark/src/remark-prism.ts b/packages/markdown/remark/src/remark-prism.ts index 4e6da3810..adc9522e5 100644 --- a/packages/markdown/remark/src/remark-prism.ts +++ b/packages/markdown/remark/src/remark-prism.ts @@ -44,22 +44,30 @@ function runHighlighter(lang: string, code: string) { return { classLanguage, html }; } -/** */ -function transformer(tree: any) { - const visitor = (node: any) => { - let {lang, value} = node; - node.type = 'html'; +type MaybeString = string | null | undefined; - let { html, classLanguage } = runHighlighter(lang, value); - node.value = `
${html}
`; - return node; - }; - return visit(tree, 'code', visitor) +/** */ +function transformer(className: MaybeString) { + return function(tree: any) { + const visitor = (node: any) => { + let {lang, value} = node; + node.type = 'html'; + + let { html, classLanguage } = runHighlighter(lang, value); + let classes = [classLanguage]; + if(className) { + classes.push(className); + } + node.value = `
${html}
`; + return node; + }; + return visit(tree, 'code', visitor) + } } -function plugin() { - return transformer; +function plugin(className: MaybeString) { + return transformer.bind(null, className); } export default plugin; \ No newline at end of file