1304 lines
40 KiB
JavaScript
1304 lines
40 KiB
JavaScript
|
// 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
|
||
|
});
|
||
|
|
||
|
});
|