Blame view
node_modules/eslint/lib/rules/comma-style.js
6.56 KB
c39994410
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
/** * @fileoverview Comma style - enforces comma styles of two types: last and first * @author Vignesh Anand aka vegetableman * @copyright 2014 Vignesh Anand. All rights reserved. * @copyright 2015 Evan Simmons. All rights reserved. */ "use strict"; var astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { var style = context.options[0] || "last", exceptions = {}; if (context.options.length === 2 && context.options[1].hasOwnProperty("exceptions")) { exceptions = context.options[1].exceptions; } //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** * Determines if a given token is a comma operator. * @param {ASTNode} token The token to check. * @returns {boolean} True if the token is a comma, false if not. * @private */ function isComma(token) { return !!token && (token.type === "Punctuator") && (token.value === ","); } /** * Validates the spacing around single items in lists. * @param {Token} previousItemToken The last token from the previous item. * @param {Token} commaToken The token representing the comma. * @param {Token} currentItemToken The first token of the current item. * @param {Token} reportItem The item to use when reporting an error. * @returns {void} * @private */ function validateCommaItemSpacing(previousItemToken, commaToken, currentItemToken, reportItem) { // if single line if (astUtils.isTokenOnSameLine(commaToken, currentItemToken) && astUtils.isTokenOnSameLine(previousItemToken, commaToken)) { return; } else if (!astUtils.isTokenOnSameLine(commaToken, currentItemToken) && !astUtils.isTokenOnSameLine(previousItemToken, commaToken)) { // lone comma context.report(reportItem, { line: commaToken.loc.end.line, column: commaToken.loc.start.column }, "Bad line breaking before and after ','."); } else if (style === "first" && !astUtils.isTokenOnSameLine(commaToken, currentItemToken)) { context.report(reportItem, "',' should be placed first."); } else if (style === "last" && astUtils.isTokenOnSameLine(commaToken, currentItemToken)) { context.report(reportItem, { line: commaToken.loc.end.line, column: commaToken.loc.end.column }, "',' should be placed last."); } } /** * Checks the comma placement with regards to a declaration/property/element * @param {ASTNode} node The binary expression node to check * @param {string} property The property of the node containing child nodes. * @private * @returns {void} */ function validateComma(node, property) { var items = node[property], arrayLiteral = (node.type === "ArrayExpression"), previousItemToken; if (items.length > 1 || arrayLiteral) { // seed as opening [ previousItemToken = context.getFirstToken(node); items.forEach(function(item) { var commaToken = item ? context.getTokenBefore(item) : previousItemToken, currentItemToken = item ? context.getFirstToken(item) : context.getTokenAfter(commaToken), reportItem = item || currentItemToken; /* * This works by comparing three token locations: * - previousItemToken is the last token of the previous item * - commaToken is the location of the comma before the current item * - currentItemToken is the first token of the current item * * These values get switched around if item is undefined. * previousItemToken will refer to the last token not belonging * to the current item, which could be a comma or an opening * square bracket. currentItemToken could be a comma. * * All comparisons are done based on these tokens directly, so * they are always valid regardless of an undefined item. */ if (isComma(commaToken)) { validateCommaItemSpacing(previousItemToken, commaToken, currentItemToken, reportItem); } previousItemToken = item ? context.getLastToken(item) : previousItemToken; }); /* * Special case for array literals that have empty last items, such * as [ 1, 2, ]. These arrays only have two items show up in the * AST, so we need to look at the token to verify that there's no * dangling comma. */ if (arrayLiteral) { var lastToken = context.getLastToken(node), nextToLastToken = context.getTokenBefore(lastToken); if (isComma(nextToLastToken)) { validateCommaItemSpacing( context.getTokenBefore(nextToLastToken), nextToLastToken, lastToken, lastToken ); } } } } //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- var nodes = {}; if (!exceptions.VariableDeclaration) { nodes.VariableDeclaration = function(node) { validateComma(node, "declarations"); }; } if (!exceptions.ObjectExpression) { nodes.ObjectExpression = function(node) { validateComma(node, "properties"); }; } if (!exceptions.ArrayExpression) { nodes.ArrayExpression = function(node) { validateComma(node, "elements"); }; } return nodes; }; module.exports.schema = [ { "enum": ["first", "last"] }, { "type": "object", "properties": { "exceptions": { "type": "object", "additionalProperties": { "type": "boolean" } } }, "additionalProperties": false } ]; |