Add Prism syntax highlighting (#1598)
This commit is contained in:
parent
a1c594fc95
commit
b695c8aa15
8 changed files with 85 additions and 8 deletions
1
packages/astro-prism/index.d.ts
vendored
Normal file
1
packages/astro-prism/index.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export function addAstro(Prism: any): void;
|
|
@ -15,6 +15,7 @@
|
|||
"exports": {
|
||||
".": "./index.mjs"
|
||||
},
|
||||
"types": "./index.d.ts",
|
||||
"keywords": [],
|
||||
"author": "Skypack",
|
||||
"license": "MIT",
|
||||
|
|
|
@ -46,7 +46,7 @@ describe('Astro Markdown', () => {
|
|||
});
|
||||
|
||||
// This doesn't work because the markdown plugin doesn't have Prism support yet.
|
||||
it.skip('Runs code blocks through syntax highlighter', async () => {
|
||||
it('Runs code blocks through syntax highlighter', async () => {
|
||||
const html = await fixture.readFile('/code/index.html');
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
|
|
|
@ -18,13 +18,15 @@
|
|||
"dev": "astro-scripts dev \"src/**/*.ts\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/prism": "^0.2.2",
|
||||
"@silvenon/remark-smartypants": "^1.0.0",
|
||||
"assert": "^2.0.0",
|
||||
"github-slugger": "^1.3.0",
|
||||
"mdast-util-mdx-expression": "^1.1.0",
|
||||
"mdast-util-mdx-jsx": "^1.1.0",
|
||||
"micromark-extension-mdx-expression": "^1.0.0",
|
||||
"micromark-extension-mdx-jsx": "^1.0.0",
|
||||
"mdast-util-mdx-jsx": "^1.1.0",
|
||||
"prismjs": "^1.25.0",
|
||||
"rehype-raw": "^6.0.0",
|
||||
"rehype-stringify": "^9.0.1",
|
||||
"remark-footnotes": "^4.0.1",
|
||||
|
@ -40,6 +42,7 @@
|
|||
"//": "Important that gray-matter is in devDependencies so it gets bundled by esbuild!",
|
||||
"devDependencies": {
|
||||
"@types/github-slugger": "^1.3.0",
|
||||
"@types/prismjs": "^1.16.6",
|
||||
"gray-matter": "^4.0.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import rehypeExpressions from './rehype-expressions.js';
|
|||
import { remarkJsx, loadRemarkJsx } from './remark-jsx.js';
|
||||
import rehypeJsx from './rehype-jsx.js';
|
||||
//import { remarkCodeBlock } from './codeblock.js';
|
||||
import remarkPrism from './remark-prism.js';
|
||||
import { loadPlugins } from './load-plugins.js';
|
||||
|
||||
import { unified } from 'unified';
|
||||
|
@ -46,12 +47,13 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp
|
|||
.use(markdown)
|
||||
.use([remarkJsx])
|
||||
.use([remarkExpressions])
|
||||
.use([remarkPrism])
|
||||
|
||||
const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins));
|
||||
const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins));
|
||||
|
||||
loadedRemarkPlugins.forEach(([plugin, opts]) => {
|
||||
parser.use(plugin, opts);
|
||||
parser.use([[plugin, opts]]);
|
||||
});
|
||||
|
||||
// if (scopedClassName) {
|
||||
|
@ -59,18 +61,18 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp
|
|||
// }
|
||||
|
||||
//parser.use(remarkCodeBlock);
|
||||
parser.use(markdownToHtml, { allowDangerousHtml: true, passThrough: ['raw', 'mdxTextExpression', 'mdxJsxTextElement', 'mdxJsxFlowElement']});
|
||||
parser.use([[markdownToHtml as any, { allowDangerousHtml: true, passThrough: ['raw', 'mdxTextExpression', 'mdxJsxTextElement', 'mdxJsxFlowElement']}]]);
|
||||
|
||||
loadedRehypePlugins.forEach(([plugin, opts]) => {
|
||||
parser.use(plugin, opts);
|
||||
parser.use([[plugin, opts]]);
|
||||
});
|
||||
|
||||
parser.use(rehypeJsx).use(rehypeExpressions)
|
||||
parser.use([rehypeJsx]).use(rehypeExpressions)
|
||||
|
||||
let result: string;
|
||||
try {
|
||||
const vfile = await parser
|
||||
.use(rehypeCollectHeaders)
|
||||
.use([rehypeCollectHeaders])
|
||||
.use(rehypeStringify, { allowParseErrors: true, preferUnquoted: true, allowDangerousHtml: true })
|
||||
.process(content);
|
||||
result = vfile.toString();
|
||||
|
|
65
packages/markdown/remark/src/remark-prism.ts
Normal file
65
packages/markdown/remark/src/remark-prism.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { visit } from 'unist-util-visit';
|
||||
import Prism from 'prismjs';
|
||||
import { addAstro } from '@astrojs/prism';
|
||||
import loadLanguages from 'prismjs/components/index.js';
|
||||
const noVisit = new Set(['root', 'html', 'text']);
|
||||
|
||||
const languageMap = new Map([
|
||||
['ts', 'typescript']
|
||||
]);
|
||||
|
||||
function runHighlighter(lang: string, code: string) {
|
||||
let classLanguage = `language-${lang}`
|
||||
|
||||
if (lang == null) {
|
||||
console.warn('Prism.astro: No language provided.');
|
||||
}
|
||||
|
||||
const ensureLoaded = (lang: string) => {
|
||||
if(lang && !Prism.languages[lang]) {
|
||||
loadLanguages([lang]);
|
||||
}
|
||||
};
|
||||
|
||||
if(languageMap.has(lang)) {
|
||||
ensureLoaded(languageMap.get(lang)!);
|
||||
} else if(lang === 'astro') {
|
||||
ensureLoaded('typescript');
|
||||
addAstro(Prism);
|
||||
} else {
|
||||
ensureLoaded('markup-templating'); // Prism expects this to exist for a number of other langs
|
||||
ensureLoaded(lang);
|
||||
}
|
||||
|
||||
if(lang && !Prism.languages[lang]) {
|
||||
console.warn(`Unable to load the language: ${lang}`);
|
||||
}
|
||||
|
||||
const grammar = Prism.languages[lang];
|
||||
let html = code;
|
||||
if (grammar) {
|
||||
html = Prism.highlight(code, grammar, lang);
|
||||
}
|
||||
|
||||
return { classLanguage, html };
|
||||
}
|
||||
|
||||
/** */
|
||||
function transformer(tree: any) {
|
||||
const visitor = (node: any) => {
|
||||
let {lang, value} = node;
|
||||
node.type = 'html';
|
||||
|
||||
let { html, classLanguage } = runHighlighter(lang, value);
|
||||
node.value = `<pre class="${classLanguage}"><code class="${classLanguage}">${html}</code></pre>`;
|
||||
return node;
|
||||
};
|
||||
return visit(tree, 'code', visitor)
|
||||
}
|
||||
|
||||
|
||||
function plugin() {
|
||||
return transformer;
|
||||
}
|
||||
|
||||
export default plugin;
|
|
@ -1963,6 +1963,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.1.tgz#f8ae4fbcd2b9ba4ff934698e28778961f9cb22ca"
|
||||
integrity sha512-ARATsLdrGPUnaBvxLhUlnltcMgn7pQG312S8ccdYlnyijabrX9RN/KN/iGj9Am96CoW8e/K9628BA7Bv4XHdrA==
|
||||
|
||||
"@types/prismjs@^1.16.6":
|
||||
version "1.16.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.6.tgz#377054f72f671b36dbe78c517ce2b279d83ecc40"
|
||||
integrity sha512-dTvnamRITNqNkqhlBd235kZl3KfVJQQoT5jkXeiWSBK7i4/TLKBNLV0S1wOt8gy4E2TY722KLtdmv2xc6+Wevg==
|
||||
|
||||
"@types/prompts@^2.0.12":
|
||||
version "2.0.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.0.14.tgz#10cb8899844bb0771cabe57c1becaaaca9a3b521"
|
||||
|
@ -8782,7 +8787,7 @@ pretty-hrtime@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||
integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
|
||||
|
||||
prismjs@^1.23.0:
|
||||
prismjs@^1.23.0, prismjs@^1.25.0:
|
||||
version "1.25.0"
|
||||
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756"
|
||||
integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==
|
||||
|
|
Loading…
Reference in a new issue