123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074 |
- // CodeMirror, copyright (c) by Marijn Haverbeke and others
- // Distributed under an MIT license: https://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)
- // Plain browser env
- else mod(CodeMirror)
- })(function (CodeMirror) {
- 'use strict'
- CodeMirror.defineMode('javascript', function (config, parserConfig) {
- var indentUnit = config.indentUnit
- var statementIndent = parserConfig.statementIndent
- var jsonldMode = parserConfig.jsonld
- var jsonMode = parserConfig.json || jsonldMode
- var trackScope = parserConfig.trackScope !== false
- 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'),
- D = kw('keyword d')
- var operator = kw('operator'),
- atom = { type: 'atom', style: 'atom' }
- return {
- if: kw('if'),
- while: A,
- with: A,
- else: B,
- do: B,
- try: B,
- finally: B,
- return: D,
- break: D,
- continue: D,
- new: kw('new'),
- delete: C,
- void: C,
- throw: C,
- debugger: kw('debugger'),
- 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'),
- super: kw('atom'),
- yield: C,
- export: kw('export'),
- import: kw('import'),
- extends: C,
- await: C,
- }
- })()
- 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[\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.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)) {
- return ret('number', 'number')
- } else if (/\d/.test(ch)) {
- stream.match(/^[\d_]*(?:n|(?:\.[\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(([gimyus])(?![gimyus]*\2))+\b/)
- return ret('regexp', 'string-2')
- } else {
- stream.eat('=')
- return ret('operator', 'operator', stream.current())
- }
- } else if (ch == '`') {
- state.tokenize = tokenQuasi
- return tokenQuasi(stream, state)
- } else if (ch == '#' && stream.peek() == '!') {
- stream.skipToEnd()
- return ret('meta', 'meta')
- } else if (ch == '#' && stream.eatWhile(wordRE)) {
- return ret('variable', 'property')
- } else if ((ch == '<' && stream.match('!--')) || (ch == '-' && stream.match('->') && !/\S/.test(stream.string.slice(0, stream.start)))) {
- stream.skipToEnd()
- return ret('comment', 'comment')
- } else if (isOperatorChar.test(ch)) {
- if (ch != '>' || !state.lexical || state.lexical.type != '>') {
- if (stream.eat('=')) {
- if (ch == '!' || ch == '=') stream.eat('=')
- } else if (/[<>*+\-|&?]/.test(ch)) {
- stream.eat(ch)
- if (ch == '>') stream.eat(ch)
- }
- }
- if (ch == '?' && stream.eat('.')) return ret('.')
- 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)) {
- for (; ; --pos) {
- if (pos == 0) return
- var next = stream.string.charAt(pos - 1)
- if (next == ch && stream.string.charAt(pos - 2) != '\\') {
- pos--
- break
- }
- }
- } 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, import: 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) {
- if (!trackScope) return false
- 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 inList(name, list) {
- for (var v = list; v; v = v.next) if (v.name == name) return true
- return false
- }
- function register(varname) {
- var state = cx.state
- cx.marked = 'def'
- if (!trackScope) return
- if (state.context) {
- if (state.lexical.info == 'var' && state.context && state.context.block) {
- // FIXME function decls are also not block scoped
- var newContext = registerVarScoped(varname, state.context)
- if (newContext != null) {
- state.context = newContext
- return
- }
- } else if (!inList(varname, state.localVars)) {
- state.localVars = new Var(varname, state.localVars)
- return
- }
- }
- // Fall through means this is global
- if (parserConfig.globalVars && !inList(varname, state.globalVars)) state.globalVars = new Var(varname, state.globalVars)
- }
- function registerVarScoped(varname, context) {
- if (!context) {
- return null
- } else if (context.block) {
- var inner = registerVarScoped(varname, context.prev)
- if (!inner) return null
- if (inner == context.prev) return context
- return new Context(inner, context.vars, true)
- } else if (inList(varname, context.vars)) {
- return context
- } else {
- return new Context(context.prev, new Var(varname, context.vars), false)
- }
- }
- function isModifier(name) {
- return name == 'public' || name == 'private' || name == 'protected' || name == 'abstract' || name == 'readonly'
- }
- // Combinators
- function Context(prev, vars, block) {
- this.prev = prev
- this.vars = vars
- this.block = block
- }
- function Var(name, next) {
- this.name = name
- this.next = next
- }
- var defaultVars = new Var('this', new Var('arguments', null))
- function pushcontext() {
- cx.state.context = new Context(cx.state.context, cx.state.localVars, false)
- cx.state.localVars = defaultVars
- }
- function pushblockcontext() {
- cx.state.context = new Context(cx.state.context, cx.state.localVars, true)
- cx.state.localVars = null
- }
- pushcontext.lex = pushblockcontext.lex = true
- function popcontext() {
- cx.state.localVars = cx.state.context.vars
- cx.state.context = cx.state.context.prev
- }
- popcontext.lex = true
- 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 == ';' || type == '}' || type == ')' || type == ']') return pass()
- else return cont(exp)
- }
- return exp
- }
- function statement(type, value) {
- if (type == 'var') return cont(pushlex('vardef', value), 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 == 'keyword d') return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex('stat'), maybeexpression, expect(';'), poplex)
- if (type == 'debugger') return cont(expect(';'))
- if (type == '{') return cont(pushlex('}'), pushblockcontext, block, poplex, popcontext)
- 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'), pushblockcontext, forspec, statement, popcontext, poplex)
- if (type == 'class' || (isTS && value == 'interface')) {
- cx.marked = 'keyword'
- return cont(pushlex('form', type == 'class' ? type : value), className, poplex)
- }
- if (type == 'variable') {
- if (isTS && value == 'declare') {
- cx.marked = 'keyword'
- return cont(statement)
- } else if (isTS && (value == 'module' || value == 'enum' || value == 'type') && cx.stream.match(/^\s*\w/, false)) {
- cx.marked = 'keyword'
- if (value == 'enum') return cont(enumdef)
- else if (value == 'type') return cont(typename, expect('operator'), typeexpr, expect(';'))
- else return cont(pushlex('form'), pattern, expect('{'), pushlex('}'), block, poplex, poplex)
- } else if (isTS && value == 'namespace') {
- cx.marked = 'keyword'
- return cont(pushlex('form'), expression, statement, poplex)
- } else if (isTS && value == 'abstract') {
- cx.marked = 'keyword'
- return cont(statement)
- } else {
- return cont(pushlex('stat'), maybelabel)
- }
- }
- if (type == 'switch') return cont(pushlex('form'), parenExpr, expect('{'), pushlex('}', 'switch'), pushblockcontext, block, poplex, poplex, popcontext)
- if (type == 'case') return cont(expression, expect(':'))
- if (type == 'default') return cont(expect(':'))
- if (type == 'catch') return cont(pushlex('form'), pushcontext, maybeCatchBinding, statement, poplex, popcontext)
- if (type == 'export') return cont(pushlex('stat'), afterExport, poplex)
- if (type == 'import') return cont(pushlex('stat'), afterImport, poplex)
- if (type == 'async') return cont(statement)
- if (value == '@') return cont(expression, statement)
- return pass(pushlex('stat'), expression, expect(';'), poplex)
- }
- function maybeCatchBinding(type) {
- if (type == '(') return cont(funarg, expect(')'))
- }
- function expression(type, value) {
- return expressionInner(type, value, false)
- }
- function expressionNoComma(type, value) {
- return expressionInner(type, value, true)
- }
- function parenExpr(type) {
- if (type != '(') return pass()
- return cont(pushlex(')'), maybeexpression, expect(')'), poplex)
- }
- function expressionInner(type, value, noComma) {
- if (cx.state.fatArrowAt == cx.stream.start) {
- var body = noComma ? arrowBodyNoComma : arrowBody
- if (type == '(') return cont(pushcontext, pushlex(')'), commasep(funarg, ')'), 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' || (isTS && value == 'interface')) {
- cx.marked = 'keyword'
- return cont(pushlex('form'), classExpression, poplex)
- }
- if (type == 'keyword c' || type == 'async') return cont(noComma ? expressionNoComma : expression)
- 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 maybeoperatorComma(type, value) {
- if (type == ',') return cont(maybeexpression)
- 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) || (isTS && value == '!')) return cont(me)
- if (isTS && value == '<' && cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/, false)) return cont(pushlex('>'), commasep(typeexpr, '>'), poplex, 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)
- }
- if (type == 'regexp') {
- cx.state.lastType = cx.marked = 'operator'
- cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
- return cont(expr)
- }
- }
- function quasi(type, value) {
- if (type != 'quasi') return pass()
- if (value.slice(value.length - 2) != '${') return cont(quasi)
- return cont(maybeexpression, 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 if (type == 'variable' && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
- 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)
- var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
- if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false))) cx.state.fatArrowAt = cx.stream.pos + m[0].length
- 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 (isTS && isModifier(value)) {
- cx.marked = 'keyword'
- return cont(objprop)
- } else if (type == '[') {
- return cont(expression, maybetype, expect(']'), afterprop)
- } else if (type == 'spread') {
- return cont(expressionNoComma, afterprop)
- } else if (value == '*') {
- cx.marked = 'keyword'
- return cont(objprop)
- } 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()
- if (sep && sep.indexOf(';') > -1) return pass(what)
- 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 maybetypeOrIn(type, value) {
- if (isTS && (type == ':' || value == 'in')) return cont(typeexpr)
- }
- function mayberettype(type) {
- if (isTS && type == ':') {
- if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
- else return cont(typeexpr)
- }
- }
- function isKW(_, value) {
- if (value == 'is') {
- cx.marked = 'keyword'
- return cont()
- }
- }
- function typeexpr(type, value) {
- if (value == 'keyof' || value == 'typeof' || value == 'infer' || value == 'readonly') {
- cx.marked = 'keyword'
- return cont(value == 'typeof' ? expressionNoComma : typeexpr)
- }
- if (type == 'variable' || value == 'void') {
- cx.marked = 'type'
- return cont(afterType)
- }
- if (value == '|' || value == '&') return cont(typeexpr)
- if (type == 'string' || type == 'number' || type == 'atom') return cont(afterType)
- if (type == '[') return cont(pushlex(']'), commasep(typeexpr, ']', ','), poplex, afterType)
- if (type == '{') return cont(pushlex('}'), typeprops, poplex, afterType)
- if (type == '(') return cont(commasep(typearg, ')'), maybeReturnType, afterType)
- if (type == '<') return cont(commasep(typeexpr, '>'), typeexpr)
- if (type == 'quasi') {
- return pass(quasiType, afterType)
- }
- }
- function maybeReturnType(type) {
- if (type == '=>') return cont(typeexpr)
- }
- function typeprops(type) {
- if (type.match(/[\}\)\]]/)) return cont()
- if (type == ',' || type == ';') return cont(typeprops)
- return pass(typeprop, typeprops)
- }
- function typeprop(type, value) {
- if (type == 'variable' || cx.style == 'keyword') {
- cx.marked = 'property'
- return cont(typeprop)
- } else if (value == '?' || type == 'number' || type == 'string') {
- return cont(typeprop)
- } else if (type == ':') {
- return cont(typeexpr)
- } else if (type == '[') {
- return cont(expect('variable'), maybetypeOrIn, expect(']'), typeprop)
- } else if (type == '(') {
- return pass(functiondecl, typeprop)
- } else if (!type.match(/[;\}\)\],]/)) {
- return cont()
- }
- }
- function quasiType(type, value) {
- if (type != 'quasi') return pass()
- if (value.slice(value.length - 2) != '${') return cont(quasiType)
- return cont(typeexpr, continueQuasiType)
- }
- function continueQuasiType(type) {
- if (type == '}') {
- cx.marked = 'string-2'
- cx.state.tokenize = tokenQuasi
- return cont(quasiType)
- }
- }
- function typearg(type, value) {
- if ((type == 'variable' && cx.stream.match(/^\s*[?:]/, false)) || value == '?') return cont(typearg)
- if (type == ':') return cont(typeexpr)
- if (type == 'spread') return cont(typearg)
- return pass(typeexpr)
- }
- function afterType(type, value) {
- if (value == '<') return cont(pushlex('>'), commasep(typeexpr, '>'), poplex, afterType)
- if (value == '|' || type == '.' || value == '&') return cont(typeexpr)
- if (type == '[') return cont(typeexpr, expect(']'), afterType)
- if (value == 'extends' || value == 'implements') {
- cx.marked = 'keyword'
- return cont(typeexpr)
- }
- if (value == '?') return cont(typeexpr, expect(':'), typeexpr)
- }
- function maybeTypeArgs(_, value) {
- if (value == '<') return cont(pushlex('>'), commasep(typeexpr, '>'), poplex, afterType)
- }
- function typeparam() {
- return pass(typeexpr, maybeTypeDefault)
- }
- function maybeTypeDefault(_, value) {
- if (value == '=') return cont(typeexpr)
- }
- function vardef(_, value) {
- if (value == 'enum') {
- cx.marked = 'keyword'
- return cont(enumdef)
- }
- return pass(pattern, maybetype, maybeAssign, vardefCont)
- }
- function pattern(type, value) {
- if (isTS && isModifier(value)) {
- cx.marked = 'keyword'
- return cont(pattern)
- }
- if (type == 'variable') {
- register(value)
- return cont()
- }
- if (type == 'spread') return cont(pattern)
- if (type == '[') return contCommasep(eltpattern, ']')
- 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()
- if (type == '[') return cont(expression, expect(']'), expect(':'), proppattern)
- return cont(expect(':'), pattern, maybeAssign)
- }
- function eltpattern() {
- return pass(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, value) {
- if (value == 'await') return cont(forspec)
- if (type == '(') return cont(pushlex(')'), forspec1, poplex)
- }
- function forspec1(type) {
- if (type == 'var') return cont(vardef, forspec2)
- if (type == 'variable') return cont(forspec2)
- return pass(forspec2)
- }
- function forspec2(type, value) {
- if (type == ')') return cont()
- if (type == ';') return cont(forspec2)
- if (value == 'in' || value == 'of') {
- cx.marked = 'keyword'
- return cont(expression, forspec2)
- }
- return pass(expression, forspec2)
- }
- 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, mayberettype, statement, popcontext)
- if (isTS && value == '<') return cont(pushlex('>'), commasep(typeparam, '>'), poplex, functiondef)
- }
- function functiondecl(type, value) {
- if (value == '*') {
- cx.marked = 'keyword'
- return cont(functiondecl)
- }
- if (type == 'variable') {
- register(value)
- return cont(functiondecl)
- }
- if (type == '(') return cont(pushcontext, pushlex(')'), commasep(funarg, ')'), poplex, mayberettype, popcontext)
- if (isTS && value == '<') return cont(pushlex('>'), commasep(typeparam, '>'), poplex, functiondecl)
- }
- function typename(type, value) {
- if (type == 'keyword' || type == 'variable') {
- cx.marked = 'type'
- return cont(typename)
- } else if (value == '<') {
- return cont(pushlex('>'), commasep(typeparam, '>'), poplex)
- }
- }
- function funarg(type, value) {
- if (value == '@') cont(expression, funarg)
- if (type == 'spread') return cont(funarg)
- if (isTS && isModifier(value)) {
- cx.marked = 'keyword'
- return cont(funarg)
- }
- if (isTS && type == 'this') return cont(maybetype, maybeAssign)
- 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(typeparam, '>'), poplex, classNameAfter)
- if (value == 'extends' || value == 'implements' || (isTS && type == ',')) {
- if (value == 'implements') cx.marked = 'keyword'
- return cont(isTS ? typeexpr : expression, classNameAfter)
- }
- if (type == '{') return cont(pushlex('}'), classBody, poplex)
- }
- function classBody(type, value) {
- if (type == 'async' || (type == 'variable' && (value == 'static' || value == 'get' || value == 'set' || (isTS && isModifier(value))) && cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
- cx.marked = 'keyword'
- return cont(classBody)
- }
- if (type == 'variable' || cx.style == 'keyword') {
- cx.marked = 'property'
- return cont(classfield, classBody)
- }
- if (type == 'number' || type == 'string') return cont(classfield, classBody)
- if (type == '[') return cont(expression, maybetype, expect(']'), classfield, classBody)
- if (value == '*') {
- cx.marked = 'keyword'
- return cont(classBody)
- }
- if (isTS && type == '(') return pass(functiondecl, classBody)
- if (type == ';' || type == ',') return cont(classBody)
- if (type == '}') return cont()
- if (value == '@') return cont(expression, classBody)
- }
- function classfield(type, value) {
- if (value == '!') return cont(classfield)
- if (value == '?') return cont(classfield)
- if (type == ':') return cont(typeexpr, maybeAssign)
- if (value == '=') return cont(expressionNoComma)
- var context = cx.state.lexical.prev,
- isInterface = context && context.info == 'interface'
- return pass(isInterface ? functiondecl : 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()
- if (type == '(') return pass(expression)
- if (type == '.') return pass(maybeoperatorComma)
- 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 enumdef() {
- return pass(pushlex('form'), pattern, expect('{'), pushlex('}'), commasep(enummember, '}'), poplex, poplex)
- }
- function enummember() {
- return pass(pattern, maybeAssign)
- }
- function isContinuedStatement(state, textAfter) {
- return state.lastType == 'operator' || state.lastType == ',' || isOperatorChar.test(textAfter.charAt(0)) || /[,.]/.test(textAfter.charAt(0))
- }
- function expressionAllowed(stream, state, backUp) {
- return (
- (state.tokenize == tokenBase && /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType)) ||
- (state.lastType == 'quasi' && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 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 && new Context(null, null, false),
- 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 || state.tokenize == tokenQuasi) 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 && c != popcontext) 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.length + 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 : '*/',
- blockCommentContinue: jsonMode ? null : ' * ',
- lineComment: jsonMode ? null : '//',
- fold: 'brace',
- closeBrackets: '()[]{}\'\'""``',
- helperType: jsonMode ? 'json' : 'javascript',
- jsonldMode: jsonldMode,
- jsonMode: jsonMode,
- expressionAllowed: expressionAllowed,
- skipExpression: function (state) {
- parseJS(state, 'atom', 'atom', 'true', new CodeMirror.StringStream('', 2, null))
- },
- }
- })
- 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/manifest+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 })
- })
|