UNPKG

eslint-config-chain-able

Version:
140 lines (121 loc) 4.15 kB
// The algorithm used to determine whether a regexp can appear at a // given point in the program is loosely based on sweet.js' approach. // See https://github.com/mozilla/sweet.js/wiki/design import {Parser} from "./state" import {types as tt} from "./tokentype" import {lineBreak} from "./whitespace" export class TokContext { constructor(token, isExpr, preserveSpace, override, generator) { this.token = token this.isExpr = !!isExpr this.preserveSpace = !!preserveSpace this.override = override this.generator = !!generator } } export const types = { b_stat: new TokContext("{", false), b_expr: new TokContext("{", true), b_tmpl: new TokContext("${", true), p_stat: new TokContext("(", false), p_expr: new TokContext("(", true), q_tmpl: new TokContext("`", true, true, p => p.readTmplToken()), f_expr: new TokContext("function", true), f_expr_gen: new TokContext("function", true, false, null, true), f_gen: new TokContext("function", false, false, null, true) } const pp = Parser.prototype pp.initialContext = function() { return [types.b_stat] } pp.braceIsBlock = function(prevType) { if (prevType === tt.colon) { let parent = this.curContext() if (parent === types.b_stat || parent === types.b_expr) return !parent.isExpr } if (prevType === tt._return) return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType == tt.arrow) return true if (prevType == tt.braceL) return this.curContext() === types.b_stat return !this.exprAllowed } pp.inGeneratorContext = function() { for (let i = this.context.length - 1; i >= 0; i--) if (this.context[i].generator) return true return false } pp.updateContext = function(prevType) { let update, type = this.type if (type.keyword && prevType == tt.dot) this.exprAllowed = false else if (update = type.updateContext) update.call(this, prevType) else this.exprAllowed = type.beforeExpr } // Token-specific context update code tt.parenR.updateContext = tt.braceR.updateContext = function() { if (this.context.length == 1) { this.exprAllowed = true return } let out = this.context.pop(), cur if (out === types.b_stat && (cur = this.curContext()) && cur.token === "function") { this.context.pop() this.exprAllowed = false } else if (out === types.b_tmpl) { this.exprAllowed = true } else { this.exprAllowed = !out.isExpr } } tt.braceL.updateContext = function(prevType) { this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr) this.exprAllowed = true } tt.dollarBraceL.updateContext = function() { this.context.push(types.b_tmpl) this.exprAllowed = true } tt.parenL.updateContext = function(prevType) { let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while this.context.push(statementParens ? types.p_stat : types.p_expr) this.exprAllowed = true } tt.incDec.updateContext = function() { // tokExprAllowed stays unchanged } tt._function.updateContext = function(prevType) { if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else && !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat)) this.context.push(types.f_expr) this.exprAllowed = false } tt.backQuote.updateContext = function() { if (this.curContext() === types.q_tmpl) this.context.pop() else this.context.push(types.q_tmpl) this.exprAllowed = false } tt.star.updateContext = function(prevType) { if (prevType == tt._function) { if (this.curContext() === types.f_expr) this.context[this.context.length - 1] = types.f_expr_gen else this.context.push(types.f_gen) } this.exprAllowed = true } tt.name.updateContext = function(prevType) { let allowed = false if (this.options.ecmaVersion >= 6) { if (this.value == "of" && !this.exprAllowed || this.value == "yield" && this.inGeneratorContext()) allowed = true } this.exprAllowed = allowed }