UNPKG

6.65 kBJavaScriptView Raw
1// Docs:
2// https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-5.0&tabs=visual-studio
3// https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-5.0
4
5(function (Prism) {
6
7 var commentLike = /\/(?![/*])|\/\/.*[\r\n]|\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\//.source;
8 var stringLike =
9 /@(?!")|"(?:[^\r\n\\"]|\\.)*"|@"(?:[^\\"]|""|\\[\s\S])*"(?!")/.source +
10 '|' +
11 /'(?:(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'|(?=[^\\](?!')))/.source;
12
13 /**
14 * Creates a nested pattern where all occurrences of the string `<<self>>` are replaced with the pattern itself.
15 *
16 * @param {string} pattern
17 * @param {number} depthLog2
18 * @returns {string}
19 */
20 function nested(pattern, depthLog2) {
21 for (var i = 0; i < depthLog2; i++) {
22 pattern = pattern.replace(/<self>/g, function () { return '(?:' + pattern + ')'; });
23 }
24 return pattern
25 .replace(/<self>/g, '[^\\s\\S]')
26 .replace(/<str>/g, '(?:' + stringLike + ')')
27 .replace(/<comment>/g, '(?:' + commentLike + ')');
28 }
29
30 var round = nested(/\((?:[^()'"@/]|<str>|<comment>|<self>)*\)/.source, 2);
31 var square = nested(/\[(?:[^\[\]'"@/]|<str>|<comment>|<self>)*\]/.source, 1);
32 var curly = nested(/\{(?:[^{}'"@/]|<str>|<comment>|<self>)*\}/.source, 2);
33 var angle = nested(/<(?:[^<>'"@/]|<comment>|<self>)*>/.source, 1);
34
35 var inlineCs = /@/.source +
36 /(?:await\b\s*)?/.source +
37 '(?:' + /(?!await\b)\w+\b/.source + '|' + round + ')' +
38 '(?:' + /[?!]?\.\w+\b/.source + '|' + '(?:' + angle + ')?' + round + '|' + square + ')*' +
39 /(?![?!\.(\[]|<(?!\/))/.source;
40
41 // Note about the above bracket patterns:
42 // They all ignore HTML expressions that might be in the C# code. This is a problem because HTML (like strings and
43 // comments) is parsed differently. This is a huge problem because HTML might contain brackets and quotes which
44 // messes up the bracket and string counting implemented by the above patterns.
45 //
46 // This problem is not fixable because 1) HTML expression are highly context sensitive and very difficult to detect
47 // and 2) they require one capturing group at every nested level. See the `tagRegion` pattern to admire the
48 // complexity of an HTML expression.
49 //
50 // To somewhat alleviate the problem a bit, the patterns for characters (e.g. 'a') is very permissive, it also
51 // allows invalid characters to support HTML expressions like this: <p>That's it!</p>.
52
53 var tagAttrInlineCs = /@(?![\w()])/.source + '|' + inlineCs;
54 var tagAttrValue = '(?:' +
55 /"[^"@]*"|'[^'@]*'|[^\s'"@>=]+(?=[\s>])/.source +
56 '|' +
57 '["\'][^"\'@]*(?:(?:' + tagAttrInlineCs + ')[^"\'@]*)+["\']' +
58 ')';
59
60 var tagAttrs = /(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*<tagAttrValue>|(?=[\s/>])))+)?/.source.replace(/<tagAttrValue>/, tagAttrValue);
61 var tagContent = /(?!\d)[^\s>\/=$<%]+/.source + tagAttrs + /\s*\/?>/.source;
62 var tagRegion =
63 /\B@?/.source +
64 '(?:' +
65 /<([a-zA-Z][\w:]*)/.source + tagAttrs + /\s*>/.source +
66 '(?:' +
67 (
68 /[^<]/.source +
69 '|' +
70 // all tags that are not the start tag
71 // eslint-disable-next-line regexp/strict
72 /<\/?(?!\1\b)/.source + tagContent +
73 '|' +
74 // nested start tag
75 nested(
76 // eslint-disable-next-line regexp/strict
77 /<\1/.source + tagAttrs + /\s*>/.source +
78 '(?:' +
79 (
80 /[^<]/.source +
81 '|' +
82 // all tags that are not the start tag
83 // eslint-disable-next-line regexp/strict
84 /<\/?(?!\1\b)/.source + tagContent +
85 '|' +
86 '<self>'
87 ) +
88 ')*' +
89 // eslint-disable-next-line regexp/strict
90 /<\/\1\s*>/.source,
91 2
92 )
93 ) +
94 ')*' +
95 // eslint-disable-next-line regexp/strict
96 /<\/\1\s*>/.source +
97 '|' +
98 /</.source + tagContent +
99 ')';
100
101 // Now for the actual language definition(s):
102 //
103 // Razor as a language has 2 parts:
104 // 1) CSHTML: A markup-like language that has been extended with inline C# code expressions and blocks.
105 // 2) C#+HTML: A variant of C# that can contain CSHTML tags as expressions.
106 //
107 // In the below code, both CSHTML and C#+HTML will be create as separate language definitions that reference each
108 // other. However, only CSHTML will be exported via `Prism.languages`.
109
110 Prism.languages.cshtml = Prism.languages.extend('markup', {});
111
112 var csharpWithHtml = Prism.languages.insertBefore('csharp', 'string', {
113 'html': {
114 pattern: RegExp(tagRegion),
115 greedy: true,
116 inside: Prism.languages.cshtml
117 },
118 }, { csharp: Prism.languages.extend('csharp', {}) });
119
120 var cs = {
121 pattern: /\S[\s\S]*/,
122 alias: 'language-csharp',
123 inside: csharpWithHtml
124 };
125
126 var inlineValue = {
127 pattern: RegExp(/(^|[^@])/.source + inlineCs),
128 lookbehind: true,
129 greedy: true,
130 alias: 'variable',
131 inside: {
132 'keyword': /^@/,
133 'csharp': cs
134 }
135 };
136
137 Prism.languages.cshtml.tag.pattern = RegExp(/<\/?/.source + tagContent);
138 Prism.languages.cshtml.tag.inside['attr-value'].pattern = RegExp(/=\s*/.source + tagAttrValue);
139 Prism.languages.insertBefore('inside', 'punctuation', { 'value': inlineValue }, Prism.languages.cshtml.tag.inside['attr-value']);
140
141 Prism.languages.insertBefore('cshtml', 'prolog', {
142 'razor-comment': {
143 pattern: /@\*[\s\S]*?\*@/,
144 greedy: true,
145 alias: 'comment'
146 },
147
148 'block': {
149 pattern: RegExp(
150 /(^|[^@])@/.source +
151 '(?:' +
152 [
153 // @{ ... }
154 curly,
155 // @code{ ... }
156 /(?:code|functions)\s*/.source + curly,
157 // @for (...) { ... }
158 /(?:for|foreach|lock|switch|using|while)\s*/.source + round + /\s*/.source + curly,
159 // @do { ... } while (...);
160 /do\s*/.source + curly + /\s*while\s*/.source + round + /(?:\s*;)?/.source,
161 // @try { ... } catch (...) { ... } finally { ... }
162 /try\s*/.source + curly + /\s*catch\s*/.source + round + /\s*/.source + curly + /\s*finally\s*/.source + curly,
163 // @if (...) {...} else if (...) {...} else {...}
164 /if\s*/.source + round + /\s*/.source + curly + '(?:' + /\s*else/.source + '(?:' + /\s+if\s*/.source + round + ')?' + /\s*/.source + curly + ')*',
165 // @helper Ident(params) { ... }
166 /helper\s+\w+\s*/.source + round + /\s*/.source + curly,
167 ].join('|') +
168 ')'
169 ),
170 lookbehind: true,
171 greedy: true,
172 inside: {
173 'keyword': /^@\w*/,
174 'csharp': cs
175 }
176 },
177
178 'directive': {
179 pattern: /^([ \t]*)@(?:addTagHelper|attribute|implements|inherits|inject|layout|model|namespace|page|preservewhitespace|removeTagHelper|section|tagHelperPrefix|using)(?=\s).*/m,
180 lookbehind: true,
181 greedy: true,
182 inside: {
183 'keyword': /^@\w+/,
184 'csharp': cs
185 }
186 },
187
188 'value': inlineValue,
189
190 'delegate-operator': {
191 pattern: /(^|[^@])@(?=<)/,
192 lookbehind: true,
193 alias: 'operator'
194 }
195 });
196
197 Prism.languages.razor = Prism.languages.cshtml;
198
199}(Prism));