bdcontract-web-ide/js/codemirror/mode/javascript/javascript.js

1304 lines
40 KiB
JavaScript
Executable File

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define([ "../../lib/codemirror" ], mod);
else
// Plain browser env
mod(CodeMirror);
})
(function(CodeMirror) {
"use strict";
function expressionAllowed(stream, state, backUp) {
return /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/
.test(state.lastType)
|| (state.lastType == "quasi" && /\{\s*$/
.test(stream.string.slice(0, stream.pos
- (backUp || 0))))
}
CodeMirror
.defineMode(
"javascript",
function(config, parserConfig) {
var indentUnit = config.indentUnit;
var statementIndent = parserConfig.statementIndent;
var jsonldMode = parserConfig.jsonld;
var jsonMode = parserConfig.json || jsonldMode;
var isTS = parserConfig.typescript;
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
// Tokenizer
var keywords = function() {
function kw(type) {
return {
type : type,
style : "keyword"
};
}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {
type : "atom",
style : "atom"
};
var jsKeywords = {
"if" : kw("if"),
"while" : A,
"with" : A,
"else" : B,
"do" : B,
"try" : B,
"finally" : B,
"return" : C,
"break" : C,
"continue" : C,
"new" : kw("new"),
"delete" : C,
"throw" : C,
"debugger" : C,
"var" : kw("var"),
"const" : kw("var"),
"let" : kw("var"),
"function" : kw("function"),
"catch" : kw("catch"),
"for" : kw("for"),
"switch" : kw("switch"),
"case" : kw("case"),
"default" : kw("default"),
"in" : operator,
"typeof" : operator,
"instanceof" : operator,
"true" : atom,
"false" : atom,
"null" : atom,
"undefined" : atom,
"NaN" : atom,
"Infinity" : atom,
"this" : kw("this"),
"class" : kw("class"),
"contract":kw("class"),
"super" : kw("atom"),
"yield" : C,
"export" : kw("export"),
"import" : kw("import"),
"extends" : C,
"await" : C
};
// Extend the 'normal' keywords with the
// TypeScript language extensions
if (isTS) {
var type = {
type : "variable",
style : "type"
};
var tsKeywords = {
// object-like things
"interface" : kw("class"),
"implements" : C,
"namespace" : C,
"module" : kw("module"),
"enum" : kw("module"),
"contract": kw("class"),
// scope modifiers
"public" : kw("modifier"),
"private" : kw("modifier"),
"protected" : kw("modifier"),
"abstract" : kw("modifier"),
// types
"string" : type,
"number" : type,
"boolean" : type,
"any" : type
};
for ( var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}();
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
function readRegexp(stream) {
var escaped = false, next, inSet = false;
while ((next = stream.next()) != null) {
if (!escaped) {
if (next == "/" && !inSet)
return;
if (next == "[")
inSet = true;
else if (inSet && next == "]")
inSet = false;
}
escaped = !escaped && next == "\\";
}
}
// Used as scratch variables to communicate
// multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp;
content = cont;
return style;
}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "."
&& stream
.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
return ret("number", "number");
} else if (ch == "." && stream.match("..")) {
return ret("spread", "meta");
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
return ret(ch);
} else if (ch == "=" && stream.eat(">")) {
return ret("=>", "operator");
} else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
} else if (ch == "0" && stream.eat(/o/i)) {
stream.eatWhile(/[0-7]/i);
return ret("number", "number");
} else if (ch == "0" && stream.eat(/b/i)) {
stream.eatWhile(/[01]/i);
return ret("number", "number");
} else if (/\d/.test(ch)) {
stream
.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
} else if (ch == "/") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
} else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
} else if (expressionAllowed(stream,
state, 1)) {
readRegexp(stream);
stream
.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
return ret("regexp", "string-2");
} else {
stream.eatWhile(isOperatorChar);
return ret("operator", "operator",
stream.current());
}
} else if (ch == "`") {
state.tokenize = tokenQuasi;
return tokenQuasi(stream, state);
} else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
} else if (isOperatorChar.test(ch)) {
if (ch != ">" || !state.lexical
|| state.lexical.type != ">")
stream.eatWhile(isOperatorChar);
return ret("operator", "operator",
stream.current());
} else if (wordRE.test(ch)) {
stream.eatWhile(wordRE);
var word = stream.current()
if (state.lastType != ".") {
if (keywords
.propertyIsEnumerable(word)) {
var kw = keywords[word]
return ret(kw.type, kw.style,
word)
}
if (word == "async"
&& stream
.match(
/^\s*[\(\w]/,
false))
return ret("async", "keyword",
word)
}
return ret("variable", "variable", word)
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next;
if (jsonldMode
&& stream.peek() == "@"
&& stream
.match(isJsonldKeyword)) {
state.tokenize = tokenBase;
return ret("jsonld-keyword", "meta");
}
while ((next = stream.next()) != null) {
if (next == quote && !escaped)
break;
escaped = !escaped && next == "\\";
}
if (!escaped)
state.tokenize = tokenBase;
return ret("string", "string");
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "comment");
}
function tokenQuasi(stream, state) {
var escaped = false, next;
while ((next = stream.next()) != null) {
if (!escaped
&& (next == "`" || next == "$"
&& stream.eat("{"))) {
state.tokenize = tokenBase;
break;
}
escaped = !escaped && next == "\\";
}
return ret("quasi", "string-2", stream
.current());
}
var brackets = "([{}])";
// This is a crude lookahead trick to try and
// notice that we're
// parsing the argument patterns for a fat-arrow
// function before we
// actually hit the arrow token. It only works
// if the arrow is on
// the same line as the arguments and there's no
// strange noise
// (comments) in between. Fallback is to only
// notice when we hit the
// arrow, and not declare the arguments as
// locals for the arrow
// body.
function findFatArrow(stream, state) {
if (state.fatArrowAt)
state.fatArrowAt = null;
var arrow = stream.string.indexOf("=>",
stream.start);
if (arrow < 0)
return;
if (isTS) { // Try to skip TypeScript return
// type declarations after the
// arguments
var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/
.exec(stream.string.slice(
stream.start, arrow))
if (m)
arrow = m.index
}
var depth = 0, sawSomething = false;
for (var pos = arrow - 1; pos >= 0; --pos) {
var ch = stream.string.charAt(pos);
var bracket = brackets.indexOf(ch);
if (bracket >= 0 && bracket < 3) {
if (!depth) {
++pos;
break;
}
if (--depth == 0) {
if (ch == "(")
sawSomething = true;
break;
}
} else if (bracket >= 3 && bracket < 6) {
++depth;
} else if (wordRE.test(ch)) {
sawSomething = true;
} else if (/["'\/]/.test(ch)) {
return;
} else if (sawSomething && !depth) {
++pos;
break;
}
}
if (sawSomething && !depth)
state.fatArrowAt = pos;
}
// Parser
var atomicTypes = {
"atom" : true,
"number" : true,
"variable" : true,
"string" : true,
"regexp" : true,
"this" : true,
"jsonld-keyword" : true
};
function JSLexical(indented, column, type,
align, prev, info) {
this.indented = indented;
this.column = column;
this.type = type;
this.prev = prev;
this.info = info;
if (align != null)
this.align = align;
}
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname)
return true;
for (var cx = state.context; cx; cx = cx.prev) {
for (var v = cx.vars; v; v = v.next)
if (v.name == varname)
return true;
}
}
function parseJS(state, style, type, content,
stream) {
var cc = state.cc;
// Communicate our context to the
// combinators.
// (Less wasteful than consing up a hundred
// closures on every call.)
cx.state = state;
cx.stream = stream;
cx.marked = null, cx.cc = cc;
cx.style = style;
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
while (true) {
var combinator = cc.length ? cc.pop()
: jsonMode ? expression
: statement;
if (combinator(type, content)) {
while (cc.length
&& cc[cc.length - 1].lex)
cc.pop()();
if (cx.marked)
return cx.marked;
if (type == "variable"
&& inScope(state, content))
return "variable-2";
return style;
}
}
}
// Combinator utils
var cx = {
state : null,
column : null,
marked : null,
cc : null
};
function pass() {
for (var i = arguments.length - 1; i >= 0; i--)
cx.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function register(varname) {
function inList(list) {
for (var v = list; v; v = v.next)
if (v.name == varname)
return true;
return false;
}
var state = cx.state;
cx.marked = "def";
if (state.context) {
if (inList(state.localVars))
return;
state.localVars = {
name : varname,
next : state.localVars
};
} else {
if (inList(state.globalVars))
return;
if (parserConfig.globalVars)
state.globalVars = {
name : varname,
next : state.globalVars
};
}
}
// Combinators
var defaultVars = {
name : "this",
next : {
name : "arguments"
}
};
function pushcontext() {
cx.state.context = {
prev : cx.state.context,
vars : cx.state.localVars
};
cx.state.localVars = defaultVars;
}
function popcontext() {
cx.state.localVars = cx.state.context.vars;
cx.state.context = cx.state.context.prev;
}
function pushlex(type, info) {
var result = function() {
var state = cx.state, indent = state.indented;
if (state.lexical.type == "stat")
indent = state.lexical.indented;
else
for (var outer = state.lexical; outer
&& outer.type == ")"
&& outer.align; outer = outer.prev)
indent = outer.indented;
state.lexical = new JSLexical(indent,
cx.stream.column(), type, null,
state.lexical, info);
};
result.lex = true;
return result;
}
function poplex() {
var state = cx.state;
if (state.lexical.prev) {
if (state.lexical.type == ")")
state.indented = state.lexical.indented;
state.lexical = state.lexical.prev;
}
}
poplex.lex = true;
function expect(wanted) {
function exp(type) {
if (type == wanted)
return cont();
else if (wanted == ";")
return pass();
else
return cont(exp);
}
;
return exp;
}
function statement(type, value) {
if (type == "var")
return cont(pushlex("vardef",
value.length), vardef,
expect(";"), poplex);
if (type == "keyword a")
return cont(pushlex("form"), parenExpr,
statement, poplex);
if (type == "keyword b")
return cont(pushlex("form"), statement,
poplex);
if (type == "{")
return cont(pushlex("}"), block, poplex);
if (type == ";")
return cont();
if (type == "if") {
if (cx.state.lexical.info == "else"
&& cx.state.cc[cx.state.cc.length - 1] == poplex)
cx.state.cc.pop()();
return cont(pushlex("form"), parenExpr,
statement, poplex, maybeelse);
}
if (type == "function")
return cont(functiondef);
if (type == "for")
return cont(pushlex("form"), forspec,
statement, poplex);
if (type == "variable") {
if (isTS && value == "type") {
cx.marked = "keyword"
return cont(typeexpr,
expect("operator"),
typeexpr, expect(";"));
} else {
return cont(pushlex("stat"),
maybelabel);
}
}
if (type == "switch")
return cont(pushlex("form"), parenExpr,
expect("{"), pushlex("}",
"switch"), block,
poplex, poplex);
if (type == "case")
return cont(expression, expect(":"));
if (type == "default")
return cont(expect(":"));
if (type == "catch")
return cont(pushlex("form"),
pushcontext, expect("("),
funarg, expect(")"), statement,
poplex, popcontext);
if (type == "class")
return cont(pushlex("form"), className,
poplex);
if (type == "export")
return cont(pushlex("stat"),
afterExport, poplex);
if (type == "import")
return cont(pushlex("stat"),
afterImport, poplex);
if (type == "module")
return cont(pushlex("form"), pattern,
expect("{"), pushlex("}"),
block, poplex, poplex)
if (type == "async")
return cont(statement)
if (value == "@")
return cont(expression, statement)
return pass(pushlex("stat"), expression,
expect(";"), poplex);
}
function expression(type) {
return expressionInner(type, false);
}
function expressionNoComma(type) {
return expressionInner(type, true);
}
function parenExpr(type) {
if (type != "(")
return pass()
return cont(pushlex(")"), expression,
expect(")"), poplex)
}
function expressionInner(type, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma
: arrowBody;
if (type == "(")
return cont(pushcontext,
pushlex(")"), commasep(
pattern, ")"),
poplex, expect("=>"), body,
popcontext);
else if (type == "variable")
return pass(pushcontext, pattern,
expect("=>"), body,
popcontext);
}
var maybeop = noComma ? maybeoperatorNoComma
: maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type))
return cont(maybeop);
if (type == "function")
return cont(functiondef, maybeop);
if (type == "class")
return cont(pushlex("form"),
classExpression, poplex);
if (type == "keyword c" || type == "async")
return cont(noComma ? maybeexpressionNoComma
: maybeexpression);
if (type == "(")
return cont(pushlex(")"),
maybeexpression, expect(")"),
poplex, maybeop);
if (type == "operator" || type == "spread")
return cont(noComma ? expressionNoComma
: expression);
if (type == "[")
return cont(pushlex("]"), arrayLiteral,
poplex, maybeop);
if (type == "{")
return contCommasep(objprop, "}", null,
maybeop);
if (type == "quasi")
return pass(quasi, maybeop);
if (type == "new")
return cont(maybeTarget(noComma));
return cont();
}
function maybeexpression(type) {
if (type.match(/[;\}\)\],]/))
return pass();
return pass(expression);
}
function maybeexpressionNoComma(type) {
if (type.match(/[;\}\)\],]/))
return pass();
return pass(expressionNoComma);
}
function maybeoperatorComma(type, value) {
if (type == ",")
return cont(expression);
return maybeoperatorNoComma(type, value,
false);
}
function maybeoperatorNoComma(type, value,
noComma) {
var me = noComma == false ? maybeoperatorComma
: maybeoperatorNoComma;
var expr = noComma == false ? expression
: expressionNoComma;
if (type == "=>")
return cont(pushcontext,
noComma ? arrowBodyNoComma
: arrowBody, popcontext);
if (type == "operator") {
if (/\+\+|--/.test(value))
return cont(me);
if (value == "?")
return cont(expression,
expect(":"), expr);
return cont(expr);
}
if (type == "quasi") {
return pass(quasi, me);
}
if (type == ";")
return;
if (type == "(")
return contCommasep(expressionNoComma,
")", "call", me);
if (type == ".")
return cont(property, me);
if (type == "[")
return cont(pushlex("]"),
maybeexpression, expect("]"),
poplex, me);
if (isTS && value == "as") {
cx.marked = "keyword";
return cont(typeexpr, me)
}
}
function quasi(type, value) {
if (type != "quasi")
return pass();
if (value.slice(value.length - 2) != "${")
return cont(quasi);
return cont(expression, continueQuasi);
}
function continueQuasi(type) {
if (type == "}") {
cx.marked = "string-2";
cx.state.tokenize = tokenQuasi;
return cont(quasi);
}
}
function arrowBody(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement
: expression);
}
function arrowBodyNoComma(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement
: expressionNoComma);
}
function maybeTarget(noComma) {
return function(type) {
if (type == ".")
return cont(noComma ? targetNoComma
: target);
else
return pass(noComma ? expressionNoComma
: expression);
};
}
function target(_, value) {
if (value == "target") {
cx.marked = "keyword";
return cont(maybeoperatorComma);
}
}
function targetNoComma(_, value) {
if (value == "target") {
cx.marked = "keyword";
return cont(maybeoperatorNoComma);
}
}
function maybelabel(type) {
if (type == ":")
return cont(poplex, statement);
return pass(maybeoperatorComma,
expect(";"), poplex);
}
function property(type) {
if (type == "variable") {
cx.marked = "property";
return cont();
}
}
function objprop(type, value) {
if (type == "async") {
cx.marked = "property";
return cont(objprop);
} else if (type == "variable"
|| cx.style == "keyword") {
cx.marked = "property";
if (value == "get" || value == "set")
return cont(getterSetter);
return cont(afterprop);
} else if (type == "number"
|| type == "string") {
cx.marked = jsonldMode ? "property"
: (cx.style + " property");
return cont(afterprop);
} else if (type == "jsonld-keyword") {
return cont(afterprop);
} else if (type == "modifier") {
return cont(objprop)
} else if (type == "[") {
return cont(expression, expect("]"),
afterprop);
} else if (type == "spread") {
return cont(expression, afterprop);
} else if (type == ":") {
return pass(afterprop)
}
}
function getterSetter(type) {
if (type != "variable")
return pass(afterprop);
cx.marked = "property";
return cont(functiondef);
}
function afterprop(type) {
if (type == ":")
return cont(expressionNoComma);
if (type == "(")
return pass(functiondef);
}
function commasep(what, end, sep) {
function proceed(type, value) {
if (sep ? sep.indexOf(type) > -1
: type == ",") {
var lex = cx.state.lexical;
if (lex.info == "call")
lex.pos = (lex.pos || 0) + 1;
return cont(
function(type, value) {
if (type == end
|| value == end)
return pass()
return pass(what)
}, proceed);
}
if (type == end || value == end)
return cont();
return cont(expect(end));
}
return function(type, value) {
if (type == end || value == end)
return cont();
return pass(what, proceed);
};
}
function contCommasep(what, end, info) {
for (var i = 3; i < arguments.length; i++)
cx.cc.push(arguments[i]);
return cont(pushlex(end, info), commasep(
what, end), poplex);
}
function block(type) {
if (type == "}")
return cont();
return pass(statement, block);
}
function maybetype(type, value) {
if (isTS) {
if (type == ":")
return cont(typeexpr);
if (value == "?")
return cont(maybetype);
}
}
function typeexpr(type) {
if (type == "variable") {
cx.marked = "type";
return cont(afterType);
}
if (type == "string" || type == "number"
|| type == "atom")
return cont(afterType);
if (type == "{")
return cont(pushlex("}"), commasep(
typeprop, "}", ",;"), poplex,
afterType)
if (type == "(")
return cont(commasep(typearg, ")"),
maybeReturnType)
}
function maybeReturnType(type) {
if (type == "=>")
return cont(typeexpr)
}
function typeprop(type, value) {
if (type == "variable"
|| cx.style == "keyword") {
cx.marked = "property"
return cont(typeprop)
} else if (value == "?") {
return cont(typeprop)
} else if (type == ":") {
return cont(typeexpr)
} else if (type == "[") {
return cont(expression, maybetype,
expect("]"), typeprop)
}
}
function typearg(type) {
if (type == "variable")
return cont(typearg)
else if (type == ":")
return cont(typeexpr)
}
function afterType(type, value) {
if (value == "<")
return cont(pushlex(">"), commasep(
typeexpr, ">"), poplex,
afterType)
if (value == "|" || type == ".")
return cont(typeexpr)
if (type == "[")
return cont(expect("]"), afterType)
if (value == "extends")
return cont(typeexpr)
}
function vardef() {
return pass(pattern, maybetype,
maybeAssign, vardefCont);
}
function pattern(type, value) {
if (type == "modifier")
return cont(pattern)
if (type == "variable") {
register(value);
return cont();
}
if (type == "spread")
return cont(pattern);
if (type == "[")
return contCommasep(pattern, "]");
if (type == "{")
return contCommasep(proppattern, "}");
}
function proppattern(type, value) {
if (type == "variable"
&& !cx.stream.match(/^\s*:/, false)) {
register(value);
return cont(maybeAssign);
}
if (type == "variable")
cx.marked = "property";
if (type == "spread")
return cont(pattern);
if (type == "}")
return pass();
return cont(expect(":"), pattern,
maybeAssign);
}
function maybeAssign(_type, value) {
if (value == "=")
return cont(expressionNoComma);
}
function vardefCont(type) {
if (type == ",")
return cont(vardef);
}
function maybeelse(type, value) {
if (type == "keyword b" && value == "else")
return cont(pushlex("form", "else"),
statement, poplex);
}
function forspec(type) {
if (type == "(")
return cont(pushlex(")"), forspec1,
expect(")"), poplex);
}
function forspec1(type) {
if (type == "var")
return cont(vardef, expect(";"),
forspec2);
if (type == ";")
return cont(forspec2);
if (type == "variable")
return cont(formaybeinof);
return pass(expression, expect(";"),
forspec2);
}
function formaybeinof(_type, value) {
if (value == "in" || value == "of") {
cx.marked = "keyword";
return cont(expression);
}
return cont(maybeoperatorComma, forspec2);
}
function forspec2(type, value) {
if (type == ";")
return cont(forspec3);
if (value == "in" || value == "of") {
cx.marked = "keyword";
return cont(expression);
}
return pass(expression, expect(";"),
forspec3);
}
function forspec3(type) {
if (type != ")")
cont(expression);
}
function functiondef(type, value) {
if (value == "*") {
cx.marked = "keyword";
return cont(functiondef);
}
if (type == "variable") {
register(value);
return cont(functiondef);
}
if (type == "(")
return cont(pushcontext, pushlex(")"),
commasep(funarg, ")"), poplex,
maybetype, statement,
popcontext);
if (isTS && value == "<")
return cont(pushlex(">"), commasep(
typeexpr, ">"), poplex,
functiondef)
}
function funarg(type) {
if (type == "spread")
return cont(funarg);
return pass(pattern, maybetype, maybeAssign);
}
function classExpression(type, value) {
// Class expressions may have an optional
// name.
if (type == "variable")
return className(type, value);
return classNameAfter(type, value);
}
function className(type, value) {
if (type == "variable") {
register(value);
return cont(classNameAfter);
}
}
function classNameAfter(type, value) {
if (value == "<")
return cont(pushlex(">"), commasep(
typeexpr, ">"), poplex,
classNameAfter)
if (value == "extends"
|| value == "implements"
|| (isTS && type == ","))
return cont(isTS ? typeexpr
: expression, classNameAfter);
if (type == "{")
return cont(pushlex("}"), classBody,
poplex);
}
function classBody(type, value) {
if (type == "variable"
|| cx.style == "keyword") {
if ((value == "async"
|| value == "static"
|| value == "get"
|| value == "set" || (isTS && (value == "public"
|| value == "private"
|| value == "protected"
|| value == "readonly" || value == "abstract")))
&& cx.stream.match(
/^\s+[\w$\xa1-\uffff]/,
false)) {
cx.marked = "keyword";
return cont(classBody);
}
cx.marked = "property";
return cont(isTS ? classfield
: functiondef, classBody);
}
if (type == "[")
return cont(
expression,
expect("]"),
isTS ? classfield : functiondef,
classBody)
if (value == "*") {
cx.marked = "keyword";
return cont(classBody);
}
if (type == ";")
return cont(classBody);
if (type == "}")
return cont();
if (value == "@")
return cont(expression, classBody)
}
function classfield(type, value) {
if (value == "?")
return cont(classfield)
if (type == ":")
return cont(typeexpr, maybeAssign)
if (value == "=")
return cont(expressionNoComma)
return pass(functiondef)
}
function afterExport(type, value) {
if (value == "*") {
cx.marked = "keyword";
return cont(maybeFrom, expect(";"));
}
if (value == "default") {
cx.marked = "keyword";
return cont(expression, expect(";"));
}
if (type == "{")
return cont(commasep(exportField, "}"),
maybeFrom, expect(";"));
return pass(statement);
}
function exportField(type, value) {
if (value == "as") {
cx.marked = "keyword";
return cont(expect("variable"));
}
if (type == "variable")
return pass(expressionNoComma,
exportField);
}
function afterImport(type) {
if (type == "string")
return cont();
return pass(importSpec, maybeMoreImports,
maybeFrom);
}
function importSpec(type, value) {
if (type == "{")
return contCommasep(importSpec, "}");
if (type == "variable")
register(value);
if (value == "*")
cx.marked = "keyword";
return cont(maybeAs);
}
function maybeMoreImports(type) {
if (type == ",")
return cont(importSpec,
maybeMoreImports)
}
function maybeAs(_type, value) {
if (value == "as") {
cx.marked = "keyword";
return cont(importSpec);
}
}
function maybeFrom(_type, value) {
if (value == "from") {
cx.marked = "keyword";
return cont(expression);
}
}
function arrayLiteral(type) {
if (type == "]")
return cont();
return pass(commasep(expressionNoComma, "]"));
}
function isContinuedStatement(state, textAfter) {
return state.lastType == "operator"
|| state.lastType == ","
|| isOperatorChar.test(textAfter
.charAt(0))
|| /[,.]/.test(textAfter.charAt(0));
}
// Interface
return {
startState : function(basecolumn) {
var state = {
tokenize : tokenBase,
lastType : "sof",
cc : [],
lexical : new JSLexical(
(basecolumn || 0)
- indentUnit, 0,
"block", false),
localVars : parserConfig.localVars,
context : parserConfig.localVars
&& {
vars : parserConfig.localVars
},
indented : basecolumn || 0
};
if (parserConfig.globalVars
&& typeof parserConfig.globalVars == "object")
state.globalVars = parserConfig.globalVars;
return state;
},
token : function(stream, state) {
if (stream.sol()) {
if (!state.lexical
.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream
.indentation();
findFatArrow(stream, state);
}
if (state.tokenize != tokenComment
&& stream.eatSpace())
return null;
var style = state.tokenize(stream,
state);
if (type == "comment")
return style;
state.lastType = type == "operator"
&& (content == "++" || content == "--") ? "incdec"
: type;
return parseJS(state, style, type,
content, stream);
},
indent : function(state, textAfter) {
if (state.tokenize == tokenComment)
return CodeMirror.Pass;
if (state.tokenize != tokenBase)
return 0;
var firstChar = textAfter
&& textAfter.charAt(0), lexical = state.lexical, top
// Kludge to prevent 'maybelse' from
// blocking lexical scope pops
if (!/^\s*else\b/.test(textAfter))
for (var i = state.cc.length - 1; i >= 0; --i) {
var c = state.cc[i];
if (c == poplex)
lexical = lexical.prev;
else if (c != maybeelse)
break;
}
while ((lexical.type == "stat" || lexical.type == "form")
&& (firstChar == "}" || ((top = state.cc[state.cc.length - 1])
&& (top == maybeoperatorComma || top == maybeoperatorNoComma) && !/^[,\.=+\-*:?[\(]/
.test(textAfter))))
lexical = lexical.prev;
if (statementIndent
&& lexical.type == ")"
&& lexical.prev.type == "stat")
lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
if (type == "vardef")
return lexical.indented
+ (state.lastType == "operator"
|| state.lastType == "," ? lexical.info + 1
: 0);
else if (type == "form"
&& firstChar == "{")
return lexical.indented;
else if (type == "form")
return lexical.indented
+ indentUnit;
else if (type == "stat")
return lexical.indented
+ (isContinuedStatement(
state, textAfter) ? statementIndent
|| indentUnit
: 0);
else if (lexical.info == "switch"
&& !closing
&& parserConfig.doubleIndentSwitch != false)
return lexical.indented
+ (/^(?:case|default)\b/
.test(textAfter) ? indentUnit
: 2 * indentUnit);
else if (lexical.align)
return lexical.column
+ (closing ? 0 : 1);
else
return lexical.indented
+ (closing ? 0 : indentUnit);
},
electricInput : /^\s*(?:case .*?:|default:|\{|\})$/,
blockCommentStart : jsonMode ? null : "/*",
blockCommentEnd : jsonMode ? null : "*/",
lineComment : jsonMode ? null : "//",
fold : "brace",
closeBrackets : "()[]{}''\"\"``",
helperType : jsonMode ? "json"
: "javascript",
jsonldMode : jsonldMode,
jsonMode : jsonMode,
expressionAllowed : expressionAllowed,
skipExpression : function(state) {
var top = state.cc[state.cc.length - 1]
if (top == expression
|| top == expressionNoComma)
state.cc.pop()
}
};
});
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
CodeMirror.defineMIME("text/javascript", "javascript");
CodeMirror.defineMIME("text/ecmascript", "javascript");
CodeMirror.defineMIME("application/javascript", "javascript");
CodeMirror.defineMIME("application/x-javascript", "javascript");
CodeMirror.defineMIME("application/ecmascript", "javascript");
CodeMirror.defineMIME("application/json", {
name : "javascript",
json : true
});
CodeMirror.defineMIME("application/x-json", {
name : "javascript",
json : true
});
CodeMirror.defineMIME("application/ld+json", {
name : "javascript",
jsonld : true
});
CodeMirror.defineMIME("text/typescript", {
name : "javascript",
typescript : true
});
CodeMirror.defineMIME("application/typescript", {
name : "javascript",
typescript : true
});
});