coffeelint/src/coffeelint.coffee in coffeelint-0.0.5 vs coffeelint/src/coffeelint.coffee in coffeelint-0.0.6

- old
+ new

@@ -94,10 +94,14 @@ empty_constructor_needs_parens : level : IGNORE message : 'Invoking a constructor without parens and without arguments' + non_empty_constructor_needs_parens : + level : IGNORE + message : 'Invoking a constructor without parens and with arguments' + no_empty_param_list : level : IGNORE message : 'Empty parameter list is forbidden' space_operators : @@ -119,10 +123,14 @@ no_stand_alone_at : level : IGNORE message : '@ must not be used stand alone' + arrow_spacing : + level : IGNORE + message : 'Function arrow (->) must be spaced properly' + coffeescript_error : level : ERROR message : '' # The default coffeescript error is fine. @@ -400,19 +408,23 @@ # Return an error if the given token fails a lint check, false # otherwise. lintToken : (token) -> [type, value, lineNumber] = token - lineNumber = lineNumber.first_line if lineNumber?.first_line? + if typeof lineNumber == "object" + if type == 'OUTDENT' or type == 'INDENT' + lineNumber = lineNumber.last_line + else + lineNumber = lineNumber.first_line @tokensByLine[lineNumber] ?= [] @tokensByLine[lineNumber].push(token) # CoffeeScript loses line numbers of interpolations and multi-line # regexes, so fake it by using the last line number we know. @lineNumber = lineNumber or @lineNumber or 0 - # Now lint it. switch type + when "->" then @lintArrowSpacing(token) when "INDENT" then @lintIndentation(token) when "CLASS" then @lintClass(token) when "UNARY" then @lintUnary(token) when "{","}" then @lintBrace(token) when "IDENTIFIER" then @lintIdentifier(token) @@ -428,18 +440,22 @@ when "=", "MATH", "COMPARE", "LOGIC" @lintMath(token) else null lintUnary: (token) -> - if token[1] is 'new' - expectedIdentifier = @peek(1) - # The callStart is generated if your parameters are on the next line - # but is missing if there are no params and no parens. - expectedCallStart = @peek(2) - if expectedIdentifier?[0] is 'IDENTIFIER' and - expectedCallStart?[0] isnt 'CALL_START' - @createLexError('empty_constructor_needs_parens') + if token[1] is 'new' + expectedIdentifier = @peek(1) + # The callStart is generated if your parameters are all on the same + # line with implicit parens, and if your parameters start on the + # next line, but is missing if there are no params and no parens. + expectedCallStart = @peek(2) + if expectedIdentifier?[0] is 'IDENTIFIER' and expectedCallStart? + if expectedCallStart[0] is 'CALL_START' + if expectedCallStart.generated + @createLexError('non_empty_constructor_needs_parens') + else + @createLexError('empty_constructor_needs_parens') # Lint the given array token. lintArray : (token) -> # Track the array token pairs if token[0] == '[' @@ -671,10 +687,31 @@ attrs = {context: "class name: #{className}"} @createLexError('camel_case_classes', attrs) else null + lintArrowSpacing : (token) -> + # Throw error unless the following happens. + + # We will take a look at the previous token to see + # 1. That the token is properly spaced + # 2. Wasn't generated by the CoffeeScript compiler + # 3. That it is just indentation + # 4. If the function declaration has no parameters + # e.g. x(-> 3) + # x( -> 3) + # we will accept either having a space or not having a space there. + unless (token.spaced? or token.newLine?) and + # Throw error unless the previous token... + (@peek(-1).spaced? or #1 + @peek(-1).generated? or #2 + @peek(-1)[0] is "INDENT" or #3 + (@peek(-1)[0] is "CALL_START" and not @peek(-1).generated?)) #4 + @createLexError('arrow_spacing') + else + null + createLexError : (rule, attrs = {}) -> attrs.lineNumber = @lineNumber + 1 attrs.level = @config[rule].level attrs.line = @lines[@lineNumber] createError(rule, attrs) @@ -766,11 +803,14 @@ message = coffeeError.toString() # Parse the line number lineNumber = -1 - match = /line (\d+)/.exec message - lineNumber = parseInt match[1], 10 if match?.length > 1 + if coffeeError.location? + lineNumber = coffeeError.location.first_line + 1 + else + match = /line (\d+)/.exec message + lineNumber = parseInt match[1], 10 if match?.length > 1 attrs = { message: message level: rule.level lineNumber: lineNumber }