coffeelint
Version:
Lint your CoffeeScript
94 lines (78 loc) • 3.21 kB
text/coffeescript
module.exports = class SpaceOperators
rule:
name: 'space_operators'
level : 'ignore'
message : 'Operators must be spaced properly'
description: "This rule enforces that operators have space around them."
tokens: [ "+", "-", "=", "MATH", "COMPARE", "LOGIC", "COMPOUND_ASSIGN",
"(", ")", "CALL_START", "CALL_END" ]
constructor: ->
@callTokens = [] # A stack tracking the call token pairs.
@parenTokens = [] # A stack tracking the parens token pairs.
lintToken : ([type], tokenApi) ->
# These just keep track of state
if type in [ "CALL_START", "CALL_END" ]
@lintCall arguments...
return undefined
if type in [ "(", ")" ]
@lintParens arguments...
return undefined
# These may return errors
if type in [ "+", "-" ]
@lintPlus arguments...
else
@lintMath arguments...
lintPlus: (token, tokenApi) ->
# We can't check this inside of interpolations right now, because the
# plusses used for the string type co-ercion are marked not spaced.
if @isInInterpolation() or @isInExtendedRegex()
return null
p = tokenApi.peek(-1)
unaries = ['TERMINATOR', '(', '=', '-', '+', ',', 'CALL_START',
'INDEX_START', '..', '...', 'COMPARE', 'IF',
'THROW', 'LOGIC', 'POST_IF', ':', '[', 'INDENT',
'COMPOUND_ASSIGN', 'RETURN', 'MATH', 'BY', 'LEADING_WHEN']
isUnary = if not p then false else p[0] in unaries
if (isUnary and token.spaced) or
(not isUnary and not token.spaced and not token.newLine)
return {context: token[1]}
else
null
lintMath: (token, tokenApi) ->
if not token.spaced and not token.newLine
return {context: token[1]}
else
null
isInExtendedRegex : () ->
for t in @callTokens
return true if t.isRegex
return false
lintCall : (token, tokenApi) ->
if token[0] == 'CALL_START'
p = tokenApi.peek(-1)
# Track regex calls, to know (approximately) if we're in an
# extended regex.
token.isRegex = p and p[0] == 'IDENTIFIER' and p[1] == 'RegExp'
@callTokens.push(token)
else
@callTokens.pop()
return null
isInInterpolation : () ->
for t in @parenTokens
return true if t.isInterpolation
return false
lintParens : (token, tokenApi) ->
if token[0] == '('
p1 = tokenApi.peek(-1)
n1 = tokenApi.peek(1)
n2 = tokenApi.peek(2)
# String interpolations start with '' + so start the type co-ercion,
# so track if we're inside of one. This is most definitely not
# 100% true but what else can we do?
i = n1 and n2 and n1[0] == 'STRING' and n2[0] == '+'
token.isInterpolation = i
@parenTokens.push(token)
else
@parenTokens.pop()
# We're not linting, just tracking interpolations.
null