]> luflow.net public git repositories - flow-web.git/blob - static/highlight/languages/handlebars.js
Initial commit.
[flow-web.git] / static / highlight / languages / handlebars.js
1 /*! `handlebars` grammar compiled for Highlight.js 11.11.1 */
2 (function(){
3 var hljsGrammar = (function () {
4 'use strict';
5
6 /*
7 Language: Handlebars
8 Requires: xml.js
9 Author: Robin Ward <robin.ward@gmail.com>
10 Description: Matcher for Handlebars as well as EmberJS additions.
11 Website: https://handlebarsjs.com
12 Category: template
13 */
14
15 function handlebars(hljs) {
16 const regex = hljs.regex;
17 const BUILT_INS = {
18 $pattern: /[\w.\/]+/,
19 built_in: [
20 'action',
21 'bindattr',
22 'collection',
23 'component',
24 'concat',
25 'debugger',
26 'each',
27 'each-in',
28 'get',
29 'hash',
30 'if',
31 'in',
32 'input',
33 'link-to',
34 'loc',
35 'log',
36 'lookup',
37 'mut',
38 'outlet',
39 'partial',
40 'query-params',
41 'render',
42 'template',
43 'textarea',
44 'unbound',
45 'unless',
46 'view',
47 'with',
48 'yield'
49 ]
50 };
51
52 const LITERALS = {
53 $pattern: /[\w.\/]+/,
54 literal: [
55 'true',
56 'false',
57 'undefined',
58 'null'
59 ]
60 };
61
62 // as defined in https://handlebarsjs.com/guide/expressions.html#literal-segments
63 // this regex matches literal segments like ' abc ' or [ abc ] as well as helpers and paths
64 // like a/b, ./abc/cde, and abc.bcd
65
66 const DOUBLE_QUOTED_ID_REGEX = /""|"[^"]+"/;
67 const SINGLE_QUOTED_ID_REGEX = /''|'[^']+'/;
68 const BRACKET_QUOTED_ID_REGEX = /\[\]|\[[^\]]+\]/;
69 const PLAIN_ID_REGEX = /[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/;
70 const PATH_DELIMITER_REGEX = /(\.|\/)/;
71 const ANY_ID = regex.either(
72 DOUBLE_QUOTED_ID_REGEX,
73 SINGLE_QUOTED_ID_REGEX,
74 BRACKET_QUOTED_ID_REGEX,
75 PLAIN_ID_REGEX
76 );
77
78 const IDENTIFIER_REGEX = regex.concat(
79 regex.optional(/\.|\.\/|\//), // relative or absolute path
80 ANY_ID,
81 regex.anyNumberOfTimes(regex.concat(
82 PATH_DELIMITER_REGEX,
83 ANY_ID
84 ))
85 );
86
87 // identifier followed by a equal-sign (without the equal sign)
88 const HASH_PARAM_REGEX = regex.concat(
89 '(',
90 BRACKET_QUOTED_ID_REGEX, '|',
91 PLAIN_ID_REGEX,
92 ')(?==)'
93 );
94
95 const HELPER_NAME_OR_PATH_EXPRESSION = { begin: IDENTIFIER_REGEX };
96
97 const HELPER_PARAMETER = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, { keywords: LITERALS });
98
99 const SUB_EXPRESSION = {
100 begin: /\(/,
101 end: /\)/
102 // the "contains" is added below when all necessary sub-modes are defined
103 };
104
105 const HASH = {
106 // fka "attribute-assignment", parameters of the form 'key=value'
107 className: 'attr',
108 begin: HASH_PARAM_REGEX,
109 relevance: 0,
110 starts: {
111 begin: /=/,
112 end: /=/,
113 starts: { contains: [
114 hljs.NUMBER_MODE,
115 hljs.QUOTE_STRING_MODE,
116 hljs.APOS_STRING_MODE,
117 HELPER_PARAMETER,
118 SUB_EXPRESSION
119 ] }
120 }
121 };
122
123 const BLOCK_PARAMS = {
124 // parameters of the form '{{#with x as | y |}}...{{/with}}'
125 begin: /as\s+\|/,
126 keywords: { keyword: 'as' },
127 end: /\|/,
128 contains: [
129 {
130 // define sub-mode in order to prevent highlighting of block-parameter named "as"
131 begin: /\w+/ }
132 ]
133 };
134
135 const HELPER_PARAMETERS = {
136 contains: [
137 hljs.NUMBER_MODE,
138 hljs.QUOTE_STRING_MODE,
139 hljs.APOS_STRING_MODE,
140 BLOCK_PARAMS,
141 HASH,
142 HELPER_PARAMETER,
143 SUB_EXPRESSION
144 ],
145 returnEnd: true
146 // the property "end" is defined through inheritance when the mode is used. If depends
147 // on the surrounding mode, but "endsWithParent" does not work here (i.e. it includes the
148 // end-token of the surrounding mode)
149 };
150
151 const SUB_EXPRESSION_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
152 className: 'name',
153 keywords: BUILT_INS,
154 starts: hljs.inherit(HELPER_PARAMETERS, { end: /\)/ })
155 });
156
157 SUB_EXPRESSION.contains = [ SUB_EXPRESSION_CONTENTS ];
158
159 const OPENING_BLOCK_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
160 keywords: BUILT_INS,
161 className: 'name',
162 starts: hljs.inherit(HELPER_PARAMETERS, { end: /\}\}/ })
163 });
164
165 const CLOSING_BLOCK_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
166 keywords: BUILT_INS,
167 className: 'name'
168 });
169
170 const BASIC_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, {
171 className: 'name',
172 keywords: BUILT_INS,
173 starts: hljs.inherit(HELPER_PARAMETERS, { end: /\}\}/ })
174 });
175
176 const ESCAPE_MUSTACHE_WITH_PRECEEDING_BACKSLASH = {
177 begin: /\\\{\{/,
178 skip: true
179 };
180 const PREVENT_ESCAPE_WITH_ANOTHER_PRECEEDING_BACKSLASH = {
181 begin: /\\\\(?=\{\{)/,
182 skip: true
183 };
184
185 return {
186 name: 'Handlebars',
187 aliases: [
188 'hbs',
189 'html.hbs',
190 'html.handlebars',
191 'htmlbars'
192 ],
193 case_insensitive: true,
194 subLanguage: 'xml',
195 contains: [
196 ESCAPE_MUSTACHE_WITH_PRECEEDING_BACKSLASH,
197 PREVENT_ESCAPE_WITH_ANOTHER_PRECEEDING_BACKSLASH,
198 hljs.COMMENT(/\{\{!--/, /--\}\}/),
199 hljs.COMMENT(/\{\{!/, /\}\}/),
200 {
201 // open raw block "{{{{raw}}}} content not evaluated {{{{/raw}}}}"
202 className: 'template-tag',
203 begin: /\{\{\{\{(?!\/)/,
204 end: /\}\}\}\}/,
205 contains: [ OPENING_BLOCK_MUSTACHE_CONTENTS ],
206 starts: {
207 end: /\{\{\{\{\//,
208 returnEnd: true,
209 subLanguage: 'xml'
210 }
211 },
212 {
213 // close raw block
214 className: 'template-tag',
215 begin: /\{\{\{\{\//,
216 end: /\}\}\}\}/,
217 contains: [ CLOSING_BLOCK_MUSTACHE_CONTENTS ]
218 },
219 {
220 // open block statement
221 className: 'template-tag',
222 begin: /\{\{#/,
223 end: /\}\}/,
224 contains: [ OPENING_BLOCK_MUSTACHE_CONTENTS ]
225 },
226 {
227 className: 'template-tag',
228 begin: /\{\{(?=else\}\})/,
229 end: /\}\}/,
230 keywords: 'else'
231 },
232 {
233 className: 'template-tag',
234 begin: /\{\{(?=else if)/,
235 end: /\}\}/,
236 keywords: 'else if'
237 },
238 {
239 // closing block statement
240 className: 'template-tag',
241 begin: /\{\{\//,
242 end: /\}\}/,
243 contains: [ CLOSING_BLOCK_MUSTACHE_CONTENTS ]
244 },
245 {
246 // template variable or helper-call that is NOT html-escaped
247 className: 'template-variable',
248 begin: /\{\{\{/,
249 end: /\}\}\}/,
250 contains: [ BASIC_MUSTACHE_CONTENTS ]
251 },
252 {
253 // template variable or helper-call that is html-escaped
254 className: 'template-variable',
255 begin: /\{\{/,
256 end: /\}\}/,
257 contains: [ BASIC_MUSTACHE_CONTENTS ]
258 }
259 ]
260 };
261 }
262
263 return handlebars;
264
265 })();
266
267 hljs.registerLanguage('handlebars', hljsGrammar);
268 })();