2 * @fileoverview Enforces that a return statement is present in property getters.
3 * @author Aladdin-ADD(hh_2013@foxmail.com)
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils = require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
17 const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
20 * Checks a given code path segment is reachable.
21 * @param {CodePathSegment} segment A segment to check.
22 * @returns {boolean} `true` if the segment is reachable.
24 function isReachable(segment) {
25 return segment.reachable;
28 //------------------------------------------------------------------------------
30 //------------------------------------------------------------------------------
37 description: "enforce `return` statements in getters",
38 category: "Possible Errors",
40 url: "https://eslint.org/docs/rules/getter-return"
54 additionalProperties: false
59 expected: "Expected to return a value in {{name}}.",
60 expectedAlways: "Expected {{name}} to always return a value."
66 const options = context.options[0] || { allowImplicit: false };
67 const sourceCode = context.getSourceCode();
78 * Checks whether or not the last code path segment is reachable.
79 * Then reports this function if the segment is reachable.
81 * If the last code path segment is reachable, there are paths which are not
83 * @param {ASTNode} node A node to check.
86 function checkLastSegment(node) {
87 if (funcInfo.shouldCheck &&
88 funcInfo.codePath.currentSegments.some(isReachable)
92 loc: astUtils.getFunctionHeadLoc(node, sourceCode),
93 messageId: funcInfo.hasReturn ? "expectedAlways" : "expected",
95 name: astUtils.getFunctionNameWithKind(funcInfo.node)
102 * Checks whether a node means a getter function.
103 * @param {ASTNode} node a node to check.
104 * @returns {boolean} if node means a getter, return true; else return false.
106 function isGetter(node) {
107 const parent = node.parent;
109 if (TARGET_NODE_TYPE.test(node.type) && node.body.type === "BlockStatement") {
110 if (parent.kind === "get") {
113 if (parent.type === "Property" && astUtils.getStaticPropertyName(parent) === "get" && parent.parent.type === "ObjectExpression") {
115 // Object.defineProperty()
116 if (parent.parent.parent.type === "CallExpression" &&
117 astUtils.getStaticPropertyName(parent.parent.parent.callee) === "defineProperty") {
121 // Object.defineProperties()
122 if (parent.parent.parent.type === "Property" &&
123 parent.parent.parent.parent.type === "ObjectExpression" &&
124 parent.parent.parent.parent.parent.type === "CallExpression" &&
125 astUtils.getStaticPropertyName(parent.parent.parent.parent.parent.callee) === "defineProperties") {
134 // Stacks this function's information.
135 onCodePathStart(codePath, node) {
140 shouldCheck: isGetter(node),
145 // Pops this function's information.
147 funcInfo = funcInfo.upper;
150 // Checks the return statement is valid.
151 ReturnStatement(node) {
152 if (funcInfo.shouldCheck) {
153 funcInfo.hasReturn = true;
155 // if allowImplicit: false, should also check node.argument
156 if (!options.allowImplicit && !node.argument) {
159 messageId: "expected",
161 name: astUtils.getFunctionNameWithKind(funcInfo.node)
168 // Reports a given function if the last path is reachable.
169 "FunctionExpression:exit": checkLastSegment,
170 "ArrowFunctionExpression:exit": checkLastSegment