diff options
Diffstat (limited to 'sources/samples/toolbarconfigurator/lib/codemirror/javascript.js')
-rw-r--r-- | sources/samples/toolbarconfigurator/lib/codemirror/javascript.js | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/javascript.js b/sources/samples/toolbarconfigurator/lib/codemirror/javascript.js new file mode 100644 index 00000000..ef018478 --- /dev/null +++ b/sources/samples/toolbarconfigurator/lib/codemirror/javascript.js | |||
@@ -0,0 +1,701 @@ | |||
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others | ||
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE | ||
3 | |||
4 | // TODO actually recognize syntax of TypeScript constructs | ||
5 | |||
6 | (function(mod) { | ||
7 | if (typeof exports == "object" && typeof module == "object") // CommonJS | ||
8 | mod(require("../../lib/codemirror")); | ||
9 | else if (typeof define == "function" && define.amd) // AMD | ||
10 | define(["../../lib/codemirror"], mod); | ||
11 | else // Plain browser env | ||
12 | mod(CodeMirror); | ||
13 | })(function(CodeMirror) { | ||
14 | "use strict"; | ||
15 | |||
16 | CodeMirror.defineMode("javascript", function(config, parserConfig) { | ||
17 | var indentUnit = config.indentUnit; | ||
18 | var statementIndent = parserConfig.statementIndent; | ||
19 | var jsonldMode = parserConfig.jsonld; | ||
20 | var jsonMode = parserConfig.json || jsonldMode; | ||
21 | var isTS = parserConfig.typescript; | ||
22 | var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; | ||
23 | |||
24 | // Tokenizer | ||
25 | |||
26 | var keywords = function(){ | ||
27 | function kw(type) {return {type: type, style: "keyword"};} | ||
28 | var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); | ||
29 | var operator = kw("operator"), atom = {type: "atom", style: "atom"}; | ||
30 | |||
31 | var jsKeywords = { | ||
32 | "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, | ||
33 | "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C, | ||
34 | "var": kw("var"), "const": kw("var"), "let": kw("var"), | ||
35 | "function": kw("function"), "catch": kw("catch"), | ||
36 | "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), | ||
37 | "in": operator, "typeof": operator, "instanceof": operator, | ||
38 | "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, | ||
39 | "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"), | ||
40 | "yield": C, "export": kw("export"), "import": kw("import"), "extends": C | ||
41 | }; | ||
42 | |||
43 | // Extend the 'normal' keywords with the TypeScript language extensions | ||
44 | if (isTS) { | ||
45 | var type = {type: "variable", style: "variable-3"}; | ||
46 | var tsKeywords = { | ||
47 | // object-like things | ||
48 | "interface": kw("interface"), | ||
49 | "extends": kw("extends"), | ||
50 | "constructor": kw("constructor"), | ||
51 | |||
52 | // scope modifiers | ||
53 | "public": kw("public"), | ||
54 | "private": kw("private"), | ||
55 | "protected": kw("protected"), | ||
56 | "static": kw("static"), | ||
57 | |||
58 | // types | ||
59 | "string": type, "number": type, "bool": type, "any": type | ||
60 | }; | ||
61 | |||
62 | for (var attr in tsKeywords) { | ||
63 | jsKeywords[attr] = tsKeywords[attr]; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | return jsKeywords; | ||
68 | }(); | ||
69 | |||
70 | var isOperatorChar = /[+\-*&%=<>!?|~^]/; | ||
71 | var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; | ||
72 | |||
73 | function readRegexp(stream) { | ||
74 | var escaped = false, next, inSet = false; | ||
75 | while ((next = stream.next()) != null) { | ||
76 | if (!escaped) { | ||
77 | if (next == "/" && !inSet) return; | ||
78 | if (next == "[") inSet = true; | ||
79 | else if (inSet && next == "]") inSet = false; | ||
80 | } | ||
81 | escaped = !escaped && next == "\\"; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | // Used as scratch variables to communicate multiple values without | ||
86 | // consing up tons of objects. | ||
87 | var type, content; | ||
88 | function ret(tp, style, cont) { | ||
89 | type = tp; content = cont; | ||
90 | return style; | ||
91 | } | ||
92 | function tokenBase(stream, state) { | ||
93 | var ch = stream.next(); | ||
94 | if (ch == '"' || ch == "'") { | ||
95 | state.tokenize = tokenString(ch); | ||
96 | return state.tokenize(stream, state); | ||
97 | } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { | ||
98 | return ret("number", "number"); | ||
99 | } else if (ch == "." && stream.match("..")) { | ||
100 | return ret("spread", "meta"); | ||
101 | } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { | ||
102 | return ret(ch); | ||
103 | } else if (ch == "=" && stream.eat(">")) { | ||
104 | return ret("=>", "operator"); | ||
105 | } else if (ch == "0" && stream.eat(/x/i)) { | ||
106 | stream.eatWhile(/[\da-f]/i); | ||
107 | return ret("number", "number"); | ||
108 | } else if (/\d/.test(ch)) { | ||
109 | stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); | ||
110 | return ret("number", "number"); | ||
111 | } else if (ch == "/") { | ||
112 | if (stream.eat("*")) { | ||
113 | state.tokenize = tokenComment; | ||
114 | return tokenComment(stream, state); | ||
115 | } else if (stream.eat("/")) { | ||
116 | stream.skipToEnd(); | ||
117 | return ret("comment", "comment"); | ||
118 | } else if (state.lastType == "operator" || state.lastType == "keyword c" || | ||
119 | state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { | ||
120 | readRegexp(stream); | ||
121 | stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); | ||
122 | return ret("regexp", "string-2"); | ||
123 | } else { | ||
124 | stream.eatWhile(isOperatorChar); | ||
125 | return ret("operator", "operator", stream.current()); | ||
126 | } | ||
127 | } else if (ch == "`") { | ||
128 | state.tokenize = tokenQuasi; | ||
129 | return tokenQuasi(stream, state); | ||
130 | } else if (ch == "#") { | ||
131 | stream.skipToEnd(); | ||
132 | return ret("error", "error"); | ||
133 | } else if (isOperatorChar.test(ch)) { | ||
134 | stream.eatWhile(isOperatorChar); | ||
135 | return ret("operator", "operator", stream.current()); | ||
136 | } else if (wordRE.test(ch)) { | ||
137 | stream.eatWhile(wordRE); | ||
138 | var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; | ||
139 | return (known && state.lastType != ".") ? ret(known.type, known.style, word) : | ||
140 | ret("variable", "variable", word); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | function tokenString(quote) { | ||
145 | return function(stream, state) { | ||
146 | var escaped = false, next; | ||
147 | if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ | ||
148 | state.tokenize = tokenBase; | ||
149 | return ret("jsonld-keyword", "meta"); | ||
150 | } | ||
151 | while ((next = stream.next()) != null) { | ||
152 | if (next == quote && !escaped) break; | ||
153 | escaped = !escaped && next == "\\"; | ||
154 | } | ||
155 | if (!escaped) state.tokenize = tokenBase; | ||
156 | return ret("string", "string"); | ||
157 | }; | ||
158 | } | ||
159 | |||
160 | function tokenComment(stream, state) { | ||
161 | var maybeEnd = false, ch; | ||
162 | while (ch = stream.next()) { | ||
163 | if (ch == "/" && maybeEnd) { | ||
164 | state.tokenize = tokenBase; | ||
165 | break; | ||
166 | } | ||
167 | maybeEnd = (ch == "*"); | ||
168 | } | ||
169 | return ret("comment", "comment"); | ||
170 | } | ||
171 | |||
172 | function tokenQuasi(stream, state) { | ||
173 | var escaped = false, next; | ||
174 | while ((next = stream.next()) != null) { | ||
175 | if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { | ||
176 | state.tokenize = tokenBase; | ||
177 | break; | ||
178 | } | ||
179 | escaped = !escaped && next == "\\"; | ||
180 | } | ||
181 | return ret("quasi", "string-2", stream.current()); | ||
182 | } | ||
183 | |||
184 | var brackets = "([{}])"; | ||
185 | // This is a crude lookahead trick to try and notice that we're | ||
186 | // parsing the argument patterns for a fat-arrow function before we | ||
187 | // actually hit the arrow token. It only works if the arrow is on | ||
188 | // the same line as the arguments and there's no strange noise | ||
189 | // (comments) in between. Fallback is to only notice when we hit the | ||
190 | // arrow, and not declare the arguments as locals for the arrow | ||
191 | // body. | ||
192 | function findFatArrow(stream, state) { | ||
193 | if (state.fatArrowAt) state.fatArrowAt = null; | ||
194 | var arrow = stream.string.indexOf("=>", stream.start); | ||
195 | if (arrow < 0) return; | ||
196 | |||
197 | var depth = 0, sawSomething = false; | ||
198 | for (var pos = arrow - 1; pos >= 0; --pos) { | ||
199 | var ch = stream.string.charAt(pos); | ||
200 | var bracket = brackets.indexOf(ch); | ||
201 | if (bracket >= 0 && bracket < 3) { | ||
202 | if (!depth) { ++pos; break; } | ||
203 | if (--depth == 0) break; | ||
204 | } else if (bracket >= 3 && bracket < 6) { | ||
205 | ++depth; | ||
206 | } else if (wordRE.test(ch)) { | ||
207 | sawSomething = true; | ||
208 | } else if (/["'\/]/.test(ch)) { | ||
209 | return; | ||
210 | } else if (sawSomething && !depth) { | ||
211 | ++pos; | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | if (sawSomething && !depth) state.fatArrowAt = pos; | ||
216 | } | ||
217 | |||
218 | // Parser | ||
219 | |||
220 | var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; | ||
221 | |||
222 | function JSLexical(indented, column, type, align, prev, info) { | ||
223 | this.indented = indented; | ||
224 | this.column = column; | ||
225 | this.type = type; | ||
226 | this.prev = prev; | ||
227 | this.info = info; | ||
228 | if (align != null) this.align = align; | ||
229 | } | ||
230 | |||
231 | function inScope(state, varname) { | ||
232 | for (var v = state.localVars; v; v = v.next) | ||
233 | if (v.name == varname) return true; | ||
234 | for (var cx = state.context; cx; cx = cx.prev) { | ||
235 | for (var v = cx.vars; v; v = v.next) | ||
236 | if (v.name == varname) return true; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | function parseJS(state, style, type, content, stream) { | ||
241 | var cc = state.cc; | ||
242 | // Communicate our context to the combinators. | ||
243 | // (Less wasteful than consing up a hundred closures on every call.) | ||
244 | cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; | ||
245 | |||
246 | if (!state.lexical.hasOwnProperty("align")) | ||
247 | state.lexical.align = true; | ||
248 | |||
249 | while(true) { | ||
250 | var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; | ||
251 | if (combinator(type, content)) { | ||
252 | while(cc.length && cc[cc.length - 1].lex) | ||
253 | cc.pop()(); | ||
254 | if (cx.marked) return cx.marked; | ||
255 | if (type == "variable" && inScope(state, content)) return "variable-2"; | ||
256 | return style; | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | // Combinator utils | ||
262 | |||
263 | var cx = {state: null, column: null, marked: null, cc: null}; | ||
264 | function pass() { | ||
265 | for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); | ||
266 | } | ||
267 | function cont() { | ||
268 | pass.apply(null, arguments); | ||
269 | return true; | ||
270 | } | ||
271 | function register(varname) { | ||
272 | function inList(list) { | ||
273 | for (var v = list; v; v = v.next) | ||
274 | if (v.name == varname) return true; | ||
275 | return false; | ||
276 | } | ||
277 | var state = cx.state; | ||
278 | if (state.context) { | ||
279 | cx.marked = "def"; | ||
280 | if (inList(state.localVars)) return; | ||
281 | state.localVars = {name: varname, next: state.localVars}; | ||
282 | } else { | ||
283 | if (inList(state.globalVars)) return; | ||
284 | if (parserConfig.globalVars) | ||
285 | state.globalVars = {name: varname, next: state.globalVars}; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | // Combinators | ||
290 | |||
291 | var defaultVars = {name: "this", next: {name: "arguments"}}; | ||
292 | function pushcontext() { | ||
293 | cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; | ||
294 | cx.state.localVars = defaultVars; | ||
295 | } | ||
296 | function popcontext() { | ||
297 | cx.state.localVars = cx.state.context.vars; | ||
298 | cx.state.context = cx.state.context.prev; | ||
299 | } | ||
300 | function pushlex(type, info) { | ||
301 | var result = function() { | ||
302 | var state = cx.state, indent = state.indented; | ||
303 | if (state.lexical.type == "stat") indent = state.lexical.indented; | ||
304 | else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) | ||
305 | indent = outer.indented; | ||
306 | state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); | ||
307 | }; | ||
308 | result.lex = true; | ||
309 | return result; | ||
310 | } | ||
311 | function poplex() { | ||
312 | var state = cx.state; | ||
313 | if (state.lexical.prev) { | ||
314 | if (state.lexical.type == ")") | ||
315 | state.indented = state.lexical.indented; | ||
316 | state.lexical = state.lexical.prev; | ||
317 | } | ||
318 | } | ||
319 | poplex.lex = true; | ||
320 | |||
321 | function expect(wanted) { | ||
322 | function exp(type) { | ||
323 | if (type == wanted) return cont(); | ||
324 | else if (wanted == ";") return pass(); | ||
325 | else return cont(exp); | ||
326 | }; | ||
327 | return exp; | ||
328 | } | ||
329 | |||
330 | function statement(type, value) { | ||
331 | if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); | ||
332 | if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); | ||
333 | if (type == "keyword b") return cont(pushlex("form"), statement, poplex); | ||
334 | if (type == "{") return cont(pushlex("}"), block, poplex); | ||
335 | if (type == ";") return cont(); | ||
336 | if (type == "if") { | ||
337 | if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) | ||
338 | cx.state.cc.pop()(); | ||
339 | return cont(pushlex("form"), expression, statement, poplex, maybeelse); | ||
340 | } | ||
341 | if (type == "function") return cont(functiondef); | ||
342 | if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); | ||
343 | if (type == "variable") return cont(pushlex("stat"), maybelabel); | ||
344 | if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), | ||
345 | block, poplex, poplex); | ||
346 | if (type == "case") return cont(expression, expect(":")); | ||
347 | if (type == "default") return cont(expect(":")); | ||
348 | if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), | ||
349 | statement, poplex, popcontext); | ||
350 | if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex); | ||
351 | if (type == "class") return cont(pushlex("form"), className, poplex); | ||
352 | if (type == "export") return cont(pushlex("form"), afterExport, poplex); | ||
353 | if (type == "import") return cont(pushlex("form"), afterImport, poplex); | ||
354 | return pass(pushlex("stat"), expression, expect(";"), poplex); | ||
355 | } | ||
356 | function expression(type) { | ||
357 | return expressionInner(type, false); | ||
358 | } | ||
359 | function expressionNoComma(type) { | ||
360 | return expressionInner(type, true); | ||
361 | } | ||
362 | function expressionInner(type, noComma) { | ||
363 | if (cx.state.fatArrowAt == cx.stream.start) { | ||
364 | var body = noComma ? arrowBodyNoComma : arrowBody; | ||
365 | if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); | ||
366 | else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); | ||
367 | } | ||
368 | |||
369 | var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; | ||
370 | if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); | ||
371 | if (type == "function") return cont(functiondef, maybeop); | ||
372 | if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); | ||
373 | if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); | ||
374 | if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); | ||
375 | if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); | ||
376 | if (type == "{") return contCommasep(objprop, "}", null, maybeop); | ||
377 | if (type == "quasi") { return pass(quasi, maybeop); } | ||
378 | return cont(); | ||
379 | } | ||
380 | function maybeexpression(type) { | ||
381 | if (type.match(/[;\}\)\],]/)) return pass(); | ||
382 | return pass(expression); | ||
383 | } | ||
384 | function maybeexpressionNoComma(type) { | ||
385 | if (type.match(/[;\}\)\],]/)) return pass(); | ||
386 | return pass(expressionNoComma); | ||
387 | } | ||
388 | |||
389 | function maybeoperatorComma(type, value) { | ||
390 | if (type == ",") return cont(expression); | ||
391 | return maybeoperatorNoComma(type, value, false); | ||
392 | } | ||
393 | function maybeoperatorNoComma(type, value, noComma) { | ||
394 | var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; | ||
395 | var expr = noComma == false ? expression : expressionNoComma; | ||
396 | if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); | ||
397 | if (type == "operator") { | ||
398 | if (/\+\+|--/.test(value)) return cont(me); | ||
399 | if (value == "?") return cont(expression, expect(":"), expr); | ||
400 | return cont(expr); | ||
401 | } | ||
402 | if (type == "quasi") { return pass(quasi, me); } | ||
403 | if (type == ";") return; | ||
404 | if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); | ||
405 | if (type == ".") return cont(property, me); | ||
406 | if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); | ||
407 | } | ||
408 | function quasi(type, value) { | ||
409 | if (type != "quasi") return pass(); | ||
410 | if (value.slice(value.length - 2) != "${") return cont(quasi); | ||
411 | return cont(expression, continueQuasi); | ||
412 | } | ||
413 | function continueQuasi(type) { | ||
414 | if (type == "}") { | ||
415 | cx.marked = "string-2"; | ||
416 | cx.state.tokenize = tokenQuasi; | ||
417 | return cont(quasi); | ||
418 | } | ||
419 | } | ||
420 | function arrowBody(type) { | ||
421 | findFatArrow(cx.stream, cx.state); | ||
422 | return pass(type == "{" ? statement : expression); | ||
423 | } | ||
424 | function arrowBodyNoComma(type) { | ||
425 | findFatArrow(cx.stream, cx.state); | ||
426 | return pass(type == "{" ? statement : expressionNoComma); | ||
427 | } | ||
428 | function maybelabel(type) { | ||
429 | if (type == ":") return cont(poplex, statement); | ||
430 | return pass(maybeoperatorComma, expect(";"), poplex); | ||
431 | } | ||
432 | function property(type) { | ||
433 | if (type == "variable") {cx.marked = "property"; return cont();} | ||
434 | } | ||
435 | function objprop(type, value) { | ||
436 | if (type == "variable" || cx.style == "keyword") { | ||
437 | cx.marked = "property"; | ||
438 | if (value == "get" || value == "set") return cont(getterSetter); | ||
439 | return cont(afterprop); | ||
440 | } else if (type == "number" || type == "string") { | ||
441 | cx.marked = jsonldMode ? "property" : (cx.style + " property"); | ||
442 | return cont(afterprop); | ||
443 | } else if (type == "jsonld-keyword") { | ||
444 | return cont(afterprop); | ||
445 | } else if (type == "[") { | ||
446 | return cont(expression, expect("]"), afterprop); | ||
447 | } | ||
448 | } | ||
449 | function getterSetter(type) { | ||
450 | if (type != "variable") return pass(afterprop); | ||
451 | cx.marked = "property"; | ||
452 | return cont(functiondef); | ||
453 | } | ||
454 | function afterprop(type) { | ||
455 | if (type == ":") return cont(expressionNoComma); | ||
456 | if (type == "(") return pass(functiondef); | ||
457 | } | ||
458 | function commasep(what, end) { | ||
459 | function proceed(type) { | ||
460 | if (type == ",") { | ||
461 | var lex = cx.state.lexical; | ||
462 | if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; | ||
463 | return cont(what, proceed); | ||
464 | } | ||
465 | if (type == end) return cont(); | ||
466 | return cont(expect(end)); | ||
467 | } | ||
468 | return function(type) { | ||
469 | if (type == end) return cont(); | ||
470 | return pass(what, proceed); | ||
471 | }; | ||
472 | } | ||
473 | function contCommasep(what, end, info) { | ||
474 | for (var i = 3; i < arguments.length; i++) | ||
475 | cx.cc.push(arguments[i]); | ||
476 | return cont(pushlex(end, info), commasep(what, end), poplex); | ||
477 | } | ||
478 | function block(type) { | ||
479 | if (type == "}") return cont(); | ||
480 | return pass(statement, block); | ||
481 | } | ||
482 | function maybetype(type) { | ||
483 | if (isTS && type == ":") return cont(typedef); | ||
484 | } | ||
485 | function typedef(type) { | ||
486 | if (type == "variable"){cx.marked = "variable-3"; return cont();} | ||
487 | } | ||
488 | function vardef() { | ||
489 | return pass(pattern, maybetype, maybeAssign, vardefCont); | ||
490 | } | ||
491 | function pattern(type, value) { | ||
492 | if (type == "variable") { register(value); return cont(); } | ||
493 | if (type == "[") return contCommasep(pattern, "]"); | ||
494 | if (type == "{") return contCommasep(proppattern, "}"); | ||
495 | } | ||
496 | function proppattern(type, value) { | ||
497 | if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { | ||
498 | register(value); | ||
499 | return cont(maybeAssign); | ||
500 | } | ||
501 | if (type == "variable") cx.marked = "property"; | ||
502 | return cont(expect(":"), pattern, maybeAssign); | ||
503 | } | ||
504 | function maybeAssign(_type, value) { | ||
505 | if (value == "=") return cont(expressionNoComma); | ||
506 | } | ||
507 | function vardefCont(type) { | ||
508 | if (type == ",") return cont(vardef); | ||
509 | } | ||
510 | function maybeelse(type, value) { | ||
511 | if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); | ||
512 | } | ||
513 | function forspec(type) { | ||
514 | if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); | ||
515 | } | ||
516 | function forspec1(type) { | ||
517 | if (type == "var") return cont(vardef, expect(";"), forspec2); | ||
518 | if (type == ";") return cont(forspec2); | ||
519 | if (type == "variable") return cont(formaybeinof); | ||
520 | return pass(expression, expect(";"), forspec2); | ||
521 | } | ||
522 | function formaybeinof(_type, value) { | ||
523 | if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } | ||
524 | return cont(maybeoperatorComma, forspec2); | ||
525 | } | ||
526 | function forspec2(type, value) { | ||
527 | if (type == ";") return cont(forspec3); | ||
528 | if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } | ||
529 | return pass(expression, expect(";"), forspec3); | ||
530 | } | ||
531 | function forspec3(type) { | ||
532 | if (type != ")") cont(expression); | ||
533 | } | ||
534 | function functiondef(type, value) { | ||
535 | if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} | ||
536 | if (type == "variable") {register(value); return cont(functiondef);} | ||
537 | if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext); | ||
538 | } | ||
539 | function funarg(type) { | ||
540 | if (type == "spread") return cont(funarg); | ||
541 | return pass(pattern, maybetype); | ||
542 | } | ||
543 | function className(type, value) { | ||
544 | if (type == "variable") {register(value); return cont(classNameAfter);} | ||
545 | } | ||
546 | function classNameAfter(type, value) { | ||
547 | if (value == "extends") return cont(expression, classNameAfter); | ||
548 | if (type == "{") return cont(pushlex("}"), classBody, poplex); | ||
549 | } | ||
550 | function classBody(type, value) { | ||
551 | if (type == "variable" || cx.style == "keyword") { | ||
552 | if (value == "static") { | ||
553 | cx.marked = "keyword"; | ||
554 | return cont(classBody); | ||
555 | } | ||
556 | cx.marked = "property"; | ||
557 | if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); | ||
558 | return cont(functiondef, classBody); | ||
559 | } | ||
560 | if (value == "*") { | ||
561 | cx.marked = "keyword"; | ||
562 | return cont(classBody); | ||
563 | } | ||
564 | if (type == ";") return cont(classBody); | ||
565 | if (type == "}") return cont(); | ||
566 | } | ||
567 | function classGetterSetter(type) { | ||
568 | if (type != "variable") return pass(); | ||
569 | cx.marked = "property"; | ||
570 | return cont(); | ||
571 | } | ||
572 | function afterModule(type, value) { | ||
573 | if (type == "string") return cont(statement); | ||
574 | if (type == "variable") { register(value); return cont(maybeFrom); } | ||
575 | } | ||
576 | function afterExport(_type, value) { | ||
577 | if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } | ||
578 | if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } | ||
579 | return pass(statement); | ||
580 | } | ||
581 | function afterImport(type) { | ||
582 | if (type == "string") return cont(); | ||
583 | return pass(importSpec, maybeFrom); | ||
584 | } | ||
585 | function importSpec(type, value) { | ||
586 | if (type == "{") return contCommasep(importSpec, "}"); | ||
587 | if (type == "variable") register(value); | ||
588 | if (value == "*") cx.marked = "keyword"; | ||
589 | return cont(maybeAs); | ||
590 | } | ||
591 | function maybeAs(_type, value) { | ||
592 | if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } | ||
593 | } | ||
594 | function maybeFrom(_type, value) { | ||
595 | if (value == "from") { cx.marked = "keyword"; return cont(expression); } | ||
596 | } | ||
597 | function arrayLiteral(type) { | ||
598 | if (type == "]") return cont(); | ||
599 | return pass(expressionNoComma, maybeArrayComprehension); | ||
600 | } | ||
601 | function maybeArrayComprehension(type) { | ||
602 | if (type == "for") return pass(comprehension, expect("]")); | ||
603 | if (type == ",") return cont(commasep(maybeexpressionNoComma, "]")); | ||
604 | return pass(commasep(expressionNoComma, "]")); | ||
605 | } | ||
606 | function comprehension(type) { | ||
607 | if (type == "for") return cont(forspec, comprehension); | ||
608 | if (type == "if") return cont(expression, comprehension); | ||
609 | } | ||
610 | |||
611 | function isContinuedStatement(state, textAfter) { | ||
612 | return state.lastType == "operator" || state.lastType == "," || | ||
613 | isOperatorChar.test(textAfter.charAt(0)) || | ||
614 | /[,.]/.test(textAfter.charAt(0)); | ||
615 | } | ||
616 | |||
617 | // Interface | ||
618 | |||
619 | return { | ||
620 | startState: function(basecolumn) { | ||
621 | var state = { | ||
622 | tokenize: tokenBase, | ||
623 | lastType: "sof", | ||
624 | cc: [], | ||
625 | lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), | ||
626 | localVars: parserConfig.localVars, | ||
627 | context: parserConfig.localVars && {vars: parserConfig.localVars}, | ||
628 | indented: 0 | ||
629 | }; | ||
630 | if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") | ||
631 | state.globalVars = parserConfig.globalVars; | ||
632 | return state; | ||
633 | }, | ||
634 | |||
635 | token: function(stream, state) { | ||
636 | if (stream.sol()) { | ||
637 | if (!state.lexical.hasOwnProperty("align")) | ||
638 | state.lexical.align = false; | ||
639 | state.indented = stream.indentation(); | ||
640 | findFatArrow(stream, state); | ||
641 | } | ||
642 | if (state.tokenize != tokenComment && stream.eatSpace()) return null; | ||
643 | var style = state.tokenize(stream, state); | ||
644 | if (type == "comment") return style; | ||
645 | state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; | ||
646 | return parseJS(state, style, type, content, stream); | ||
647 | }, | ||
648 | |||
649 | indent: function(state, textAfter) { | ||
650 | if (state.tokenize == tokenComment) return CodeMirror.Pass; | ||
651 | if (state.tokenize != tokenBase) return 0; | ||
652 | var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; | ||
653 | // Kludge to prevent 'maybelse' from blocking lexical scope pops | ||
654 | if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { | ||
655 | var c = state.cc[i]; | ||
656 | if (c == poplex) lexical = lexical.prev; | ||
657 | else if (c != maybeelse) break; | ||
658 | } | ||
659 | if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; | ||
660 | if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") | ||
661 | lexical = lexical.prev; | ||
662 | var type = lexical.type, closing = firstChar == type; | ||
663 | |||
664 | if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); | ||
665 | else if (type == "form" && firstChar == "{") return lexical.indented; | ||
666 | else if (type == "form") return lexical.indented + indentUnit; | ||
667 | else if (type == "stat") | ||
668 | return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); | ||
669 | else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) | ||
670 | return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); | ||
671 | else if (lexical.align) return lexical.column + (closing ? 0 : 1); | ||
672 | else return lexical.indented + (closing ? 0 : indentUnit); | ||
673 | }, | ||
674 | |||
675 | electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, | ||
676 | blockCommentStart: jsonMode ? null : "/*", | ||
677 | blockCommentEnd: jsonMode ? null : "*/", | ||
678 | lineComment: jsonMode ? null : "//", | ||
679 | fold: "brace", | ||
680 | closeBrackets: "()[]{}''\"\"``", | ||
681 | |||
682 | helperType: jsonMode ? "json" : "javascript", | ||
683 | jsonldMode: jsonldMode, | ||
684 | jsonMode: jsonMode | ||
685 | }; | ||
686 | }); | ||
687 | |||
688 | CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); | ||
689 | |||
690 | CodeMirror.defineMIME("text/javascript", "javascript"); | ||
691 | CodeMirror.defineMIME("text/ecmascript", "javascript"); | ||
692 | CodeMirror.defineMIME("application/javascript", "javascript"); | ||
693 | CodeMirror.defineMIME("application/x-javascript", "javascript"); | ||
694 | CodeMirror.defineMIME("application/ecmascript", "javascript"); | ||
695 | CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); | ||
696 | CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); | ||
697 | CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); | ||
698 | CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); | ||
699 | CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); | ||
700 | |||
701 | }); | ||