UNPKG

@coffeelint/cli

Version:
126 lines (114 loc) 4.22 kB
(function() { var NoImplicitBraces, slice = [].slice; module.exports = NoImplicitBraces = (function() { class NoImplicitBraces { constructor() { this.isClass = false; this.className = ''; } lintToken(token, tokenApi) { var _type, _val, c, lineNum, peekIdent, prevToken, ref, type, val; [type, val, lineNum] = token; if (type === 'OUTDENT' || type === 'INDENT' || type === 'CLASS') { return this.trackClass(...arguments); } // reset "className" if class uses EXTENDS keyword if (type === 'EXTENDS') { this.className = ''; return; } // If we're looking at an IDENTIFIER, and we're in a class, and we've not // set a className (or the previous non-identifier was 'EXTENDS', set the // current identifier as the class name) if ((type === 'IDENTIFIER' || type === 'PROPERTY') && this.isClass && this.className === '') { // Backtrack to get the full classname c = 0; while ((ref = tokenApi.peek(c)[0]) === 'IDENTIFIER' || ref === 'PROPERTY' || ref === '.') { this.className += tokenApi.peek(c)[1]; c++; } } if (token.generated && type === '{') { // If strict mode is set to false it allows implicit braces when the // object is declared over multiple lines. if (!tokenApi.config[this.rule.name].strict) { [prevToken] = tokenApi.peek(-1); if (prevToken === 'INDENT' || prevToken === 'TERMINATOR') { return; } } if (this.isClass) { // The way CoffeeScript generates tokens for classes // is a bit weird. It generates '{' tokens around instance // methods (also known as the prototypes of an Object). [prevToken] = tokenApi.peek(-1); // If there is a TERMINATOR token right before the '{' token if (prevToken === 'TERMINATOR') { return; } peekIdent = ''; c = -2; // Go back until you grab all the tokens with IDENTIFIER, // PROPERTY or '.' while (([_type, _val] = tokenApi.peek(c))) { if (_type !== 'IDENTIFIER' && _type !== 'PROPERTY' && _type !== '.') { break; } peekIdent = _val + peekIdent; c--; } if (peekIdent === this.className) { return; } } return { token: tokenApi.peek(c + 1) }; } } trackClass(token, tokenApi) { var ln, n0, n1, ref, ref1, ref2; ref = [token, tokenApi.peek()], (ref1 = ref[0], [n0] = ref1, [ln] = slice.call(ref1, -1)), (ref2 = ref[1], [n1] = ref2); if (n0 === 'INDENT') { this.dent++; } if (n0 === 'OUTDENT') { this.dent--; } if (this.dent === 0 && n0 === 'OUTDENT' && n1 === 'TERMINATOR') { this.isClass = false; } if (n0 === 'CLASS') { this.isClass = true; this.className = ''; } return null; } }; NoImplicitBraces.prototype.rule = { type: 'style', name: 'no_implicit_braces', level: 'ignore', message: 'Implicit braces are forbidden', strict: true, description: `This rule prohibits implicit braces when declaring object literals. Implicit braces can make code more difficult to understand, especially when used in combination with optional parenthesis. <pre> <code># Do you find this code ambiguous? Is it a # function call with three arguments or four? myFunction a, b, 1:2, 3:4 # While the same code written in a more # explicit manner has no ambiguity. myFunction(a, b, {1:2, 3:4}) </code> </pre> Implicit braces are permitted by default, since their use is idiomatic CoffeeScript.` }; NoImplicitBraces.prototype.tokens = ['{', 'OUTDENT', 'INDENT', 'CLASS', 'IDENTIFIER', 'PROPERTY', 'EXTENDS']; NoImplicitBraces.prototype.dent = 0; return NoImplicitBraces; }).call(this); }).call(this);