| 'use strict' |
| |
| /** |
| * @fileoverview Disallows or enforces spaces inside of array brackets. |
| * @author Jamund Ferguson |
| * @copyright 2015 Jamund Ferguson. All rights reserved. |
| * @copyright 2014 Brandyn Bennett. All rights reserved. |
| * @copyright 2014 Michael Ficarra. No rights reserved. |
| * @copyright 2014 Vignesh Anand. All rights reserved. |
| */ |
| // ------------------------------------------------------------------------------ |
| // Rule Definition |
| // ------------------------------------------------------------------------------ |
| |
| module.exports = { |
| meta: { |
| docs: { |
| url: 'https://github.com/xjamundx/eslint-plugin-standard#rules-explanations' |
| } |
| }, |
| |
| create: function (context) { |
| var spaced = context.options[0] === 'always' |
| var either = context.options[0] === 'either' |
| |
| /** |
| * Determines whether an option is set, relative to the spacing option. |
| * If spaced is "always", then check whether option is set to false. |
| * If spaced is "never", then check whether option is set to true. |
| * @param {Object} option - The option to exclude. |
| * @returns {boolean} Whether or not the property is excluded. |
| */ |
| function isOptionSet (option) { |
| return context.options[1] != null ? context.options[1][option] === !spaced : false |
| } |
| |
| var options = { |
| either: either, |
| spaced: spaced, |
| singleElementException: isOptionSet('singleValue'), |
| objectsInArraysException: isOptionSet('objectsInArrays'), |
| arraysInArraysException: isOptionSet('arraysInArrays') |
| } |
| |
| // -------------------------------------------------------------------------- |
| // Helpers |
| // -------------------------------------------------------------------------- |
| |
| /** |
| * Determines whether two adjacent tokens are have whitespace between them. |
| * @param {Object} left - The left token object. |
| * @param {Object} right - The right token object. |
| * @returns {boolean} Whether or not there is space between the tokens. |
| */ |
| function isSpaced (left, right) { |
| return left.range[1] < right.range[0] |
| } |
| |
| /** |
| * Determines whether two adjacent tokens are on the same line. |
| * @param {Object} left - The left token object. |
| * @param {Object} right - The right token object. |
| * @returns {boolean} Whether or not the tokens are on the same line. |
| */ |
| function isSameLine (left, right) { |
| return left.loc.start.line === right.loc.start.line |
| } |
| |
| /** |
| * Reports that there shouldn't be a space after the first token |
| * @param {ASTNode} node - The node to report in the event of an error. |
| * @param {Token} token - The token to use for the report. |
| * @returns {void} |
| */ |
| function reportNoBeginningSpace (node, token) { |
| context.report(node, token.loc.start, |
| "There should be no space after '" + token.value + "'") |
| } |
| |
| /** |
| * Reports that there shouldn't be a space before the last token |
| * @param {ASTNode} node - The node to report in the event of an error. |
| * @param {Token} token - The token to use for the report. |
| * @returns {void} |
| */ |
| function reportNoEndingSpace (node, token) { |
| context.report(node, token.loc.start, |
| "There should be no space before '" + token.value + "'") |
| } |
| |
| /** |
| * Reports that there should be a space after the first token |
| * @param {ASTNode} node - The node to report in the event of an error. |
| * @param {Token} token - The token to use for the report. |
| * @returns {void} |
| */ |
| function reportRequiredBeginningSpace (node, token) { |
| context.report(node, token.loc.start, |
| "A space is required after '" + token.value + "'") |
| } |
| |
| /** |
| * Reports that there should be a space before the last token |
| * @param {ASTNode} node - The node to report in the event of an error. |
| * @param {Token} token - The token to use for the report. |
| * @returns {void} |
| */ |
| function reportRequiredEndingSpace (node, token) { |
| context.report(node, token.loc.start, |
| "A space is required before '" + token.value + "'") |
| } |
| |
| /** |
| * Checks if a start and end brace in a node are spaced evenly |
| * and not too long (>1 space) |
| * @param node |
| * @param start |
| * @param end |
| * @returns {boolean} |
| */ |
| function isEvenlySpacedAndNotTooLong (node, start, end) { |
| var expectedSpace = start[1].range[0] - start[0].range[1] |
| var endSpace = end[1].range[0] - end[0].range[1] |
| return endSpace === expectedSpace && endSpace <= 1 |
| } |
| |
| /** |
| * Validates the spacing around array brackets |
| * @param {ASTNode} node - The node we're checking for spacing |
| * @returns {void} |
| */ |
| function validateArraySpacing (node) { |
| if (node.elements.length === 0) { |
| return |
| } |
| |
| var first = context.getFirstToken(node) |
| var second = context.getFirstToken(node, 1) |
| var penultimate = context.getLastToken(node, 1) |
| var last = context.getLastToken(node) |
| |
| var openingBracketMustBeSpaced = |
| (options.objectsInArraysException && second.value === '{') || |
| (options.arraysInArraysException && second.value === '[') || |
| (options.singleElementException && node.elements.length === 1) |
| ? !options.spaced : options.spaced |
| |
| var closingBracketMustBeSpaced = |
| (options.objectsInArraysException && penultimate.value === '}') || |
| (options.arraysInArraysException && penultimate.value === ']') || |
| (options.singleElementException && node.elements.length === 1) |
| ? !options.spaced : options.spaced |
| |
| // we only care about evenly spaced things |
| if (options.either) { |
| // newlines at any point means return |
| if (!isSameLine(first, last)) { |
| return |
| } |
| |
| // confirm that the object expression/literal is spaced evenly |
| if (!isEvenlySpacedAndNotTooLong(node, [first, second], [penultimate, last])) { |
| context.report(node, 'Expected consistent spacing') |
| } |
| |
| return |
| } |
| |
| if (isSameLine(first, second)) { |
| if (openingBracketMustBeSpaced && !isSpaced(first, second)) { |
| reportRequiredBeginningSpace(node, first) |
| } |
| if (!openingBracketMustBeSpaced && isSpaced(first, second)) { |
| reportNoBeginningSpace(node, first) |
| } |
| } |
| |
| if (isSameLine(penultimate, last)) { |
| if (closingBracketMustBeSpaced && !isSpaced(penultimate, last)) { |
| reportRequiredEndingSpace(node, last) |
| } |
| if (!closingBracketMustBeSpaced && isSpaced(penultimate, last)) { |
| reportNoEndingSpace(node, last) |
| } |
| } |
| } |
| |
| // -------------------------------------------------------------------------- |
| // Public |
| // -------------------------------------------------------------------------- |
| |
| return { |
| ArrayPattern: validateArraySpacing, |
| ArrayExpression: validateArraySpacing |
| } |
| } |
| } |