UNPKG

4.05 kBJavaScriptView Raw
1(function(Prism) {
2
3var javascript = Prism.util.clone(Prism.languages.javascript);
4
5Prism.languages.jsx = Prism.languages.extend('markup', javascript);
6Prism.languages.jsx.tag.pattern = /<\/?(?:[\w.:-]+(?:\s+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'">=]+|\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\}))?|\{\s*\.{3}\s*[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\s*\}))*\s*\/?)?>/i;
7
8Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
9Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;
10Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
11
12Prism.languages.insertBefore('inside', 'attr-name', {
13 'spread': {
14 pattern: /\{\s*\.{3}\s*[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\s*\}/,
15 inside: {
16 'punctuation': /\.{3}|[{}.]/,
17 'attr-value': /\w+/
18 }
19 }
20}, Prism.languages.jsx.tag);
21
22Prism.languages.insertBefore('inside', 'attr-value',{
23 'script': {
24 // Allow for two levels of nesting
25 pattern: /=(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\})/i,
26 inside: {
27 'script-punctuation': {
28 pattern: /^=(?={)/,
29 alias: 'punctuation'
30 },
31 rest: Prism.languages.jsx
32 },
33 'alias': 'language-javascript'
34 }
35}, Prism.languages.jsx.tag);
36
37// The following will handle plain text inside tags
38var stringifyToken = function (token) {
39 if (!token) {
40 return '';
41 }
42 if (typeof token === 'string') {
43 return token;
44 }
45 if (typeof token.content === 'string') {
46 return token.content;
47 }
48 return token.content.map(stringifyToken).join('');
49};
50
51var walkTokens = function (tokens) {
52 var openedTags = [];
53 for (var i = 0; i < tokens.length; i++) {
54 var token = tokens[i];
55 var notTagNorBrace = false;
56
57 if (typeof token !== 'string') {
58 if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
59 // We found a tag, now find its kind
60
61 if (token.content[0].content[0].content === '</') {
62 // Closing tag
63 if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
64 // Pop matching opening tag
65 openedTags.pop();
66 }
67 } else {
68 if (token.content[token.content.length - 1].content === '/>') {
69 // Autoclosed tag, ignore
70 } else {
71 // Opening tag
72 openedTags.push({
73 tagName: stringifyToken(token.content[0].content[1]),
74 openedBraces: 0
75 });
76 }
77 }
78 } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
79
80 // Here we might have entered a JSX context inside a tag
81 openedTags[openedTags.length - 1].openedBraces++;
82
83 } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
84
85 // Here we might have left a JSX context inside a tag
86 openedTags[openedTags.length - 1].openedBraces--;
87
88 } else {
89 notTagNorBrace = true
90 }
91 }
92 if (notTagNorBrace || typeof token === 'string') {
93 if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
94 // Here we are inside a tag, and not inside a JSX context.
95 // That's plain text: drop any tokens matched.
96 var plainText = stringifyToken(token);
97
98 // And merge text with adjacent text
99 if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
100 plainText += stringifyToken(tokens[i + 1]);
101 tokens.splice(i + 1, 1);
102 }
103 if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
104 plainText = stringifyToken(tokens[i - 1]) + plainText;
105 tokens.splice(i - 1, 1);
106 i--;
107 }
108
109 tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
110 }
111 }
112
113 if (token.content && typeof token.content !== 'string') {
114 walkTokens(token.content);
115 }
116 }
117};
118
119Prism.hooks.add('after-tokenize', function (env) {
120 if (env.language !== 'jsx' && env.language !== 'tsx') {
121 return;
122 }
123 walkTokens(env.tokens);
124});
125
126}(Prism));