summaryrefslogtreecommitdiff
path: root/src/compiler/transform/prism.ts
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@matthewphillips.info> 2021-04-09 14:09:13 -0400
committerGravatar GitHub <noreply@github.com> 2021-04-09 14:09:13 -0400
commitad9c3b1d8dbf1c3aff75497271347ed36ea38a0b (patch)
tree8e0aed5ea1783df8322e1db589e84f9579152ba3 /src/compiler/transform/prism.ts
parent084845f79d064626d5f5069ce7b945e3b44bdbd7 (diff)
downloadastro-ad9c3b1d8dbf1c3aff75497271347ed36ea38a0b.tar.gz
astro-ad9c3b1d8dbf1c3aff75497271347ed36ea38a0b.tar.zst
astro-ad9c3b1d8dbf1c3aff75497271347ed36ea38a0b.zip
Parse inner JSX as Astro (#67)
* Parse inner JSX as Astro This completes the compiler changes, updating the parser so that it parses inner "JSX" as Astro. It does this by finding the start and end of HTML tags and feeds that back into the parser. The result is a structure like this: ``` { type: 'MustacheTag', expression: [ { type: 'Expression', codeStart: 'colors.map(color => (', codeEnd: '}}' children: [ { type: 'Fragment', children: [ { type: 'Element', name: 'div' } ] } ] } ] } ``` There is a new Node type, `Expression`. Note that `MustacheTag` remains in the tree, all it contains is an Expression though. I could spend some time trying to remove it, there's just a few places that expect it to exist. * Update import to the transform * Transform prism components into expressions
Diffstat (limited to 'src/compiler/transform/prism.ts')
-rw-r--r--src/compiler/transform/prism.ts90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/compiler/transform/prism.ts b/src/compiler/transform/prism.ts
new file mode 100644
index 000000000..628dcce7e
--- /dev/null
+++ b/src/compiler/transform/prism.ts
@@ -0,0 +1,90 @@
+import type { Transformer } from '../../@types/transformer';
+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): Transformer {
+ 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',
+ expression: {
+ type: 'Expression',
+ codeStart: '`' + escape(code) + '`',
+ codeEnd: '',
+ children: []
+ }
+ },
+ ],
+ },
+ ],
+ 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;
+ }
+ },
+ };
+}