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