GPQAPP
960 строк · 38.0 Кб
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: https://codemirror.net/LICENSE
3
4(function(mod) {5if (typeof exports == "object" && typeof module == "object") // CommonJS6mod(require("../../lib/codemirror"));7else if (typeof define == "function" && define.amd) // AMD8define(["../../lib/codemirror"], mod);9else // Plain browser env10mod(CodeMirror);11})(function(CodeMirror) {12"use strict";13
14CodeMirror.defineMode("javascript", function(config, parserConfig) {15var indentUnit = config.indentUnit;16var statementIndent = parserConfig.statementIndent;17var jsonldMode = parserConfig.jsonld;18var jsonMode = parserConfig.json || jsonldMode;19var trackScope = parserConfig.trackScope !== false20var isTS = parserConfig.typescript;21var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;22
23// Tokenizer24
25var keywords = function(){26function kw(type) {return {type: type, style: "keyword"};}27var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");28var operator = kw("operator"), atom = {type: "atom", style: "atom"};29
30return {31"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,32"return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,33"debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),34"function": kw("function"), "catch": kw("catch"),35"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),36"in": operator, "typeof": operator, "instanceof": operator,37"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,38"this": kw("this"), "class": kw("class"), "super": kw("atom"),39"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,40"await": C41};42}();43
44var isOperatorChar = /[+\-*&%=<>!?|~^@]/;45var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;46
47function readRegexp(stream) {48var escaped = false, next, inSet = false;49while ((next = stream.next()) != null) {50if (!escaped) {51if (next == "/" && !inSet) return;52if (next == "[") inSet = true;53else if (inSet && next == "]") inSet = false;54}55escaped = !escaped && next == "\\";56}57}58
59// Used as scratch variables to communicate multiple values without60// consing up tons of objects.61var type, content;62function ret(tp, style, cont) {63type = tp; content = cont;64return style;65}66function tokenBase(stream, state) {67var ch = stream.next();68if (ch == '"' || ch == "'") {69state.tokenize = tokenString(ch);70return state.tokenize(stream, state);71} else if (ch == "." && stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)) {72return ret("number", "number");73} else if (ch == "." && stream.match("..")) {74return ret("spread", "meta");75} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {76return ret(ch);77} else if (ch == "=" && stream.eat(">")) {78return ret("=>", "operator");79} else if (ch == "0" && stream.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)) {80return ret("number", "number");81} else if (/\d/.test(ch)) {82stream.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/);83return ret("number", "number");84} else if (ch == "/") {85if (stream.eat("*")) {86state.tokenize = tokenComment;87return tokenComment(stream, state);88} else if (stream.eat("/")) {89stream.skipToEnd();90return ret("comment", "comment");91} else if (expressionAllowed(stream, state, 1)) {92readRegexp(stream);93stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/);94return ret("regexp", "string-2");95} else {96stream.eat("=");97return ret("operator", "operator", stream.current());98}99} else if (ch == "`") {100state.tokenize = tokenQuasi;101return tokenQuasi(stream, state);102} else if (ch == "#" && stream.peek() == "!") {103stream.skipToEnd();104return ret("meta", "meta");105} else if (ch == "#" && stream.eatWhile(wordRE)) {106return ret("variable", "property")107} else if (ch == "<" && stream.match("!--") ||108(ch == "-" && stream.match("->") && !/\S/.test(stream.string.slice(0, stream.start)))) {109stream.skipToEnd()110return ret("comment", "comment")111} else if (isOperatorChar.test(ch)) {112if (ch != ">" || !state.lexical || state.lexical.type != ">") {113if (stream.eat("=")) {114if (ch == "!" || ch == "=") stream.eat("=")115} else if (/[<>*+\-|&?]/.test(ch)) {116stream.eat(ch)117if (ch == ">") stream.eat(ch)118}119}120if (ch == "?" && stream.eat(".")) return ret(".")121return ret("operator", "operator", stream.current());122} else if (wordRE.test(ch)) {123stream.eatWhile(wordRE);124var word = stream.current()125if (state.lastType != ".") {126if (keywords.propertyIsEnumerable(word)) {127var kw = keywords[word]128return ret(kw.type, kw.style, word)129}130if (word == "async" && stream.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/, false))131return ret("async", "keyword", word)132}133return ret("variable", "variable", word)134}135}136
137function tokenString(quote) {138return function(stream, state) {139var escaped = false, next;140if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){141state.tokenize = tokenBase;142return ret("jsonld-keyword", "meta");143}144while ((next = stream.next()) != null) {145if (next == quote && !escaped) break;146escaped = !escaped && next == "\\";147}148if (!escaped) state.tokenize = tokenBase;149return ret("string", "string");150};151}152
153function tokenComment(stream, state) {154var maybeEnd = false, ch;155while (ch = stream.next()) {156if (ch == "/" && maybeEnd) {157state.tokenize = tokenBase;158break;159}160maybeEnd = (ch == "*");161}162return ret("comment", "comment");163}164
165function tokenQuasi(stream, state) {166var escaped = false, next;167while ((next = stream.next()) != null) {168if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {169state.tokenize = tokenBase;170break;171}172escaped = !escaped && next == "\\";173}174return ret("quasi", "string-2", stream.current());175}176
177var brackets = "([{}])";178// This is a crude lookahead trick to try and notice that we're179// parsing the argument patterns for a fat-arrow function before we180// actually hit the arrow token. It only works if the arrow is on181// the same line as the arguments and there's no strange noise182// (comments) in between. Fallback is to only notice when we hit the183// arrow, and not declare the arguments as locals for the arrow184// body.185function findFatArrow(stream, state) {186if (state.fatArrowAt) state.fatArrowAt = null;187var arrow = stream.string.indexOf("=>", stream.start);188if (arrow < 0) return;189
190if (isTS) { // Try to skip TypeScript return type declarations after the arguments191var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))192if (m) arrow = m.index193}194
195var depth = 0, sawSomething = false;196for (var pos = arrow - 1; pos >= 0; --pos) {197var ch = stream.string.charAt(pos);198var bracket = brackets.indexOf(ch);199if (bracket >= 0 && bracket < 3) {200if (!depth) { ++pos; break; }201if (--depth == 0) { if (ch == "(") sawSomething = true; break; }202} else if (bracket >= 3 && bracket < 6) {203++depth;204} else if (wordRE.test(ch)) {205sawSomething = true;206} else if (/["'\/`]/.test(ch)) {207for (;; --pos) {208if (pos == 0) return209var next = stream.string.charAt(pos - 1)210if (next == ch && stream.string.charAt(pos - 2) != "\\") { pos--; break }211}212} else if (sawSomething && !depth) {213++pos;214break;215}216}217if (sawSomething && !depth) state.fatArrowAt = pos;218}219
220// Parser221
222var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true,223"regexp": true, "this": true, "import": true, "jsonld-keyword": true};224
225function JSLexical(indented, column, type, align, prev, info) {226this.indented = indented;227this.column = column;228this.type = type;229this.prev = prev;230this.info = info;231if (align != null) this.align = align;232}233
234function inScope(state, varname) {235if (!trackScope) return false236for (var v = state.localVars; v; v = v.next)237if (v.name == varname) return true;238for (var cx = state.context; cx; cx = cx.prev) {239for (var v = cx.vars; v; v = v.next)240if (v.name == varname) return true;241}242}243
244function parseJS(state, style, type, content, stream) {245var cc = state.cc;246// Communicate our context to the combinators.247// (Less wasteful than consing up a hundred closures on every call.)248cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;249
250if (!state.lexical.hasOwnProperty("align"))251state.lexical.align = true;252
253while(true) {254var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;255if (combinator(type, content)) {256while(cc.length && cc[cc.length - 1].lex)257cc.pop()();258if (cx.marked) return cx.marked;259if (type == "variable" && inScope(state, content)) return "variable-2";260return style;261}262}263}264
265// Combinator utils266
267var cx = {state: null, column: null, marked: null, cc: null};268function pass() {269for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);270}271function cont() {272pass.apply(null, arguments);273return true;274}275function inList(name, list) {276for (var v = list; v; v = v.next) if (v.name == name) return true277return false;278}279function register(varname) {280var state = cx.state;281cx.marked = "def";282if (!trackScope) return283if (state.context) {284if (state.lexical.info == "var" && state.context && state.context.block) {285// FIXME function decls are also not block scoped286var newContext = registerVarScoped(varname, state.context)287if (newContext != null) {288state.context = newContext289return290}291} else if (!inList(varname, state.localVars)) {292state.localVars = new Var(varname, state.localVars)293return294}295}296// Fall through means this is global297if (parserConfig.globalVars && !inList(varname, state.globalVars))298state.globalVars = new Var(varname, state.globalVars)299}300function registerVarScoped(varname, context) {301if (!context) {302return null303} else if (context.block) {304var inner = registerVarScoped(varname, context.prev)305if (!inner) return null306if (inner == context.prev) return context307return new Context(inner, context.vars, true)308} else if (inList(varname, context.vars)) {309return context310} else {311return new Context(context.prev, new Var(varname, context.vars), false)312}313}314
315function isModifier(name) {316return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"317}318
319// Combinators320
321function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block }322function Var(name, next) { this.name = name; this.next = next }323
324var defaultVars = new Var("this", new Var("arguments", null))325function pushcontext() {326cx.state.context = new Context(cx.state.context, cx.state.localVars, false)327cx.state.localVars = defaultVars328}329function pushblockcontext() {330cx.state.context = new Context(cx.state.context, cx.state.localVars, true)331cx.state.localVars = null332}333pushcontext.lex = pushblockcontext.lex = true334function popcontext() {335cx.state.localVars = cx.state.context.vars336cx.state.context = cx.state.context.prev337}338popcontext.lex = true339function pushlex(type, info) {340var result = function() {341var state = cx.state, indent = state.indented;342if (state.lexical.type == "stat") indent = state.lexical.indented;343else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)344indent = outer.indented;345state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);346};347result.lex = true;348return result;349}350function poplex() {351var state = cx.state;352if (state.lexical.prev) {353if (state.lexical.type == ")")354state.indented = state.lexical.indented;355state.lexical = state.lexical.prev;356}357}358poplex.lex = true;359
360function expect(wanted) {361function exp(type) {362if (type == wanted) return cont();363else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass();364else return cont(exp);365};366return exp;367}368
369function statement(type, value) {370if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex);371if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);372if (type == "keyword b") return cont(pushlex("form"), statement, poplex);373if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);374if (type == "debugger") return cont(expect(";"));375if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext);376if (type == ";") return cont();377if (type == "if") {378if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)379cx.state.cc.pop()();380return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);381}382if (type == "function") return cont(functiondef);383if (type == "for") return cont(pushlex("form"), pushblockcontext, forspec, statement, popcontext, poplex);384if (type == "class" || (isTS && value == "interface")) {385cx.marked = "keyword"386return cont(pushlex("form", type == "class" ? type : value), className, poplex)387}388if (type == "variable") {389if (isTS && value == "declare") {390cx.marked = "keyword"391return cont(statement)392} else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {393cx.marked = "keyword"394if (value == "enum") return cont(enumdef);395else if (value == "type") return cont(typename, expect("operator"), typeexpr, expect(";"));396else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)397} else if (isTS && value == "namespace") {398cx.marked = "keyword"399return cont(pushlex("form"), expression, statement, poplex)400} else if (isTS && value == "abstract") {401cx.marked = "keyword"402return cont(statement)403} else {404return cont(pushlex("stat"), maybelabel);405}406}407if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext,408block, poplex, poplex, popcontext);409if (type == "case") return cont(expression, expect(":"));410if (type == "default") return cont(expect(":"));411if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext);412if (type == "export") return cont(pushlex("stat"), afterExport, poplex);413if (type == "import") return cont(pushlex("stat"), afterImport, poplex);414if (type == "async") return cont(statement)415if (value == "@") return cont(expression, statement)416return pass(pushlex("stat"), expression, expect(";"), poplex);417}418function maybeCatchBinding(type) {419if (type == "(") return cont(funarg, expect(")"))420}421function expression(type, value) {422return expressionInner(type, value, false);423}424function expressionNoComma(type, value) {425return expressionInner(type, value, true);426}427function parenExpr(type) {428if (type != "(") return pass()429return cont(pushlex(")"), maybeexpression, expect(")"), poplex)430}431function expressionInner(type, value, noComma) {432if (cx.state.fatArrowAt == cx.stream.start) {433var body = noComma ? arrowBodyNoComma : arrowBody;434if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);435else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);436}437
438var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;439if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);440if (type == "function") return cont(functiondef, maybeop);441if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }442if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);443if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);444if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);445if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);446if (type == "{") return contCommasep(objprop, "}", null, maybeop);447if (type == "quasi") return pass(quasi, maybeop);448if (type == "new") return cont(maybeTarget(noComma));449return cont();450}451function maybeexpression(type) {452if (type.match(/[;\}\)\],]/)) return pass();453return pass(expression);454}455
456function maybeoperatorComma(type, value) {457if (type == ",") return cont(maybeexpression);458return maybeoperatorNoComma(type, value, false);459}460function maybeoperatorNoComma(type, value, noComma) {461var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;462var expr = noComma == false ? expression : expressionNoComma;463if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);464if (type == "operator") {465if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);466if (isTS && value == "<" && cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/, false))467return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);468if (value == "?") return cont(expression, expect(":"), expr);469return cont(expr);470}471if (type == "quasi") { return pass(quasi, me); }472if (type == ";") return;473if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);474if (type == ".") return cont(property, me);475if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);476if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }477if (type == "regexp") {478cx.state.lastType = cx.marked = "operator"479cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)480return cont(expr)481}482}483function quasi(type, value) {484if (type != "quasi") return pass();485if (value.slice(value.length - 2) != "${") return cont(quasi);486return cont(maybeexpression, continueQuasi);487}488function continueQuasi(type) {489if (type == "}") {490cx.marked = "string-2";491cx.state.tokenize = tokenQuasi;492return cont(quasi);493}494}495function arrowBody(type) {496findFatArrow(cx.stream, cx.state);497return pass(type == "{" ? statement : expression);498}499function arrowBodyNoComma(type) {500findFatArrow(cx.stream, cx.state);501return pass(type == "{" ? statement : expressionNoComma);502}503function maybeTarget(noComma) {504return function(type) {505if (type == ".") return cont(noComma ? targetNoComma : target);506else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)507else return pass(noComma ? expressionNoComma : expression);508};509}510function target(_, value) {511if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }512}513function targetNoComma(_, value) {514if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }515}516function maybelabel(type) {517if (type == ":") return cont(poplex, statement);518return pass(maybeoperatorComma, expect(";"), poplex);519}520function property(type) {521if (type == "variable") {cx.marked = "property"; return cont();}522}523function objprop(type, value) {524if (type == "async") {525cx.marked = "property";526return cont(objprop);527} else if (type == "variable" || cx.style == "keyword") {528cx.marked = "property";529if (value == "get" || value == "set") return cont(getterSetter);530var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params531if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))532cx.state.fatArrowAt = cx.stream.pos + m[0].length533return cont(afterprop);534} else if (type == "number" || type == "string") {535cx.marked = jsonldMode ? "property" : (cx.style + " property");536return cont(afterprop);537} else if (type == "jsonld-keyword") {538return cont(afterprop);539} else if (isTS && isModifier(value)) {540cx.marked = "keyword"541return cont(objprop)542} else if (type == "[") {543return cont(expression, maybetype, expect("]"), afterprop);544} else if (type == "spread") {545return cont(expressionNoComma, afterprop);546} else if (value == "*") {547cx.marked = "keyword";548return cont(objprop);549} else if (type == ":") {550return pass(afterprop)551}552}553function getterSetter(type) {554if (type != "variable") return pass(afterprop);555cx.marked = "property";556return cont(functiondef);557}558function afterprop(type) {559if (type == ":") return cont(expressionNoComma);560if (type == "(") return pass(functiondef);561}562function commasep(what, end, sep) {563function proceed(type, value) {564if (sep ? sep.indexOf(type) > -1 : type == ",") {565var lex = cx.state.lexical;566if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;567return cont(function(type, value) {568if (type == end || value == end) return pass()569return pass(what)570}, proceed);571}572if (type == end || value == end) return cont();573if (sep && sep.indexOf(";") > -1) return pass(what)574return cont(expect(end));575}576return function(type, value) {577if (type == end || value == end) return cont();578return pass(what, proceed);579};580}581function contCommasep(what, end, info) {582for (var i = 3; i < arguments.length; i++)583cx.cc.push(arguments[i]);584return cont(pushlex(end, info), commasep(what, end), poplex);585}586function block(type) {587if (type == "}") return cont();588return pass(statement, block);589}590function maybetype(type, value) {591if (isTS) {592if (type == ":") return cont(typeexpr);593if (value == "?") return cont(maybetype);594}595}596function maybetypeOrIn(type, value) {597if (isTS && (type == ":" || value == "in")) return cont(typeexpr)598}599function mayberettype(type) {600if (isTS && type == ":") {601if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)602else return cont(typeexpr)603}604}605function isKW(_, value) {606if (value == "is") {607cx.marked = "keyword"608return cont()609}610}611function typeexpr(type, value) {612if (value == "keyof" || value == "typeof" || value == "infer" || value == "readonly") {613cx.marked = "keyword"614return cont(value == "typeof" ? expressionNoComma : typeexpr)615}616if (type == "variable" || value == "void") {617cx.marked = "type"618return cont(afterType)619}620if (value == "|" || value == "&") return cont(typeexpr)621if (type == "string" || type == "number" || type == "atom") return cont(afterType);622if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)623if (type == "{") return cont(pushlex("}"), typeprops, poplex, afterType)624if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType)625if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)626if (type == "quasi") { return pass(quasiType, afterType); }627}628function maybeReturnType(type) {629if (type == "=>") return cont(typeexpr)630}631function typeprops(type) {632if (type.match(/[\}\)\]]/)) return cont()633if (type == "," || type == ";") return cont(typeprops)634return pass(typeprop, typeprops)635}636function typeprop(type, value) {637if (type == "variable" || cx.style == "keyword") {638cx.marked = "property"639return cont(typeprop)640} else if (value == "?" || type == "number" || type == "string") {641return cont(typeprop)642} else if (type == ":") {643return cont(typeexpr)644} else if (type == "[") {645return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop)646} else if (type == "(") {647return pass(functiondecl, typeprop)648} else if (!type.match(/[;\}\)\],]/)) {649return cont()650}651}652function quasiType(type, value) {653if (type != "quasi") return pass();654if (value.slice(value.length - 2) != "${") return cont(quasiType);655return cont(typeexpr, continueQuasiType);656}657function continueQuasiType(type) {658if (type == "}") {659cx.marked = "string-2";660cx.state.tokenize = tokenQuasi;661return cont(quasiType);662}663}664function typearg(type, value) {665if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)666if (type == ":") return cont(typeexpr)667if (type == "spread") return cont(typearg)668return pass(typeexpr)669}670function afterType(type, value) {671if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)672if (value == "|" || type == "." || value == "&") return cont(typeexpr)673if (type == "[") return cont(typeexpr, expect("]"), afterType)674if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }675if (value == "?") return cont(typeexpr, expect(":"), typeexpr)676}677function maybeTypeArgs(_, value) {678if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)679}680function typeparam() {681return pass(typeexpr, maybeTypeDefault)682}683function maybeTypeDefault(_, value) {684if (value == "=") return cont(typeexpr)685}686function vardef(_, value) {687if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}688return pass(pattern, maybetype, maybeAssign, vardefCont);689}690function pattern(type, value) {691if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }692if (type == "variable") { register(value); return cont(); }693if (type == "spread") return cont(pattern);694if (type == "[") return contCommasep(eltpattern, "]");695if (type == "{") return contCommasep(proppattern, "}");696}697function proppattern(type, value) {698if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {699register(value);700return cont(maybeAssign);701}702if (type == "variable") cx.marked = "property";703if (type == "spread") return cont(pattern);704if (type == "}") return pass();705if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern);706return cont(expect(":"), pattern, maybeAssign);707}708function eltpattern() {709return pass(pattern, maybeAssign)710}711function maybeAssign(_type, value) {712if (value == "=") return cont(expressionNoComma);713}714function vardefCont(type) {715if (type == ",") return cont(vardef);716}717function maybeelse(type, value) {718if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);719}720function forspec(type, value) {721if (value == "await") return cont(forspec);722if (type == "(") return cont(pushlex(")"), forspec1, poplex);723}724function forspec1(type) {725if (type == "var") return cont(vardef, forspec2);726if (type == "variable") return cont(forspec2);727return pass(forspec2)728}729function forspec2(type, value) {730if (type == ")") return cont()731if (type == ";") return cont(forspec2)732if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression, forspec2) }733return pass(expression, forspec2)734}735function functiondef(type, value) {736if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}737if (type == "variable") {register(value); return cont(functiondef);}738if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);739if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)740}741function functiondecl(type, value) {742if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);}743if (type == "variable") {register(value); return cont(functiondecl);}744if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext);745if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl)746}747function typename(type, value) {748if (type == "keyword" || type == "variable") {749cx.marked = "type"750return cont(typename)751} else if (value == "<") {752return cont(pushlex(">"), commasep(typeparam, ">"), poplex)753}754}755function funarg(type, value) {756if (value == "@") cont(expression, funarg)757if (type == "spread") return cont(funarg);758if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }759if (isTS && type == "this") return cont(maybetype, maybeAssign)760return pass(pattern, maybetype, maybeAssign);761}762function classExpression(type, value) {763// Class expressions may have an optional name.764if (type == "variable") return className(type, value);765return classNameAfter(type, value);766}767function className(type, value) {768if (type == "variable") {register(value); return cont(classNameAfter);}769}770function classNameAfter(type, value) {771if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)772if (value == "extends" || value == "implements" || (isTS && type == ",")) {773if (value == "implements") cx.marked = "keyword";774return cont(isTS ? typeexpr : expression, classNameAfter);775}776if (type == "{") return cont(pushlex("}"), classBody, poplex);777}778function classBody(type, value) {779if (type == "async" ||780(type == "variable" &&781(value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&782cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {783cx.marked = "keyword";784return cont(classBody);785}786if (type == "variable" || cx.style == "keyword") {787cx.marked = "property";788return cont(classfield, classBody);789}790if (type == "number" || type == "string") return cont(classfield, classBody);791if (type == "[")792return cont(expression, maybetype, expect("]"), classfield, classBody)793if (value == "*") {794cx.marked = "keyword";795return cont(classBody);796}797if (isTS && type == "(") return pass(functiondecl, classBody)798if (type == ";" || type == ",") return cont(classBody);799if (type == "}") return cont();800if (value == "@") return cont(expression, classBody)801}802function classfield(type, value) {803if (value == "!") return cont(classfield)804if (value == "?") return cont(classfield)805if (type == ":") return cont(typeexpr, maybeAssign)806if (value == "=") return cont(expressionNoComma)807var context = cx.state.lexical.prev, isInterface = context && context.info == "interface"808return pass(isInterface ? functiondecl : functiondef)809}810function afterExport(type, value) {811if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }812if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }813if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));814return pass(statement);815}816function exportField(type, value) {817if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }818if (type == "variable") return pass(expressionNoComma, exportField);819}820function afterImport(type) {821if (type == "string") return cont();822if (type == "(") return pass(expression);823if (type == ".") return pass(maybeoperatorComma);824return pass(importSpec, maybeMoreImports, maybeFrom);825}826function importSpec(type, value) {827if (type == "{") return contCommasep(importSpec, "}");828if (type == "variable") register(value);829if (value == "*") cx.marked = "keyword";830return cont(maybeAs);831}832function maybeMoreImports(type) {833if (type == ",") return cont(importSpec, maybeMoreImports)834}835function maybeAs(_type, value) {836if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }837}838function maybeFrom(_type, value) {839if (value == "from") { cx.marked = "keyword"; return cont(expression); }840}841function arrayLiteral(type) {842if (type == "]") return cont();843return pass(commasep(expressionNoComma, "]"));844}845function enumdef() {846return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)847}848function enummember() {849return pass(pattern, maybeAssign);850}851
852function isContinuedStatement(state, textAfter) {853return state.lastType == "operator" || state.lastType == "," ||854isOperatorChar.test(textAfter.charAt(0)) ||855/[,.]/.test(textAfter.charAt(0));856}857
858function expressionAllowed(stream, state, backUp) {859return state.tokenize == tokenBase &&860/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||861(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))862}863
864// Interface865
866return {867startState: function(basecolumn) {868var state = {869tokenize: tokenBase,870lastType: "sof",871cc: [],872lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),873localVars: parserConfig.localVars,874context: parserConfig.localVars && new Context(null, null, false),875indented: basecolumn || 0876};877if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")878state.globalVars = parserConfig.globalVars;879return state;880},881
882token: function(stream, state) {883if (stream.sol()) {884if (!state.lexical.hasOwnProperty("align"))885state.lexical.align = false;886state.indented = stream.indentation();887findFatArrow(stream, state);888}889if (state.tokenize != tokenComment && stream.eatSpace()) return null;890var style = state.tokenize(stream, state);891if (type == "comment") return style;892state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;893return parseJS(state, style, type, content, stream);894},895
896indent: function(state, textAfter) {897if (state.tokenize == tokenComment || state.tokenize == tokenQuasi) return CodeMirror.Pass;898if (state.tokenize != tokenBase) return 0;899var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top900// Kludge to prevent 'maybelse' from blocking lexical scope pops901if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {902var c = state.cc[i];903if (c == poplex) lexical = lexical.prev;904else if (c != maybeelse && c != popcontext) break;905}906while ((lexical.type == "stat" || lexical.type == "form") &&907(firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&908(top == maybeoperatorComma || top == maybeoperatorNoComma) &&909!/^[,\.=+\-*:?[\(]/.test(textAfter))))910lexical = lexical.prev;911if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")912lexical = lexical.prev;913var type = lexical.type, closing = firstChar == type;914
915if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0);916else if (type == "form" && firstChar == "{") return lexical.indented;917else if (type == "form") return lexical.indented + indentUnit;918else if (type == "stat")919return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);920else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)921return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);922else if (lexical.align) return lexical.column + (closing ? 0 : 1);923else return lexical.indented + (closing ? 0 : indentUnit);924},925
926electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,927blockCommentStart: jsonMode ? null : "/*",928blockCommentEnd: jsonMode ? null : "*/",929blockCommentContinue: jsonMode ? null : " * ",930lineComment: jsonMode ? null : "//",931fold: "brace",932closeBrackets: "()[]{}''\"\"``",933
934helperType: jsonMode ? "json" : "javascript",935jsonldMode: jsonldMode,936jsonMode: jsonMode,937
938expressionAllowed: expressionAllowed,939
940skipExpression: function(state) {941parseJS(state, "atom", "atom", "true", new CodeMirror.StringStream("", 2, null))942}943};944});945
946CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);947
948CodeMirror.defineMIME("text/javascript", "javascript");949CodeMirror.defineMIME("text/ecmascript", "javascript");950CodeMirror.defineMIME("application/javascript", "javascript");951CodeMirror.defineMIME("application/x-javascript", "javascript");952CodeMirror.defineMIME("application/ecmascript", "javascript");953CodeMirror.defineMIME("application/json", { name: "javascript", json: true });954CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true });955CodeMirror.defineMIME("application/manifest+json", { name: "javascript", json: true })956CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true });957CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });958CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });959
960});961