1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
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['"]/;
/** escaping code samples that contain template string replacement parts, ${foo} or example. */
function escape(code: string) {
return code.replace(/[`$]/g, (match) => {
return '\\' + match;
});
}
/** default export - Transform prism */
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',
codeChunks: ['`' + escape(code) + '`'],
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;
}
},
};
}
|