source: node_modules/highlight.js/lib/languages/htmlbars.js@ d24f17c

main
Last change on this file since d24f17c was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/**
2 * @param {string} value
3 * @returns {RegExp}
4 * */
5
6/**
7 * @param {RegExp | string } re
8 * @returns {string}
9 */
10function source(re) {
11 if (!re) return null;
12 if (typeof re === "string") return re;
13
14 return re.source;
15}
16
17/**
18 * @param {RegExp | string } re
19 * @returns {string}
20 */
21function anyNumberOfTimes(re) {
22 return concat('(', re, ')*');
23}
24
25/**
26 * @param {RegExp | string } re
27 * @returns {string}
28 */
29function optional(re) {
30 return concat('(', re, ')?');
31}
32
33/**
34 * @param {...(RegExp | string) } args
35 * @returns {string}
36 */
37function concat(...args) {
38 const joined = args.map((x) => source(x)).join("");
39 return joined;
40}
41
42/**
43 * Any of the passed expresssions may match
44 *
45 * Creates a huge this | this | that | that match
46 * @param {(RegExp | string)[] } args
47 * @returns {string}
48 */
49function either(...args) {
50 const joined = '(' + args.map((x) => source(x)).join("|") + ")";
51 return joined;
52}
53
54/*
55Language: Handlebars
56Requires: xml.js
57Author: Robin Ward <robin.ward@gmail.com>
58Description: Matcher for Handlebars as well as EmberJS additions.
59Website: https://handlebarsjs.com
60Category: template
61*/
62
63function handlebars(hljs) {
64 const BUILT_INS = {
65 'builtin-name': [
66 'action',
67 'bindattr',
68 'collection',
69 'component',
70 'concat',
71 'debugger',
72 'each',
73 'each-in',
74 'get',
75 'hash',
76 'if',
77 'in',
78 'input',
79 'link-to',
80 'loc',
81 'log',
82 'lookup',
83 'mut',
84 'outlet',
85 'partial',
86 'query-params',
87 'render',
88 'template',
89 'textarea',
90 'unbound',
91 'unless',
92 'view',
93 'with',
94 'yield'
95 ]
96 };
97
98 const LITERALS = {
99 literal: [
100 'true',
101 'false',
102 'undefined',
103 'null'
104 ]
105 };
106
107 // as defined in https://handlebarsjs.com/guide/expressions.html#literal-segments
108 // this regex matches literal segments like ' abc ' or [ abc ] as well as helpers and paths
109 // like a/b, ./abc/cde, and abc.bcd
110
111 const DOUBLE_QUOTED_ID_REGEX = /""|"[^"]+"/;
112 const SINGLE_QUOTED_ID_REGEX = /''|'[^']+'/;
113 const BRACKET_QUOTED_ID_REGEX = /\[\]|\[[^\]]+\]/;
114 const PLAIN_ID_REGEX = /[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/;
115 const PATH_DELIMITER_REGEX = /(\.|\/)/;
116 const ANY_ID = either(
117 DOUBLE_QUOTED_ID_REGEX,
118 SINGLE_QUOTED_ID_REGEX,
119 BRACKET_QUOTED_ID_REGEX,
120 PLAIN_ID_REGEX
121 );
122
123 const IDENTIFIER_REGEX = concat(
124 optional(/\.|\.\/|\//), // relative or absolute path
125 ANY_ID,
126 anyNumberOfTimes(concat(
127 PATH_DELIMITER_REGEX,
128 ANY_ID
129 ))
130 );
131
132 // identifier followed by a equal-sign (without the equal sign)
133 const HASH_PARAM_REGEX = concat(
134 '(',
135 BRACKET_QUOTED_ID_REGEX, '|',
136 PLAIN_ID_REGEX,
137 ')(?==)'
138 );
139
140 const HELPER_NAME_OR_PATH_EXPRESSION = {
141 begin: IDENTIFIER_REGEX,
142 lexemes: /[\w.\/]+/
143 };
144
145 const HELPER_PARAMETER = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
146 keywords: LITERALS
147 });
148
149 const SUB_EXPRESSION = {
150 begin: /\(/,
151 end: /\)/
152 // the "contains" is added below when all necessary sub-modes are defined
153 };
154
155 const HASH = {
156 // fka "attribute-assignment", parameters of the form 'key=value'
157 className: 'attr',
158 begin: HASH_PARAM_REGEX,
159 relevance: 0,
160 starts: {
161 begin: /=/,
162 end: /=/,
163 starts: {
164 contains: [
165 hljs.NUMBER_MODE,
166 hljs.QUOTE_STRING_MODE,
167 hljs.APOS_STRING_MODE,
168 HELPER_PARAMETER,
169 SUB_EXPRESSION
170 ]
171 }
172 }
173 };
174
175 const BLOCK_PARAMS = {
176 // parameters of the form '{{#with x as | y |}}...{{/with}}'
177 begin: /as\s+\|/,
178 keywords: {
179 keyword: 'as'
180 },
181 end: /\|/,
182 contains: [
183 {
184 // define sub-mode in order to prevent highlighting of block-parameter named "as"
185 begin: /\w+/
186 }
187 ]
188 };
189
190 const HELPER_PARAMETERS = {
191 contains: [
192 hljs.NUMBER_MODE,
193 hljs.QUOTE_STRING_MODE,
194 hljs.APOS_STRING_MODE,
195 BLOCK_PARAMS,
196 HASH,
197 HELPER_PARAMETER,
198 SUB_EXPRESSION
199 ],
200 returnEnd: true
201 // the property "end" is defined through inheritance when the mode is used. If depends
202 // on the surrounding mode, but "endsWithParent" does not work here (i.e. it includes the
203 // end-token of the surrounding mode)
204 };
205
206 const SUB_EXPRESSION_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
207 className: 'name',
208 keywords: BUILT_INS,
209 starts: hljs.inherit(HELPER_PARAMETERS, {
210 end: /\)/
211 })
212 });
213
214 SUB_EXPRESSION.contains = [SUB_EXPRESSION_CONTENTS];
215
216 const OPENING_BLOCK_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
217 keywords: BUILT_INS,
218 className: 'name',
219 starts: hljs.inherit(HELPER_PARAMETERS, {
220 end: /\}\}/
221 })
222 });
223
224 const CLOSING_BLOCK_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
225 keywords: BUILT_INS,
226 className: 'name'
227 });
228
229 const BASIC_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
230 className: 'name',
231 keywords: BUILT_INS,
232 starts: hljs.inherit(HELPER_PARAMETERS, {
233 end: /\}\}/
234 })
235 });
236
237 const ESCAPE_MUSTACHE_WITH_PRECEEDING_BACKSLASH = {
238 begin: /\\\{\{/,
239 skip: true
240 };
241 const PREVENT_ESCAPE_WITH_ANOTHER_PRECEEDING_BACKSLASH = {
242 begin: /\\\\(?=\{\{)/,
243 skip: true
244 };
245
246 return {
247 name: 'Handlebars',
248 aliases: [
249 'hbs',
250 'html.hbs',
251 'html.handlebars',
252 'htmlbars'
253 ],
254 case_insensitive: true,
255 subLanguage: 'xml',
256 contains: [
257 ESCAPE_MUSTACHE_WITH_PRECEEDING_BACKSLASH,
258 PREVENT_ESCAPE_WITH_ANOTHER_PRECEEDING_BACKSLASH,
259 hljs.COMMENT(/\{\{!--/, /--\}\}/),
260 hljs.COMMENT(/\{\{!/, /\}\}/),
261 {
262 // open raw block "{{{{raw}}}} content not evaluated {{{{/raw}}}}"
263 className: 'template-tag',
264 begin: /\{\{\{\{(?!\/)/,
265 end: /\}\}\}\}/,
266 contains: [OPENING_BLOCK_MUSTACHE_CONTENTS],
267 starts: {
268 end: /\{\{\{\{\//,
269 returnEnd: true,
270 subLanguage: 'xml'
271 }
272 },
273 {
274 // close raw block
275 className: 'template-tag',
276 begin: /\{\{\{\{\//,
277 end: /\}\}\}\}/,
278 contains: [CLOSING_BLOCK_MUSTACHE_CONTENTS]
279 },
280 {
281 // open block statement
282 className: 'template-tag',
283 begin: /\{\{#/,
284 end: /\}\}/,
285 contains: [OPENING_BLOCK_MUSTACHE_CONTENTS]
286 },
287 {
288 className: 'template-tag',
289 begin: /\{\{(?=else\}\})/,
290 end: /\}\}/,
291 keywords: 'else'
292 },
293 {
294 className: 'template-tag',
295 begin: /\{\{(?=else if)/,
296 end: /\}\}/,
297 keywords: 'else if'
298 },
299 {
300 // closing block statement
301 className: 'template-tag',
302 begin: /\{\{\//,
303 end: /\}\}/,
304 contains: [CLOSING_BLOCK_MUSTACHE_CONTENTS]
305 },
306 {
307 // template variable or helper-call that is NOT html-escaped
308 className: 'template-variable',
309 begin: /\{\{\{/,
310 end: /\}\}\}/,
311 contains: [BASIC_MUSTACHE_CONTENTS]
312 },
313 {
314 // template variable or helper-call that is html-escaped
315 className: 'template-variable',
316 begin: /\{\{/,
317 end: /\}\}/,
318 contains: [BASIC_MUSTACHE_CONTENTS]
319 }
320 ]
321 };
322}
323
324/*
325 Language: HTMLBars (legacy)
326 Requires: xml.js
327 Description: Matcher for Handlebars as well as EmberJS additions.
328 Website: https://github.com/tildeio/htmlbars
329 Category: template
330 */
331
332function htmlbars(hljs) {
333 const definition = handlebars(hljs);
334
335 definition.name = "HTMLbars";
336
337 // HACK: This lets handlebars do the auto-detection if it's been loaded (by
338 // default the build script will load in alphabetical order) and if not (perhaps
339 // an install is only using `htmlbars`, not `handlebars`) then this will still
340 // allow HTMLBars to participate in the auto-detection
341
342 // worse case someone will have HTMLbars and handlebars competing for the same
343 // content and will need to change their setup to only require handlebars, but
344 // I don't consider this a breaking change
345 if (hljs.getLanguage("handlebars")) {
346 definition.disableAutodetect = true;
347 }
348
349 return definition;
350}
351
352module.exports = htmlbars;
Note: See TracBrowser for help on using the repository browser.