coffeelint-callback-handle-error
Version:
Coffeelint rule finds instances of error objects passed through a callback not being handled
94 lines (78 loc) • 2.88 kB
text/coffeescript
getNodeType = (node) ->
return node.constructor.name
module.exports = class CallbackHandleError
rule:
name: 'callback_handle_error'
level: 'error'
message: 'Error in callback not handled'
description: '''
Finds instances of error objects passed through a callback not being handled
'''
# param name config
patterns: ["^err(or)?", "[Ee]rr(or)?$"]
lintAST: (node, @astApi) ->
patterns = @astApi.config.patterns ? @rule.patterns
@errorVariablePatterns = (new RegExp(pattern) for pattern in patterns)
@lintNode node
return
lintNode: (node) ->
node_type = getNodeType(node)
switch node_type
when 'Code'
for param in node.params
var_name = param.name?.value
for pattern in @errorVariablePatterns
if pattern.test(var_name) && !@handlesError(node, var_name)
@throwError node, "Error object '#{var_name}' in callback not handled"
break
node.eachChild (child)=>
@lintNode child
return
return
handlesError: (code_node, var_name)->
found_usage = false
code_node.traverseChildren true, (child)->
node_type = getNodeType child
switch node_type
when 'If'
# check for if they use the error in an if
child.condition.traverseChildren false, (inner_child)->
inner_type = getNodeType inner_child
switch inner_type
# HACK: Handles change of token naming in CoffeeScript 1.11.0
when 'Literal', 'IdentifierLiteral'
if inner_child.value is var_name
found_usage = true
return false
return
when 'Call'
# passing the error to another call is considered using it
for arg in child.args
arg.traverseChildren false, (inner_child)->
inner_type = getNodeType inner_child
switch inner_type
# HACK: Handles change of token naming in CoffeeScript 1.11.0
when 'Literal', 'IdentifierLiteral'
if inner_child.value is var_name
found_usage = true
return false
return
return
when 'Code'
# stop going down the chain when the var gets overwritten with another param
for param in child.params
inner_child_type = getNodeType param
if inner_child_type is 'Param'
if param.name.value is var_name
return false
# if we already found a usage, break out of the traverse
if found_usage
return false
return
return found_usage
throwError: (node, message) ->
err = @astApi.createError
lineNumber: node.locationData.first_line + 1
message: message
@errors.push err
return