diff options
author | 2021-04-08 15:17:00 -0400 | |
---|---|---|
committer | 2021-04-08 15:17:00 -0400 | |
commit | 72ae661e9e6f7b32adf9e6a47cdc6352dfa2a27d (patch) | |
tree | 3bc185025ee58360d05e509eb0873d796e9cb7a5 /src/compiler/optimize | |
parent | 2b346d7a4c08b2c6ab6276751a8a984ba050656f (diff) | |
download | astro-72ae661e9e6f7b32adf9e6a47cdc6352dfa2a27d.tar.gz astro-72ae661e9e6f7b32adf9e6a47cdc6352dfa2a27d.tar.zst astro-72ae661e9e6f7b32adf9e6a47cdc6352dfa2a27d.zip |
Add support for syntax highlighting of code blocks (#65)
* Add support for syntax highlighting of code blocks
* Escape usage of backtick strings
* Add workspace root for snowpack
* Use prismjs/components as an external module
Diffstat (limited to 'src/compiler/optimize')
-rw-r--r-- | src/compiler/optimize/index.ts | 7 | ||||
-rw-r--r-- | src/compiler/optimize/prism.ts | 85 |
2 files changed, 89 insertions, 3 deletions
diff --git a/src/compiler/optimize/index.ts b/src/compiler/optimize/index.ts index a7bf828e0..fcbd6e950 100644 --- a/src/compiler/optimize/index.ts +++ b/src/compiler/optimize/index.ts @@ -7,6 +7,7 @@ import { walk } from 'estree-walker'; import optimizeStyles from './styles.js'; import optimizeDoctype from './doctype.js'; import optimizeModuleScripts from './module-scripts.js'; +import optimizeCodeBlocks from './prism.js'; interface VisitorCollection { enter: Map<string, VisitorFn[]>; @@ -57,7 +58,7 @@ function walkAstWithVisitors(tmpl: TemplateNode, collection: VisitorCollection) if (collection.enter.has(node.type)) { const fns = collection.enter.get(node.type)!; for (let fn of fns) { - fn(node, parent, key, index); + fn.call(this, node, parent, key, index); } } }, @@ -65,7 +66,7 @@ function walkAstWithVisitors(tmpl: TemplateNode, collection: VisitorCollection) if (collection.leave.has(node.type)) { const fns = collection.leave.get(node.type)!; for (let fn of fns) { - fn(node, parent, key, index); + fn.call(this, node, parent, key, index); } } }, @@ -83,7 +84,7 @@ export async function optimize(ast: Ast, opts: OptimizeOptions) { const cssVisitors = createVisitorCollection(); const finalizers: Array<() => Promise<void>> = []; - const optimizers = [optimizeStyles(opts), optimizeDoctype(opts), optimizeModuleScripts(opts)]; + const optimizers = [optimizeStyles(opts), optimizeDoctype(opts), optimizeModuleScripts(opts), optimizeCodeBlocks(ast.module)]; for (const optimizer of optimizers) { collectVisitors(optimizer, htmlVisitors, cssVisitors, finalizers); diff --git a/src/compiler/optimize/prism.ts b/src/compiler/optimize/prism.ts new file mode 100644 index 000000000..2a96ab73d --- /dev/null +++ b/src/compiler/optimize/prism.ts @@ -0,0 +1,85 @@ +import type { Optimizer } from '../../@types/optimizer'; +import type { Script } from '../../parser/interfaces'; +import { getAttrValue } from '../../ast.js'; + +const PRISM_IMPORT = `import Prism from 'astro/components/Prism.astro';\n`; +const prismImportExp = /import Prism from ['"]astro\/components\/Prism.astro['"]/; + +function escape(code: string) { + return code.replace(/[`$]/g, match => { + return '\\' + match; + }); +} + +export default function (module: Script): Optimizer { + let usesPrism = false; + + return { + visitors: { + html: { + Element: { + enter(node) { + if (node.name !== 'code') return; + const className = getAttrValue(node.attributes, 'class') || ''; + const classes = className.split(' '); + + let lang; + for (let cn of classes) { + const matches = /language-(.+)/.exec(cn); + if (matches) { + lang = matches[1]; + } + } + + if (!lang) return; + + let code; + if (node.children?.length) { + code = node.children[0].data; + } + + const repl = { + start: 0, + end: 0, + type: 'InlineComponent', + name: 'Prism', + attributes: [ + { + type: 'Attribute', + name: 'lang', + value: [ + { + type: 'Text', + raw: lang, + data: lang, + }, + ], + }, + { + type: 'Attribute', + name: 'code', + value: [ + { + type: 'MustacheTag', + content: '`' + escape(code) + '`', + }, + ], + }, + ], + children: [], + }; + + this.replace(repl); + usesPrism = true; + }, + }, + }, + }, + async finalize() { + // Add the Prism import if needed. + if (usesPrism && !prismImportExp.test(module.content)) { + module.content = PRISM_IMPORT + module.content; + } + }, + }; +} |