Blame view
node_modules/eslint/lib/rules/arrow-body-style.js
7.03 KB
f7563de62
|
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 |
/** * @fileoverview Rule to require braces in arrow function body. * @author Alberto RodrÃguez */ "use strict"; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ const astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: "require braces around arrow function bodies", category: "ECMAScript 6", recommended: false }, schema: { anyOf: [ { type: "array", items: [ { enum: ["always", "never"] } ], minItems: 0, maxItems: 1 }, { type: "array", items: [ { enum: ["as-needed"] }, { type: "object", properties: { requireReturnForObjectLiteral: { type: "boolean" } }, additionalProperties: false } ], minItems: 0, maxItems: 2 } ] }, fixable: "code" }, create(context) { const options = context.options; const always = options[0] === "always"; const asNeeded = !options[0] || options[0] === "as-needed"; const never = options[0] === "never"; const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral; const sourceCode = context.getSourceCode(); /** * Determines whether a arrow function body needs braces * @param {ASTNode} node The arrow function node. * @returns {void} */ function validate(node) { const arrowBody = node.body; if (arrowBody.type === "BlockStatement") { const blockBody = arrowBody.body; if (blockBody.length !== 1 && !never) { return; } if (asNeeded && requireReturnForObjectLiteral && blockBody[0].type === "ReturnStatement" && blockBody[0].argument && blockBody[0].argument.type === "ObjectExpression") { return; } if (never || asNeeded && blockBody[0].type === "ReturnStatement") { context.report({ node, loc: arrowBody.loc.start, message: "Unexpected block statement surrounding arrow body.", fix(fixer) { if (blockBody.length !== 1 || blockBody[0].type !== "ReturnStatement" || !blockBody[0].argument) { return null; } const sourceText = sourceCode.getText(); const returnKeyword = sourceCode.getFirstToken(blockBody[0]); const firstValueToken = sourceCode.getTokenAfter(returnKeyword); let lastValueToken = sourceCode.getLastToken(blockBody[0]); if (astUtils.isSemicolonToken(lastValueToken)) { /* The last token of the returned value is the last token of the ReturnExpression (if * the ReturnExpression has no semicolon), or the second-to-last token (if the ReturnExpression * has a semicolon). */ lastValueToken = sourceCode.getTokenBefore(lastValueToken); } const tokenAfterArrowBody = sourceCode.getTokenAfter(arrowBody); if (tokenAfterArrowBody && tokenAfterArrowBody.type === "Punctuator" && /^[([/`+-]/.test(tokenAfterArrowBody.value)) { // Don't do a fix if the next token would cause ASI issues when preceded by the returned value. return null; } const textBeforeReturn = sourceText.slice(arrowBody.range[0] + 1, returnKeyword.range[0]); const textBetweenReturnAndValue = sourceText.slice(returnKeyword.range[1], firstValueToken.range[0]); const rawReturnValueText = sourceText.slice(firstValueToken.range[0], lastValueToken.range[1]); const returnValueText = astUtils.isOpeningBraceToken(firstValueToken) ? `(${rawReturnValueText})` : rawReturnValueText; const textAfterValue = sourceText.slice(lastValueToken.range[1], blockBody[0].range[1] - 1); const textAfterReturnStatement = sourceText.slice(blockBody[0].range[1], arrowBody.range[1] - 1); /* * For fixes that only contain spaces around the return value, remove the extra spaces. * This avoids ugly fixes that end up with extra spaces after the arrow, e.g. `() => 0 ;` */ return fixer.replaceText( arrowBody, (textBeforeReturn + textBetweenReturnAndValue).replace(/^\s*$/, "") + returnValueText + (textAfterValue + textAfterReturnStatement).replace(/^\s*$/, "") ); } }); } } else { if (always || (asNeeded && requireReturnForObjectLiteral && arrowBody.type === "ObjectExpression")) { context.report({ node, loc: arrowBody.loc.start, message: "Expected block statement surrounding arrow body.", fix(fixer) { const lastTokenBeforeBody = sourceCode.getLastTokenBetween(sourceCode.getFirstToken(node), arrowBody, astUtils.isNotOpeningParenToken); const firstBodyToken = sourceCode.getTokenAfter(lastTokenBeforeBody); return fixer.replaceTextRange( [firstBodyToken.range[0], node.range[1]], `{return ${sourceCode.getText().slice(firstBodyToken.range[0], node.range[1])}}` ); } }); } } } return { ArrowFunctionExpression: validate }; } }; |