coffeelint/lib/coffeelint.js in coffeelint-1.11.0 vs coffeelint/lib/coffeelint.js in coffeelint-1.14.0

- old
+ new

@@ -80,11 +80,11 @@ mergeDefaultConfig = function(userConfig) { var config, rule, ruleConfig, ruleLoader; try { ruleLoader = nodeRequire('./ruleLoader'); ruleLoader.loadFromConfig(coffeelint, userConfig); - } catch (_error) {} + } catch (undefined) {} config = {}; if (userConfig.coffeelint) { config.coffeelint = userConfig.coffeelint; } for (rule in RULES) { @@ -139,12 +139,12 @@ }; coffeelint.invertLiterate = function(source) { var len, line, n, newSource, ref; source = CoffeeScript.helpers.invertLiterate(source); - newSource = ""; - ref = source.split("\n"); + newSource = ''; + ref = source.split('\n'); for (n = 0, len = ref.length; n < len; n++) { line = ref[n]; if (line.match(/^#/)) { line = line.replace(/\s*$/, ''); } @@ -160,38 +160,38 @@ var e, name, p, ref, ref1; if (ruleName == null) { ruleName = void 0; } p = new RuleConstructor; - name = (p != null ? (ref = p.rule) != null ? ref.name : void 0 : void 0) || "(unknown)"; + name = (p != null ? (ref = p.rule) != null ? ref.name : void 0 : void 0) || '(unknown)'; e = function(msg) { throw new Error("Invalid rule: " + name + " " + msg); }; if (p.rule == null) { - e("Rules must provide rule attribute with a default configuration."); + e('Rules must provide rule attribute with a default configuration.'); } if (p.rule.name == null) { - e("Rule defaults require a name"); + e('Rule defaults require a name'); } if ((ruleName != null) && ruleName !== p.rule.name) { e("Mismatched rule name: " + ruleName); } if (p.rule.message == null) { - e("Rule defaults require a message"); + e('Rule defaults require a message'); } if (p.rule.description == null) { - e("Rule defaults require a description"); + e('Rule defaults require a description'); } if ((ref1 = p.rule.level) !== 'ignore' && ref1 !== 'warn' && ref1 !== 'error') { e("Default level must be 'ignore', 'warn', or 'error'"); } if (typeof p.lintToken === 'function') { if (!p.tokens) { e("'tokens' is required for 'lintToken'"); } } else if (typeof p.lintLine !== 'function' && typeof p.lintAST !== 'function') { - e("Rules must implement lintToken, lintLine, or lintAST"); + e('Rules must implement lintToken, lintLine, or lintAST'); } RULES[p.rule.name] = p.rule; return _rules[p.rule.name] = RuleConstructor; }; @@ -282,11 +282,11 @@ hasSyntaxError = function(source) { try { CoffeeScript.tokens(source); return false; - } catch (_error) {} + } catch (undefined) {} return true; }; ErrorReport = require('./error_report.coffee'); @@ -312,21 +312,21 @@ config = mergeDefaultConfig(userConfig); if (literate) { source = this.invertLiterate(source); } if ((userConfig != null ? (ref = userConfig.coffeelint) != null ? ref.transforms : void 0 : void 0) != null) { - sourceLength = source.split("\n").length; + sourceLength = source.split('\n').length; ref2 = userConfig != null ? (ref1 = userConfig.coffeelint) != null ? ref1.transforms : void 0 : void 0; for (n = 0, len = ref2.length; n < len; n++) { m = ref2[n]; try { ruleLoader = nodeRequire('./ruleLoader'); transform = ruleLoader.require(m); source = transform(source); - } catch (_error) {} + } catch (undefined) {} } - if (sourceLength !== source.split("\n").length && config.transform_messes_up_line_numbers.level !== 'ignore') { + if (sourceLength !== source.split('\n').length && config.transform_messes_up_line_numbers.level !== 'ignore') { errors.push(extend({ lineNumber: 1, context: "File was transformed from " + sourceLength + " lines to " + (source.split("\n").length) + " lines" }, config.transform_messes_up_line_numbers)); } @@ -427,11 +427,11 @@ },{"./../package.json":2,"./ast_linter.coffee":3,"./error_report.coffee":5,"./lexical_linter.coffee":6,"./line_linter.coffee":7,"./rules.coffee":8,"./rules/arrow_spacing.coffee":9,"./rules/braces_spacing.coffee":10,"./rules/camel_case_classes.coffee":11,"./rules/colon_assignment_spacing.coffee":12,"./rules/cyclomatic_complexity.coffee":13,"./rules/duplicate_key.coffee":14,"./rules/empty_constructor_needs_parens.coffee":15,"./rules/ensure_comprehensions.coffee":16,"./rules/eol_last.coffee":17,"./rules/indentation.coffee":18,"./rules/line_endings.coffee":19,"./rules/max_line_length.coffee":20,"./rules/missing_fat_arrows.coffee":21,"./rules/newlines_after_classes.coffee":22,"./rules/no_backticks.coffee":23,"./rules/no_debugger.coffee":24,"./rules/no_empty_functions.coffee":25,"./rules/no_empty_param_list.coffee":26,"./rules/no_implicit_braces.coffee":27,"./rules/no_implicit_parens.coffee":28,"./rules/no_interpolation_in_single_quotes.coffee":29,"./rules/no_nested_string_interpolation.coffee":30,"./rules/no_plusplus.coffee":31,"./rules/no_private_function_fat_arrows.coffee":32,"./rules/no_stand_alone_at.coffee":33,"./rules/no_tabs.coffee":34,"./rules/no_this.coffee":35,"./rules/no_throwing_strings.coffee":36,"./rules/no_trailing_semicolons.coffee":37,"./rules/no_trailing_whitespace.coffee":38,"./rules/no_unnecessary_double_quotes.coffee":39,"./rules/no_unnecessary_fat_arrows.coffee":40,"./rules/non_empty_constructor_needs_parens.coffee":41,"./rules/prefer_english_operator.coffee":42,"./rules/space_operators.coffee":43,"./rules/spacing_after_comma.coffee":44,"./rules/transform_messes_up_line_numbers.coffee":45}],2:[function(require,module,exports){ module.exports={ "name": "coffeelint", "description": "Lint your CoffeeScript", - "version": "1.11.0", + "version": "1.14.0", "homepage": "http://www.coffeelint.org", "keywords": [ "lint", "coffeescript", "coffee-script" @@ -468,10 +468,11 @@ "pretest": "cake compile", "test": "./vowsrunner.js --spec test/*.coffee test/*.litcoffee", "testrule": "npm run compile && ./vowsrunner.js --spec", "posttest": "npm run lint", "prepublish": "cake prepublish", + "postpublish": "cake postpublish", "publish": "cake publish", "install": "cake install", "lint": "cake compile && ./bin/coffeelint .", "lint-csv": "cake compile && ./bin/coffeelint --csv .", "lint-jslint": "cake compile && ./bin/coffeelint --jslint .", @@ -543,16 +544,16 @@ ASTLinter.prototype.acceptRule = function(rule) { return typeof rule.lintAST === 'function'; }; ASTLinter.prototype.lint = function() { - var coffeeError, err, errors, j, len, ref, rule, v; + var coffeeError, err, error, errors, j, len, ref, rule, v; errors = []; try { this.node = this.CoffeeScript.nodes(this.source); - } catch (_error) { - coffeeError = _error; + } catch (error) { + coffeeError = error; err = this._parseCoffeeScriptError(coffeeError); if (err != null) { errors.push(err); } return errors; @@ -644,22 +645,22 @@ if (attrs.level == null) { attrs.level = this.config[ruleName].level; } level = attrs.level; if (level !== 'ignore' && level !== 'warn' && level !== 'error') { - throw new Error("unknown level " + level); + throw new Error("unknown level " + level + " for rule: " + ruleName); } if (level === 'error' || level === 'warn') { attrs.rule = ruleName; return defaults(attrs, this.config[ruleName]); } else { return null; } }; BaseLinter.prototype.acceptRule = function(rule) { - throw new Error("acceptRule needs to be overridden in the subclass"); + throw new Error('acceptRule needs to be overridden in the subclass'); }; BaseLinter.prototype.setupRules = function(rules) { var RuleConstructor, level, name, results, rule; this.rules = []; @@ -673,11 +674,11 @@ results.push(this.rules.push(rule)); } else { results.push(void 0); } } else if (level !== 'ignore') { - throw new Error("unknown level " + level); + throw new Error("unknown level " + level + " for rule: " + rule); } else { results.push(void 0); } } return results; @@ -849,30 +850,23 @@ } return errors; }; LexicalLinter.prototype.lintToken = function(token) { - var base, errors, j, len, lineNumber, ref, ref1, rule, type, v, value; - type = token[0], value = token[1], lineNumber = token[2]; - if (typeof lineNumber === "object") { - if (type === 'OUTDENT' || type === 'INDENT') { - lineNumber = lineNumber.last_line; - } else { - lineNumber = lineNumber.first_line; - } - } + var base, errors, j, len, lineNumber, ref, ref1, ref2, rule, type, v, value; + type = token[0], value = token[1], (ref = token[2], lineNumber = ref.first_line); if ((base = this.tokensByLine)[lineNumber] == null) { base[lineNumber] = []; } this.tokensByLine[lineNumber].push(token); this.lineNumber = lineNumber || this.lineNumber || 0; this.tokenApi.lineNumber = this.lineNumber; errors = []; - ref = this.rules; - for (j = 0, len = ref.length; j < len; j++) { - rule = ref[j]; - if (!(ref1 = token[0], indexOf.call(rule.tokens, ref1) >= 0)) { + ref1 = this.rules; + for (j = 0, len = ref1.length; j < len; j++) { + rule = ref1[j]; + if (!(ref2 = token[0], indexOf.call(rule.tokens, ref2) >= 0)) { continue; } v = this.normalizeResult(rule, rule.lintToken(token, this.tokenApi)); if (v != null) { errors.push(v); @@ -883,12 +877,15 @@ LexicalLinter.prototype.createError = function(ruleName, attrs) { if (attrs == null) { attrs = {}; } - attrs.lineNumber = this.lineNumber + 1; - attrs.line = this.tokenApi.lines[this.lineNumber]; + if (attrs.lineNumber == null) { + attrs.lineNumber = this.lineNumber; + } + attrs.lineNumber += 1; + attrs.line = this.tokenApi.lines[attrs.lineNumber - 1]; return LexicalLinter.__super__.createError.call(this, ruleName, attrs); }; return LexicalLinter; @@ -933,11 +930,11 @@ if (this.context["class"].classIndents === 0) { this.context["class"].inClass = false; this.context["class"].classIndents = null; } } - if (this.context["class"].inClass && !line.match(/^\s*$/)) { + if (!line.match(/^\s*$/)) { this.context["class"].lastUnemptyLineInClass = this.lineNumber; } } else { if (!line.match(/\\s*/)) { this.context["class"].lastUnemptyLineInClass = null; @@ -1019,10 +1016,11 @@ errors = []; ref = this.lineApi.lines; for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) { line = ref[lineNumber]; this.lineApi.lineNumber = this.lineNumber = lineNumber; + this.lineApi.line = this.lineApi.lines[lineNumber]; this.lineApi.maintainClassContext(line); this.collectInlineConfig(line); ref1 = this.lintLine(line); for (j = 0, len1 = ref1.length; j < len1; j++) { error = ref1[j]; @@ -1054,11 +1052,11 @@ rules = []; if (result[2] != null) { ref = result[2].split(','); for (i = 0, len = ref.length; i < len; i++) { r = ref[i]; - rules.push(r.replace(/^\s+|\s+$/g, "")); + rules.push(r.replace(/^\s+|\s+$/g, '')); } } this.block_config[cmd][this.lineNumber] = rules; } return null; @@ -1106,43 +1104,30 @@ ArrowSpacing.prototype.rule = { name: 'arrow_spacing', level: 'ignore', message: 'Function arrows (-> and =>) must be spaced properly', - description: "<p>This rule checks to see that there is spacing before and after\nthe arrow operator that declares a function. This rule is disabled\nby default.</p> <p>Note that if arrow_spacing is enabled, and you\npass an empty function as a parameter, arrow_spacing will accept\neither a space or no space in-between the arrow operator and the\nparenthesis</p>\n<pre><code># Both of this will not trigger an error,\n# even with arrow_spacing enabled.\nx(-> 3)\nx( -> 3)\n\n# However, this will trigger an error\nx((a,b)-> 3)\n</code>\n</pre>" + description: '<p>This rule checks to see that there is spacing before and after\nthe arrow operator that declares a function. This rule is disabled\nby default.</p> <p>Note that if arrow_spacing is enabled, and you\npass an empty function as a parameter, arrow_spacing will accept\neither a space or no space in-between the arrow operator and the\nparenthesis</p>\n<pre><code># Both of this will not trigger an error,\n# even with arrow_spacing enabled.\nx(-> 3)\nx( -> 3)\n\n# However, this will trigger an error\nx((a,b)-> 3)\n</code>\n</pre>' }; ArrowSpacing.prototype.tokens = ['->', '=>']; ArrowSpacing.prototype.lintToken = function(token, tokenApi) { var pp; pp = tokenApi.peek(-1); if (!pp) { return; } - if (!token.spaced && (pp[1] === "(" && (pp.generated == null)) && tokenApi.peek(1)[0] === 'INDENT' && tokenApi.peek(2)[0] === 'OUTDENT') { + if (!token.spaced && tokenApi.peek(1)[0] === 'INDENT' && tokenApi.peek(2)[0] === 'OUTDENT') { return null; - } else if (!(((token.spaced != null) || (token.newLine != null) || this.atEof(tokenApi)) && (((pp.spaced != null) || pp[0] === 'TERMINATOR') || (pp.generated != null) || pp[0] === "INDENT" || (pp[1] === "(" && (pp.generated == null))))) { + } else if (!(((token.spaced != null) || (token.newLine != null)) && (((pp.spaced != null) || pp[0] === 'TERMINATOR') || (pp.generated != null) || pp[0] === 'INDENT' || (pp[1] === '(' && (pp.generated == null))))) { return true; } else { return null; } }; - ArrowSpacing.prototype.atEof = function(tokenApi) { - var i, j, len, ref, ref1, token, tokens; - tokens = tokenApi.tokens, i = tokenApi.i; - ref = tokens.slice(i + 1); - for (j = 0, len = ref.length; j < len; j++) { - token = ref[j]; - if (!(token.generated || ((ref1 = token[0]) === 'OUTDENT' || ref1 === 'TERMINATOR'))) { - return false; - } - } - return true; - }; - return ArrowSpacing; })(); @@ -1172,11 +1157,11 @@ var nearestToken, totalDifference; totalDifference = 0; while (true) { totalDifference += difference; nearestToken = tokenApi.peek(totalDifference); - if (nearestToken[0] === 'OUTDENT') { + if (nearestToken[0] === 'OUTDENT' || (nearestToken.generated != null)) { continue; } return nearestToken; } }; @@ -1238,11 +1223,11 @@ CamelCaseClasses.prototype.rule = { name: 'camel_case_classes', level: 'error', message: 'Class name should be UpperCamelCased', - description: "This rule mandates that all class names are UpperCamelCased.\nCamel casing class names is a generally accepted way of\ndistinguishing constructor functions - which require the 'new'\nprefix to behave properly - from plain old functions.\n<pre>\n<code># Good!\nclass BoaConstrictor\n\n# Bad!\nclass boaConstrictor\n</code>\n</pre>\nThis rule is enabled by default." + description: 'This rule mandates that all class names are UpperCamelCased.\nCamel casing class names is a generally accepted way of\ndistinguishing constructor functions - which require the \'new\'\nprefix to behave properly - from plain old functions.\n<pre>\n<code># Good!\nclass BoaConstrictor\n\n# Bad!\nclass boaConstrictor\n</code>\n</pre>\nThis rule is enabled by default.' }; CamelCaseClasses.prototype.tokens = ['CLASS']; CamelCaseClasses.prototype.lintToken = function(token, tokenApi) { @@ -1286,11 +1271,11 @@ message: 'Colon assignment without proper spacing', spacing: { left: 0, right: 0 }, - description: "<p>This rule checks to see that there is spacing before and\nafter the colon in a colon assignment (i.e., classes, objects).\nThe spacing amount is specified by\nspacing.left and spacing.right, respectively.\nA zero value means no spacing required.\n</p>\n<pre><code>\n#\n# If spacing.left and spacing.right is 1\n#\n\n# Good\nobject = {spacing : true}\nclass Dog\n canBark : true\n\n# Bad\nobject = {spacing: true}\nclass Cat\n canBark: false\n</code></pre>" + description: '<p>This rule checks to see that there is spacing before and\nafter the colon in a colon assignment (i.e., classes, objects).\nThe spacing amount is specified by\nspacing.left and spacing.right, respectively.\nA zero value means no spacing required.\n</p>\n<pre><code>\n#\n# If spacing.left and spacing.right is 1\n#\n\n# Doesn\'t throw an error\nobject = {spacing : true}\nclass Dog\n canBark : true\n\n# Throws an error\nobject = {spacing: true}\nclass Cat\n canBark: false\n</code></pre>' }; ColonAssignmentSpacing.prototype.tokens = [':']; ColonAssignmentSpacing.prototype.lintToken = function(token, tokenApi) { @@ -1316,11 +1301,11 @@ ref1 = checkSpacing('right'), isRightSpaced = ref1[0], rightSpacing = ref1[1]; if (isLeftSpaced && isRightSpaced) { return null; } else { return { - context: "Incorrect spacing around column " + token[2].first_column + ".\nExpected left: " + spaceRules.left + ", right: " + spaceRules.right + ".\nGot left: " + leftSpacing + ", right: " + rightSpacing + "." + context: "Incorrect spacing around column " + token[2].first_column }; } }; return ColonAssignmentSpacing; @@ -1335,14 +1320,14 @@ module.exports = CyclomaticComplexity = (function() { function CyclomaticComplexity() {} CyclomaticComplexity.prototype.rule = { name: 'cyclomatic_complexity', - value: 10, level: 'ignore', message: 'The cyclomatic complexity is too damn high', - description: 'Examine the complexity of your application.' + value: 10, + description: 'Examine the complexity of your function.' }; CyclomaticComplexity.prototype.getComplexity = function(node) { var complexity, name, ref; name = this.astApi.getNodeName(node); @@ -1354,28 +1339,28 @@ this.astApi = astApi; this.lintNode(node); return void 0; }; - CyclomaticComplexity.prototype.lintNode = function(node, line) { + CyclomaticComplexity.prototype.lintNode = function(node) { var complexity, error, name, ref, rule; name = (ref = this.astApi) != null ? ref.getNodeName(node) : void 0; complexity = this.getComplexity(node); node.eachChild((function(_this) { return function(childNode) { - var nodeLine; - nodeLine = childNode.locationData.first_line; - if (childNode) { - return complexity += _this.lintNode(childNode, nodeLine); + var childComplexity, ref1; + childComplexity = _this.lintNode(childNode); + if (((ref1 = _this.astApi) != null ? ref1.getNodeName(childNode) : void 0) !== 'Code') { + return complexity += childComplexity; } }; })(this)); rule = this.astApi.config[this.rule.name]; if (name === 'Code' && complexity >= rule.value) { error = this.astApi.createError({ context: complexity + 1, - lineNumber: line + 1, + lineNumber: node.locationData.first_line + 1, lineNumberEnd: node.locationData.last_line + 1 }); if (error) { this.errors.push(error); } @@ -1395,11 +1380,11 @@ module.exports = DuplicateKey = (function() { DuplicateKey.prototype.rule = { name: 'duplicate_key', level: 'error', message: 'Duplicate key defined in object or class', - description: "Prevents defining duplicate keys in object literals and classes" + description: 'Prevents defining duplicate keys in object literals and classes' }; DuplicateKey.prototype.tokens = ['IDENTIFIER', '{', '}']; function DuplicateKey() { @@ -1467,11 +1452,11 @@ EmptyConstructorNeedsParens.prototype.rule = { name: 'empty_constructor_needs_parens', level: 'ignore', message: 'Invoking a constructor without parens and without arguments', - description: "Requires constructors with no parameters to include the parens" + description: 'Requires constructors with no parameters to include the parens' }; EmptyConstructorNeedsParens.prototype.tokens = ['UNARY']; EmptyConstructorNeedsParens.prototype.lintToken = function(token, tokenApi) { @@ -1531,44 +1516,52 @@ EnsureComprehensions.prototype.tokens = ['FOR']; EnsureComprehensions.prototype.forBlock = false; EnsureComprehensions.prototype.lintToken = function(token, tokenApi) { - var atEqual, idents, numCallEnds, numCallStarts, peeker, prevIdents, prevToken, ref, ref1; + var atEqual, idents, numCallEnds, numCallStarts, numParenEnds, numParenStarts, peeker, prevIdents, prevToken, ref, ref1; idents = this.findIdents(tokenApi); if (this.forBlock) { this.forBlock = false; return; } peeker = -1; atEqual = false; numCallEnds = 0; numCallStarts = 0; + numParenStarts = 0; + numParenEnds = 0; prevIdents = []; while ((prevToken = tokenApi.peek(peeker))) { if (prevToken[0] === 'CALL_END') { numCallEnds++; } if (prevToken[0] === 'CALL_START') { numCallStarts++; } + if (prevToken[0] === '(') { + numParenStarts++; + } + if (prevToken[0] === ')') { + numParenEnds++; + } if (prevToken[0] === 'IDENTIFIER') { if (!atEqual) { prevIdents.push(prevToken[1]); } else if (ref = prevToken[1], indexOf.call(idents, ref) >= 0) { return; } } if (((ref1 = prevToken[0]) === '(' || ref1 === '->' || ref1 === 'TERMINATOR') || (prevToken.newLine != null)) { break; } - if (prevToken[0] === '=') { + if (prevToken[0] === '=' && numParenEnds === numParenStarts) { atEqual = true; } peeker--; } - if (atEqual && prevIdents.length > 0 && numCallStarts === numCallEnds) { + if (atEqual && numCallStarts === numCallEnds) { return { context: '' }; } }; @@ -1613,18 +1606,21 @@ EOLLast.prototype.rule = { name: 'eol_last', level: 'ignore', message: 'File does not end with a single newline', - description: "Checks that the file ends with a single newline" + description: 'Checks that the file ends with a single newline' }; EOLLast.prototype.lintLine = function(line, lineApi) { + var isNewline, previousIsNewline; if (!lineApi.isLastLine()) { return null; } - if (line.length) { + isNewline = line.length === 0; + previousIsNewline = lineApi.lineCount > 1 ? lineApi.lines[lineApi.lineNumber - 1].length === 0 : false; + if (!(isNewline && !previousIsNewline)) { return true; } }; return EOLLast; @@ -1632,57 +1628,58 @@ })(); },{}],18:[function(require,module,exports){ -var Indentation; +var Indentation, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; module.exports = Indentation = (function() { Indentation.prototype.rule = { name: 'indentation', value: 2, level: 'error', message: 'Line contains inconsistent indentation', - description: "This rule imposes a standard number of spaces to be used for\nindentation. Since whitespace is significant in CoffeeScript, it's\ncritical that a project chooses a standard indentation format and\nstays consistent. Other roads lead to darkness. <pre> <code>#\nEnabling this option will prevent this ugly\n# but otherwise valid CoffeeScript.\ntwoSpaces = () ->\n fourSpaces = () ->\n eightSpaces = () ->\n 'this is valid CoffeeScript'\n\n</code>\n</pre>\nTwo space indentation is enabled by default." + description: 'This rule imposes a standard number of spaces to be used for\nindentation. Since whitespace is significant in CoffeeScript, it\'s\ncritical that a project chooses a standard indentation format and\nstays consistent. Other roads lead to darkness. <pre> <code>#\nEnabling this option will prevent this ugly\n# but otherwise valid CoffeeScript.\ntwoSpaces = () ->\n fourSpaces = () ->\n eightSpaces = () ->\n \'this is valid CoffeeScript\'\n\n</code>\n</pre>\nTwo space indentation is enabled by default.' }; Indentation.prototype.tokens = ['INDENT', '[', ']', '.']; + Indentation.prototype.keywords = ['->', '=>', '@', 'CATCH', 'CLASS', 'ELSE', 'FINALLY', 'FOR', 'FORIN', 'FOROF', 'IDENTIFIER', 'IF', 'LEADING_WHEN', 'LOOP', 'RETURN', 'SWITCH', 'THROW', 'TRY', 'UNTIL', 'WHEN', 'WHILE', 'YIELD']; + function Indentation() { this.arrayTokens = []; } Indentation.prototype.lintToken = function(token, tokenApi) { - var currentLine, expected, ignoreIndent, isArrayIndent, isInterpIndent, isMultiline, lineNumber, lines, numIndents, previous, previousSymbol, ref, ref1, ref2, type; + var currentLine, expected, ignoreIndent, isArrayIndent, isMultiline, lineNumber, lines, numIndents, previous, previousSymbol, ref, ref1, ref2, type; type = token[0], numIndents = token[1], (ref = token[2], lineNumber = ref.first_line); lines = tokenApi.lines, lineNumber = tokenApi.lineNumber; expected = tokenApi.config[this.rule.name].value; if (type === '.') { currentLine = lines[lineNumber]; - if (((ref1 = currentLine.match(/\S/i)) != null ? ref1[0] : void 0) === '.') { + if (((ref1 = currentLine.match(/\S/)) != null ? ref1[0] : void 0) === '.') { return this.handleChain(tokenApi, expected); } return void 0; } if (type === '[' || type === ']') { this.lintArray(token); return void 0; } - if (token.generated != null) { + if ((token.generated != null) || (token.explicit != null)) { return null; } - previous = tokenApi.peek(-2); - isInterpIndent = previous && previous[0] === '+'; previous = tokenApi.peek(-1); isArrayIndent = this.inArray() && (previous != null ? previous.newLine : void 0); previousSymbol = (ref2 = tokenApi.peek(-1)) != null ? ref2[0] : void 0; isMultiline = previousSymbol === '=' || previousSymbol === ','; - ignoreIndent = isInterpIndent || isArrayIndent || isMultiline; + ignoreIndent = isArrayIndent || isMultiline; numIndents = this.getCorrectIndent(tokenApi); - if (!ignoreIndent && numIndents !== expected) { + if (!ignoreIndent && !(indexOf.call(numIndents, expected) >= 0)) { return { - context: "Expected " + expected + " got " + numIndents + context: "Expected " + expected + " got " + numIndents[0] }; } }; Indentation.prototype.inArray = function() { @@ -1715,13 +1712,13 @@ prevNum += 1; } checkNum = lineNumber - prevNum; if (checkNum >= 0) { prevLine = lines[checkNum]; - if (prevLine.match(/\S/i)[0] === '.' || checkNum === lastCheck) { - currentSpaces = (ref = currentLine.match(/\S/i)) != null ? ref.index : void 0; - prevSpaces = (ref1 = prevLine.match(/\S/i)) != null ? ref1.index : void 0; + if (prevLine.match(/\S/)[0] === '.' || checkNum === lastCheck) { + currentSpaces = (ref = currentLine.match(/\S/)) != null ? ref.index : void 0; + prevSpaces = (ref1 = prevLine.match(/\S/)) != null ? ref1.index : void 0; numIndents = currentSpaces - prevSpaces; prevIsIndent = prevSpaces % expected !== 0; currIsIndent = currentSpaces % expected !== 0; if (prevIsIndent && currIsIndent) { numIndents = currentSpaces; @@ -1733,25 +1730,85 @@ } } } }; + Indentation.prototype.grabLineTokens = function(tokenApi, lineNumber, all) { + var i, k, len, len1, ref, ref1, results, results1, tok, tokensByLine; + if (all == null) { + all = false; + } + tokensByLine = tokenApi.tokensByLine; + while (!((tokensByLine[lineNumber] != null) || lineNumber === 0)) { + lineNumber--; + } + if (all) { + ref = tokensByLine[lineNumber]; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + tok = ref[i]; + results.push(tok); + } + return results; + } else { + ref1 = tokensByLine[lineNumber]; + results1 = []; + for (k = 0, len1 = ref1.length; k < len1; k++) { + tok = ref1[k]; + if ((tok.generated == null) && tok[0] !== 'OUTDENT') { + results1.push(tok); + } + } + return results1; + } + }; + Indentation.prototype.getCorrectIndent = function(tokenApi) { - var curIndent, i, lineNumber, lines, prevIndent, prevLine, prevNum, ref, ref1, ref2, tokens; - lineNumber = tokenApi.lineNumber, lines = tokenApi.lines, tokens = tokenApi.tokens, i = tokenApi.i; + var _, curIndent, i, j, len, lineNumber, lines, prevIndent, prevNum, prevTokens, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ret, skipAssign, t, tokens, tryLine; + lineNumber = tokenApi.lineNumber, lines = tokenApi.lines, tokens = tokenApi.tokens; curIndent = (ref = lines[lineNumber].match(/\S/)) != null ? ref.index : void 0; prevNum = 1; while (/^\s*(#|$)/.test(lines[lineNumber - prevNum])) { prevNum += 1; } - prevLine = lines[lineNumber - prevNum]; - prevIndent = (ref1 = prevLine.match(/^(\s*)\./)) != null ? ref1[1].length : void 0; - if (prevIndent > 0) { - return curIndent - ((ref2 = prevLine.match(/\S/)) != null ? ref2.index : void 0); + prevTokens = this.grabLineTokens(tokenApi, lineNumber - prevNum); + if (((ref1 = prevTokens[0]) != null ? ref1[0] : void 0) === 'INDENT') { + return [curIndent - ((ref2 = prevTokens[1]) != null ? ref2[2].first_column : void 0), curIndent - prevTokens[0][1]]; } else { - return tokens[i][1]; + prevIndent = (ref3 = prevTokens[0]) != null ? ref3[2].first_column : void 0; + for (j = i = 0, len = prevTokens.length; i < len; j = ++i) { + _ = prevTokens[j]; + if (!(prevTokens[j][0] === '=' && ((ref4 = prevTokens[j + 1]) != null ? ref4[0] : void 0) === 'IF')) { + continue; + } + skipAssign = curIndent - prevTokens[j + 1][2].first_column; + ret = curIndent - prevIndent; + if (skipAssign < 0) { + return [ret]; + } + return [skipAssign, ret]; + } + while (prevIndent > curIndent) { + tryLine = lineNumber - prevNum; + prevTokens = this.grabLineTokens(tokenApi, tryLine, true); + if (((ref5 = prevTokens[0]) != null ? ref5[0] : void 0) === 'INDENT') { + prevIndent = prevTokens[0][1]; + prevTokens = prevTokens.slice(1); + } + t = 0; + while (!((prevTokens[t] == null) || (ref6 = prevTokens[t][0], indexOf.call(this.keywords, ref6) >= 0))) { + t++; + } + prevTokens = prevTokens.slice(t); + prevNum++; + if (prevTokens[0] == null) { + continue; + } + prevIndent = (ref7 = prevTokens[0]) != null ? ref7[2].first_column : void 0; + } } + return [curIndent - prevIndent]; }; return Indentation; })(); @@ -1767,11 +1824,11 @@ LineEndings.prototype.rule = { name: 'line_endings', level: 'ignore', value: 'unix', message: 'Line contains incorrect line endings', - description: "This rule ensures your project uses only <tt>windows</tt> or\n<tt>unix</tt> line endings. This rule is disabled by default." + description: 'This rule ensures your project uses only <tt>windows</tt> or\n<tt>unix</tt> line endings. This rule is disabled by default.' }; LineEndings.prototype.lintLine = function(line, lineApi) { var ending, lastChar, ref, valid; ending = (ref = lineApi.config[this.rule.name]) != null ? ref.value : void 0; @@ -1818,11 +1875,11 @@ name: 'max_line_length', value: 80, level: 'error', limitComments: true, message: 'Line exceeds maximum allowed length', - description: "This rule imposes a maximum line length on your code. <a\nhref=\"http://www.python.org/dev/peps/pep-0008/\">Python's style\nguide</a> does a good job explaining why you might want to limit the\nlength of your lines, though this is a matter of taste.\n\nLines can be no longer than eighty characters by default." + description: 'This rule imposes a maximum line length on your code. <a\nhref="http://www.python.org/dev/peps/pep-0008/">Python\'s style\nguide</a> does a good job explaining why you might want to limit the\nlength of your lines, though this is a matter of taste.\n\nLines can be no longer than eighty characters by default.' }; MaxLineLength.prototype.lintLine = function(line, lineApi) { var limitComments, lineLength, max, ref, ref1; max = (ref = lineApi.config[this.rule.name]) != null ? ref.value : void 0; @@ -1888,29 +1945,32 @@ MissingFatArrows.prototype.rule = { name: 'missing_fat_arrows', level: 'ignore', is_strict: false, message: 'Used `this` in a function without a fat arrow', - description: "Warns when you use `this` inside a function that wasn't defined\nwith a fat arrow. This rule does not apply to methods defined in a\nclass, since they have `this` bound to the class instance (or the\nclass itself, for class methods). The option `is_strict` is\navailable for checking bindings of class methods.\n\nIt is impossible to statically determine whether a function using\n`this` will be bound with the correct `this` value due to language\nfeatures like `Function.prototype.call` and\n`Function.prototype.bind`, so this rule may produce false positives." + description: 'Warns when you use `this` inside a function that wasn\'t defined\nwith a fat arrow. This rule does not apply to methods defined in a\nclass, since they have `this` bound to the class instance (or the\nclass itself, for class methods). The option `is_strict` is\navailable for checking bindings of class methods.\n\nIt is impossible to statically determine whether a function using\n`this` will be bound with the correct `this` value due to language\nfeatures like `Function.prototype.call` and\n`Function.prototype.bind`, so this rule may produce false positives.' }; MissingFatArrows.prototype.lintAST = function(node, astApi) { this.astApi = astApi; this.lintNode(node); return void 0; }; MissingFatArrows.prototype.lintNode = function(node, methods) { - var error, is_strict, ref; + var error, isStrict, ref; if (methods == null) { methods = []; } - is_strict = (ref = this.astApi.config[this.rule.name]) != null ? ref.is_strict : void 0; + isStrict = (ref = this.astApi.config[this.rule.name]) != null ? ref.is_strict : void 0; + if (this.isPrototype(node)) { + return; + } if (this.isConstructor(node)) { return; } - if ((!this.isFatArrowCode(node)) && (is_strict ? true : indexOf.call(methods, node) < 0) && (this.needsFatArrow(node))) { + if ((!this.isFatArrowCode(node)) && (isStrict ? true : indexOf.call(methods, node) < 0) && (this.needsFatArrow(node))) { error = this.astApi.createError({ lineNumber: node.locationData.first_line + 1 }); this.errors.push(error); } @@ -1944,10 +2004,22 @@ MissingFatArrows.prototype.isObject = function(node) { return this.astApi.getNodeName(node) === 'Obj'; }; + MissingFatArrows.prototype.isPrototype = function(node) { + var i, ident, len, props, ref, ref1; + props = (node != null ? (ref = node.variable) != null ? ref.properties : void 0 : void 0) || []; + for (i = 0, len = props.length; i < len; i++) { + ident = props[i]; + if (((ref1 = ident.name) != null ? ref1.value : void 0) === 'prototype') { + return true; + } + } + return false; + }; + MissingFatArrows.prototype.isThis = function(node) { return this.isValue(node) && node.base.value === 'this'; }; MissingFatArrows.prototype.isFatArrowCode = function(node) { @@ -1995,27 +2067,67 @@ NewlinesAfterClasses.prototype.rule = { name: 'newlines_after_classes', value: 3, level: 'ignore', message: 'Wrong count of newlines between a class and other code', - description: "<p>Checks the number of newlines between classes and other code.</p>\n\nOptions:\n- <pre><code>value</code></pre> - The number of required newlines\nafter class definitions. Defaults to 3." + description: '<p>Checks the number of newlines between classes and other code.</p>\n\nOptions:\n- <pre><code>value</code></pre> - The number of required newlines\nafter class definitions. Defaults to 3.' }; - NewlinesAfterClasses.prototype.lintLine = function(line, lineApi) { - var context, ending, got, lineNumber; - ending = lineApi.config[this.rule.name].value; - if (!ending || lineApi.isLastLine()) { - return null; + NewlinesAfterClasses.prototype.tokens = ['CLASS', '}', '{']; + + NewlinesAfterClasses.prototype.classBracesCount = 0; + + NewlinesAfterClasses.prototype.classCount = 0; + + NewlinesAfterClasses.prototype.lintToken = function(token, tokenApi) { + var afters, befores, comment, ending, got, lineNumber, lines, numIndents, outdent, ref, ref1, ref2, start, trueLine, type; + type = token[0], numIndents = token[1], (ref = token[2], lineNumber = ref.first_line); + lines = tokenApi.lines; + ending = tokenApi.config[this.rule.name].value; + if (type === 'CLASS') { + this.classCount++; } - lineNumber = lineApi.lineNumber, context = lineApi.context; - if (!context["class"].inClass && (context["class"].lastUnemptyLineInClass != null) && (lineNumber - context["class"].lastUnemptyLineInClass) !== ending) { - got = lineNumber - context["class"].lastUnemptyLineInClass; - return { - context: "Expected " + ending + " got " + got - }; + if (this.classCount > 0 && (token.generated != null)) { + if (type === '{' && ((ref1 = token.origin) != null ? ref1[0] : void 0) === ':') { + this.classBracesCount++; + } + if (type === '}' && ((ref2 = token.origin) != null ? ref2[0] : void 0) === 'OUTDENT') { + this.classBracesCount--; + this.classCount--; + if (this.classCount === 0 && this.classBracesCount === 0) { + befores = 1; + afters = 1; + comment = 0; + outdent = token.origin[2].first_line; + start = Math.min(lineNumber, outdent); + trueLine = Infinity; + while (/^\s*(#|$)/.test(lines[start + afters])) { + if (/^\s*#/.test(lines[start + afters])) { + comment += 1; + } else { + trueLine = Math.min(trueLine, start + afters); + } + afters += 1; + } + while (/^\s*(#|$)/.test(lines[start - befores])) { + if (/^\s*#/.test(lines[start - befores])) { + comment += 1; + } else { + trueLine = Math.min(trueLine, start - befores); + } + befores += 1; + } + got = afters + befores - comment - 2; + if (got !== ending && trueLine + ending <= lines.length) { + return { + context: "Expected " + ending + " got " + got, + lineNumber: trueLine + }; + } + } + } } - return null; }; return NewlinesAfterClasses; })(); @@ -2030,14 +2142,14 @@ NoBackticks.prototype.rule = { name: 'no_backticks', level: 'error', message: 'Backticks are forbidden', - description: "Backticks allow snippets of JavaScript to be embedded in\nCoffeeScript. While some folks consider backticks useful in a few\nniche circumstances, they should be avoided because so none of\nJavaScript's \"bad parts\", like <tt>with</tt> and <tt>eval</tt>,\nsneak into CoffeeScript.\nThis rule is enabled by default." + description: 'Backticks allow snippets of JavaScript to be embedded in\nCoffeeScript. While some folks consider backticks useful in a few\nniche circumstances, they should be avoided because so none of\nJavaScript\'s "bad parts", like <tt>with</tt> and <tt>eval</tt>,\nsneak into CoffeeScript.\nThis rule is enabled by default.' }; - NoBackticks.prototype.tokens = ["JS"]; + NoBackticks.prototype.tokens = ['JS']; NoBackticks.prototype.lintToken = function(token, tokenApi) { return true; }; @@ -2056,14 +2168,14 @@ NoDebugger.prototype.rule = { name: 'no_debugger', level: 'warn', message: 'Found debugging code', console: false, - description: "This rule detects `debugger` and optionally `console` calls\nThis rule is `warn` by default." + description: 'This rule detects `debugger` and optionally `console` calls\nThis rule is `warn` by default.' }; - NoDebugger.prototype.tokens = ["DEBUGGER", "IDENTIFIER"]; + NoDebugger.prototype.tokens = ['DEBUGGER', 'IDENTIFIER']; NoDebugger.prototype.lintToken = function(token, tokenApi) { var method, ref, ref1; if (token[0] === 'DEBUGGER') { return { @@ -2100,11 +2212,11 @@ NoEmptyFunctions.prototype.rule = { name: 'no_empty_functions', level: 'ignore', message: 'Empty function', - description: "Disallows declaring empty functions. The goal of this rule is that\nunintentional empty callbacks can be detected:\n<pre>\n<code>someFunctionWithCallback ->\ndoSomethingSignificant()\n</code>\n</pre>\nThe problem is that the call to\n<tt>doSomethingSignificant</tt> will be made regardless\nof <tt>someFunctionWithCallback</tt>'s execution. It can\nbe because you did not indent the call to\n<tt>doSomethingSignificant</tt> properly.\n\nIf you really meant that <tt>someFunctionWithCallback</tt>\nshould call a callback that does nothing, you can write your code\nthis way:\n<pre>\n<code>someFunctionWithCallback ->\n undefined\ndoSomethingSignificant()\n</code>\n</pre>" + description: 'Disallows declaring empty functions. The goal of this rule is that\nunintentional empty callbacks can be detected:\n<pre>\n<code>someFunctionWithCallback ->\ndoSomethingSignificant()\n</code>\n</pre>\nThe problem is that the call to\n<tt>doSomethingSignificant</tt> will be made regardless\nof <tt>someFunctionWithCallback</tt>\'s execution. It can\nbe because you did not indent the call to\n<tt>doSomethingSignificant</tt> properly.\n\nIf you really meant that <tt>someFunctionWithCallback</tt>\nshould call a callback that does nothing, you can write your code\nthis way:\n<pre>\n<code>someFunctionWithCallback ->\n undefined\ndoSomethingSignificant()\n</code>\n</pre>' }; NoEmptyFunctions.prototype.lintAST = function(node, astApi) { this.lintNode(node, astApi); return void 0; @@ -2139,14 +2251,14 @@ NoEmptyParamList.prototype.rule = { name: 'no_empty_param_list', level: 'ignore', message: 'Empty parameter list is forbidden', - description: "This rule prohibits empty parameter lists in function definitions.\n<pre>\n<code># The empty parameter list in here is unnecessary:\nmyFunction = () -&gt;\n\n# We might favor this instead:\nmyFunction = -&gt;\n</code>\n</pre>\nEmpty parameter lists are permitted by default." + description: 'This rule prohibits empty parameter lists in function definitions.\n<pre>\n<code># The empty parameter list in here is unnecessary:\nmyFunction = () -&gt;\n\n# We might favor this instead:\nmyFunction = -&gt;\n</code>\n</pre>\nEmpty parameter lists are permitted by default.' }; - NoEmptyParamList.prototype.tokens = ["PARAM_START"]; + NoEmptyParamList.prototype.tokens = ['PARAM_START']; NoEmptyParamList.prototype.lintToken = function(token, tokenApi) { var nextType; nextType = tokenApi.peek()[0]; return nextType === 'PARAM_END'; @@ -2168,48 +2280,56 @@ message: 'Implicit braces are forbidden', strict: true, description: 'This rule prohibits implicit braces when declaring object literals.\nImplicit braces can make code more difficult to understand,\nespecially when used in combination with optional parenthesis.\n<pre>\n<code># Do you find this code ambiguous? Is it a\n# function call with three arguments or four?\nmyFunction a, b, 1:2, 3:4\n\n# While the same code written in a more\n# explicit manner has no ambiguity.\nmyFunction(a, b, {1:2, 3:4})\n</code>\n</pre>\nImplicit braces are permitted by default, since their use is\nidiomatic CoffeeScript.' }; - NoImplicitBraces.prototype.tokens = ['{', 'OUTDENT', 'CLASS']; + NoImplicitBraces.prototype.tokens = ['{', 'OUTDENT', 'CLASS', 'IDENTIFIER']; function NoImplicitBraces() { this.isClass = false; - this.classBrace = false; + this.className = void 0; } NoImplicitBraces.prototype.lintToken = function(token, tokenApi) { - var lineNum, previousToken, type, val; + var lineNum, peekTwo, prevToken, type, val; type = token[0], val = token[1], lineNum = token[2]; if (type === 'OUTDENT' || type === 'CLASS') { return this.trackClass.apply(this, arguments); } - if (token.generated) { - if (this.classBrace) { - this.classBrace = false; - return; - } + if (type === 'IDENTIFIER' && this.isClass && ((this.className == null) || tokenApi.peek(-1)[0] === 'EXTENDS')) { + this.className = val; + } + if (token.generated && type === '{') { if (!tokenApi.config[this.rule.name].strict) { - previousToken = tokenApi.peek(-1)[0]; - if (previousToken === 'INDENT') { + prevToken = tokenApi.peek(-1)[0]; + if (prevToken === 'INDENT' || prevToken === 'TERMINATOR') { return; } } + if (this.isClass) { + prevToken = tokenApi.peek(-1)[0]; + if (prevToken === 'TERMINATOR') { + return; + } + peekTwo = tokenApi.peek(-2); + if (peekTwo[0] === 'IDENTIFIER' && peekTwo[1] === this.className) { + return; + } + } return true; } }; NoImplicitBraces.prototype.trackClass = function(token, tokenApi) { var ln, n0, n1, ref, ref1, ref2; ref = [token, tokenApi.peek()], (ref1 = ref[0], n0 = ref1[0], ln = ref1[ref1.length - 1]), (ref2 = ref[1], n1 = ref2[0]); if (n0 === 'OUTDENT' && n1 === 'TERMINATOR') { this.isClass = false; - this.classBrace = false; } if (n0 === 'CLASS') { this.isClass = true; - this.classBrace = true; + this.className = void 0; } return null; }; return NoImplicitBraces; @@ -2224,14 +2344,14 @@ module.exports = NoImplicitParens = (function() { function NoImplicitParens() {} NoImplicitParens.prototype.rule = { name: 'no_implicit_parens', - strict: true, level: 'ignore', message: 'Implicit parens are forbidden', - description: "This rule prohibits implicit parens on function calls.\n<pre>\n<code># Some folks don't like this style of coding.\nmyFunction a, b, c\n\n# And would rather it always be written like this:\nmyFunction(a, b, c)\n</code>\n</pre>\nImplicit parens are permitted by default, since their use is\nidiomatic CoffeeScript." + strict: true, + description: 'This rule prohibits implicit parens on function calls.\n<pre>\n<code># Some folks don\'t like this style of coding.\nmyFunction a, b, c\n\n# And would rather it always be written like this:\nmyFunction(a, b, c)\n</code>\n</pre>\nImplicit parens are permitted by default, since their use is\nidiomatic CoffeeScript.' }; NoImplicitParens.prototype.tokens = ['CALL_END']; NoImplicitParens.prototype.lintToken = function(token, tokenApi) { @@ -2347,14 +2467,14 @@ NoPlusPlus.prototype.rule = { name: 'no_plusplus', level: 'ignore', message: 'The increment and decrement operators are forbidden', - description: "This rule forbids the increment and decrement arithmetic operators.\nSome people believe the <tt>++</tt> and <tt>--</tt> to be cryptic\nand the cause of bugs due to misunderstandings of their precedence\nrules.\nThis rule is disabled by default." + description: 'This rule forbids the increment and decrement arithmetic operators.\nSome people believe the <tt>++</tt> and <tt>--</tt> to be cryptic\nand the cause of bugs due to misunderstandings of their precedence\nrules.\nThis rule is disabled by default.' }; - NoPlusPlus.prototype.tokens = ["++", "--"]; + NoPlusPlus.prototype.tokens = ['++', '--']; NoPlusPlus.prototype.lintToken = function(token, tokenApi) { return { context: "found '" + token[0] + "'" }; @@ -2382,11 +2502,11 @@ NoPrivateFunctionFatArrows.prototype.rule = { name: 'no_private_function_fat_arrows', level: 'warn', message: 'Used the fat arrow for a private function', - description: "Warns when you use the fat arrow for a private function\ninside a class defintion scope. It is not necessary and\nit does not do anything." + description: 'Warns when you use the fat arrow for a private function\ninside a class definition scope. It is not necessary and\nit does not do anything.' }; NoPrivateFunctionFatArrows.prototype.lintAST = function(node, astApi) { this.astApi = astApi; this.lintNode(node); @@ -2472,11 +2592,11 @@ NoStandAloneAt.prototype.rule = { name: 'no_stand_alone_at', level: 'ignore', message: '@ must not be used stand alone', - description: "This rule checks that no stand alone @ are in use, they are\ndiscouraged. Further information in CoffeScript issue <a\nhref=\"https://github.com/jashkenas/coffee-script/issues/1601\">\n#1601</a>" + description: 'This rule checks that no stand alone @ are in use, they are\ndiscouraged. Further information in CoffeeScript issue <a\nhref="https://github.com/jashkenas/coffee-script/issues/1601">\n#1601</a>' }; NoStandAloneAt.prototype.tokens = ['@']; NoStandAloneAt.prototype.lintToken = function(token, tokenApi) { @@ -2512,11 +2632,11 @@ NoTabs.prototype.rule = { name: 'no_tabs', level: 'error', message: 'Line contains tab indentation', - description: "This rule forbids tabs in indentation. Enough said. It is enabled by\ndefault." + description: 'This rule forbids tabs in indentation. Enough said. It is enabled by\ndefault.' }; NoTabs.prototype.lintLine = function(line, lineApi) { var indentation; indentation = line.split(indentationRegex)[0]; @@ -2539,19 +2659,24 @@ module.exports = NoThis = (function() { function NoThis() {} NoThis.prototype.rule = { name: 'no_this', - description: 'This rule prohibits \'this\'.\nUse \'@\' instead.', level: 'ignore', - message: "Don't use 'this', use '@' instead" + message: "Don't use 'this', use '@' instead", + description: 'This rule prohibits \'this\'.\nUse \'@\' instead.' }; NoThis.prototype.tokens = ['THIS']; NoThis.prototype.lintToken = function(token, tokenApi) { - return true; + var level, nextToken, ref; + level = tokenApi.config.no_stand_alone_at.level; + nextToken = (ref = tokenApi.peek(1)) != null ? ref[0] : void 0; + if (!(level !== 'ignore' && nextToken !== '.')) { + return true; + } }; return NoThis; })(); @@ -2566,11 +2691,11 @@ NoThrowingStrings.prototype.rule = { name: 'no_throwing_strings', level: 'error', message: 'Throwing strings is forbidden', - description: "This rule forbids throwing string literals or interpolations. While\nJavaScript (and CoffeeScript by extension) allow any expression to\nbe thrown, it is best to only throw <a\nhref=\"https://developer.mozilla.org\n/en/JavaScript/Reference/Global_Objects/Error\"> Error</a> objects,\nbecause they contain valuable debugging information like the stack\ntrace. Because of JavaScript's dynamic nature, CoffeeLint cannot\nensure you are always throwing instances of <tt>Error</tt>. It will\nonly catch the simple but real case of throwing literal strings.\n<pre>\n<code># CoffeeLint will catch this:\nthrow \"i made a boo boo\"\n\n# ... but not this:\nthrow getSomeString()\n</code>\n</pre>\nThis rule is enabled by default." + description: 'This rule forbids throwing string literals or interpolations. While\nJavaScript (and CoffeeScript by extension) allow any expression to\nbe thrown, it is best to only throw <a\nhref="https://developer.mozilla.org\n/en/JavaScript/Reference/Global_Objects/Error"> Error</a> objects,\nbecause they contain valuable debugging information like the stack\ntrace. Because of JavaScript\'s dynamic nature, CoffeeLint cannot\nensure you are always throwing instances of <tt>Error</tt>. It will\nonly catch the simple but real case of throwing literal strings.\n<pre>\n<code># CoffeeLint will catch this:\nthrow "i made a boo boo"\n\n# ... but not this:\nthrow getSomeString()\n</code>\n</pre>\nThis rule is enabled by default.' }; NoThrowingStrings.prototype.tokens = ['THROW']; NoThrowingStrings.prototype.lintToken = function(token, tokenApi) { @@ -2600,11 +2725,11 @@ NoTrailingSemicolons.prototype.rule = { name: 'no_trailing_semicolons', level: 'error', message: 'Line contains a trailing semicolon', - description: "This rule prohibits trailing semicolons, since they are needless\ncruft in CoffeeScript.\n<pre>\n<code># This semicolon is meaningful.\nx = '1234'; console.log(x)\n\n# This semicolon is redundant.\nalert('end of line');\n</code>\n</pre>\nTrailing semicolons are forbidden by default." + description: 'This rule prohibits trailing semicolons, since they are needless\ncruft in CoffeeScript.\n<pre>\n<code># This semicolon is meaningful.\nx = \'1234\'; console.log(x)\n\n# This semicolon is redundant.\nalert(\'end of line\');\n</code>\n</pre>\nTrailing semicolons are forbidden by default.' }; NoTrailingSemicolons.prototype.lintLine = function(line, lineApi) { var endPos, first, hasNewLine, hasSemicolon, i, last, lineTokens, newLine, ref, ref1, startCounter, startPos, stopTokens, tokenLen; lineTokens = lineApi.getLineTokens(); @@ -2655,11 +2780,11 @@ name: 'no_trailing_whitespace', level: 'error', message: 'Line ends with trailing whitespace', allowed_in_comments: false, allowed_in_empty_lines: true, - description: "This rule forbids trailing whitespace in your code, since it is\nneedless cruft. It is enabled by default." + description: 'This rule forbids trailing whitespace in your code, since it is\nneedless cruft. It is enabled by default.' }; NoTrailingWhitespace.prototype.lintLine = function(line, lineApi) { var i, len, ref, ref1, ref2, str, token, tokens; if (!((ref = lineApi.config['no_trailing_whitespace']) != null ? ref.allowed_in_empty_lines : void 0)) { @@ -2779,11 +2904,11 @@ NoUnnecessaryFatArrows.prototype.rule = { name: 'no_unnecessary_fat_arrows', level: 'warn', message: 'Unnecessary fat arrow', - description: "Disallows defining functions with fat arrows when `this`\nis not used within the function." + description: 'Disallows defining functions with fat arrows when `this`\nis not used within the function.' }; NoUnnecessaryFatArrows.prototype.lintAST = function(node, astApi) { this.astApi = astApi; this.lintNode(node); @@ -2859,11 +2984,11 @@ NonEmptyConstructorNeedsParens.prototype.rule = { name: 'non_empty_constructor_needs_parens', level: 'ignore', message: 'Invoking a constructor without parens and with arguments', - description: "Requires constructors with parameters to include the parens" + description: 'Requires constructors with parameters to include the parens' }; NonEmptyConstructorNeedsParens.prototype.handleExpectedCallStart = function(expectedCallStart) { if (expectedCallStart[0] === 'CALL_START' && expectedCallStart.generated) { return true; @@ -2882,14 +3007,14 @@ module.exports = PreferEnglishOperator = (function() { function PreferEnglishOperator() {} PreferEnglishOperator.prototype.rule = { name: 'prefer_english_operator', - description: 'This rule prohibits &&, ||, ==, != and !.\nUse and, or, is, isnt, and not instead.\n!! for converting to a boolean is ignored.', level: 'ignore', + message: 'Don\'t use &&, ||, ==, !=, or !', doubleNotLevel: 'ignore', - message: 'Don\'t use &&, ||, ==, !=, or !' + description: 'This rule prohibits &&, ||, ==, != and !.\nUse and, or, is, isnt, and not instead.\n!! for converting to a boolean is ignored.' }; PreferEnglishOperator.prototype.tokens = ['COMPARE', 'UNARY_MATH', 'LOGIC']; PreferEnglishOperator.prototype.lintToken = function(token, tokenApi) { @@ -2945,11 +3070,11 @@ module.exports = SpaceOperators = (function() { SpaceOperators.prototype.rule = { name: 'space_operators', level: 'ignore', message: 'Operators must be spaced properly', - description: "This rule enforces that operators have space around them." + description: 'This rule enforces that operators have spaces around them.' }; SpaceOperators.prototype.tokens = ['+', '-', '=', '**', 'MATH', 'COMPARE', 'LOGIC', 'COMPOUND_ASSIGN', 'STRING_START', 'STRING_END', 'CALL_START', 'CALL_END']; function SpaceOperators() { @@ -3051,13 +3176,13 @@ var SpacingAfterComma; module.exports = SpacingAfterComma = (function() { SpacingAfterComma.prototype.rule = { name: 'spacing_after_comma', - description: 'This rule requires a space after commas.', level: 'ignore', - message: 'Spaces are required after commas' + message: 'a space is required after commas', + description: 'This rule checks to make sure you have a space after commas.' }; SpacingAfterComma.prototype.tokens = [',', 'REGEX_START', 'REGEX_END']; function SpacingAfterComma() { @@ -3074,13 +3199,11 @@ if (type === 'REGEX_END') { this.inRegex = false; return; } if (!(token.spaced || token.newLine || token.generated || this.isRegexFlag(token, tokenApi))) { - return { - context: token[1] - }; + return true; } }; SpacingAfterComma.prototype.isRegexFlag = function(token, tokenApi) { var maybeEnd; @@ -3105,10 +3228,10 @@ TransformMessesUpLineNumbers.prototype.rule = { name: 'transform_messes_up_line_numbers', level: 'warn', message: 'Transforming source messes up line numbers', - description: "This rule detects when changes are made by transform function,\nand warns that line numbers are probably incorrect." + description: 'This rule detects when changes are made by transform function,\nand warns that line numbers are probably incorrect.' }; TransformMessesUpLineNumbers.prototype.tokens = []; TransformMessesUpLineNumbers.prototype.lintToken = function(token, tokenApi) {}; \ No newline at end of file