1/** 2 * @fileoverview Rule to define spacing before/after arrow function's arrow. 3 * @author Jxck 4 */ 5"use strict"; 6 7//------------------------------------------------------------------------------ 8// Requirements 9//------------------------------------------------------------------------------ 10 11const astUtils = require("./utils/ast-utils"); 12 13//------------------------------------------------------------------------------ 14// Rule Definition 15//------------------------------------------------------------------------------ 16 17module.exports = { 18 meta: { 19 type: "layout", 20 21 docs: { 22 description: "enforce consistent spacing before and after the arrow in arrow functions", 23 category: "ECMAScript 6", 24 recommended: false, 25 url: "https://eslint.org/docs/rules/arrow-spacing" 26 }, 27 28 fixable: "whitespace", 29 30 schema: [ 31 { 32 type: "object", 33 properties: { 34 before: { 35 type: "boolean", 36 default: true 37 }, 38 after: { 39 type: "boolean", 40 default: true 41 } 42 }, 43 additionalProperties: false 44 } 45 ], 46 47 messages: { 48 expectedBefore: "Missing space before =>.", 49 unexpectedBefore: "Unexpected space before =>.", 50 51 expectedAfter: "Missing space after =>.", 52 unexpectedAfter: "Unexpected space after =>." 53 } 54 }, 55 56 create(context) { 57 58 // merge rules with default 59 const rule = Object.assign({}, context.options[0]); 60 61 rule.before = rule.before !== false; 62 rule.after = rule.after !== false; 63 64 const sourceCode = context.getSourceCode(); 65 66 /** 67 * Get tokens of arrow(`=>`) and before/after arrow. 68 * @param {ASTNode} node The arrow function node. 69 * @returns {Object} Tokens of arrow and before/after arrow. 70 */ 71 function getTokens(node) { 72 const arrow = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken); 73 74 return { 75 before: sourceCode.getTokenBefore(arrow), 76 arrow, 77 after: sourceCode.getTokenAfter(arrow) 78 }; 79 } 80 81 /** 82 * Count spaces before/after arrow(`=>`) token. 83 * @param {Object} tokens Tokens before/after arrow. 84 * @returns {Object} count of space before/after arrow. 85 */ 86 function countSpaces(tokens) { 87 const before = tokens.arrow.range[0] - tokens.before.range[1]; 88 const after = tokens.after.range[0] - tokens.arrow.range[1]; 89 90 return { before, after }; 91 } 92 93 /** 94 * Determines whether space(s) before after arrow(`=>`) is satisfy rule. 95 * if before/after value is `true`, there should be space(s). 96 * if before/after value is `false`, there should be no space. 97 * @param {ASTNode} node The arrow function node. 98 * @returns {void} 99 */ 100 function spaces(node) { 101 const tokens = getTokens(node); 102 const countSpace = countSpaces(tokens); 103 104 if (rule.before) { 105 106 // should be space(s) before arrow 107 if (countSpace.before === 0) { 108 context.report({ 109 node: tokens.before, 110 messageId: "expectedBefore", 111 fix(fixer) { 112 return fixer.insertTextBefore(tokens.arrow, " "); 113 } 114 }); 115 } 116 } else { 117 118 // should be no space before arrow 119 if (countSpace.before > 0) { 120 context.report({ 121 node: tokens.before, 122 messageId: "unexpectedBefore", 123 fix(fixer) { 124 return fixer.removeRange([tokens.before.range[1], tokens.arrow.range[0]]); 125 } 126 }); 127 } 128 } 129 130 if (rule.after) { 131 132 // should be space(s) after arrow 133 if (countSpace.after === 0) { 134 context.report({ 135 node: tokens.after, 136 messageId: "expectedAfter", 137 fix(fixer) { 138 return fixer.insertTextAfter(tokens.arrow, " "); 139 } 140 }); 141 } 142 } else { 143 144 // should be no space after arrow 145 if (countSpace.after > 0) { 146 context.report({ 147 node: tokens.after, 148 messageId: "unexpectedAfter", 149 fix(fixer) { 150 return fixer.removeRange([tokens.arrow.range[1], tokens.after.range[0]]); 151 } 152 }); 153 } 154 } 155 } 156 157 return { 158 ArrowFunctionExpression: spaces 159 }; 160 } 161}; 162