]> git.proxmox.com Git - pve-eslint.git/blame - eslint/lib/rules/getter-return.js
import 8.3.0 source
[pve-eslint.git] / eslint / lib / rules / getter-return.js
CommitLineData
eb39fafa
DC
1/**
2 * @fileoverview Enforces that a return statement is present in property getters.
3 * @author Aladdin-ADD(hh_2013@foxmail.com)
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const astUtils = require("./utils/ast-utils");
13
14//------------------------------------------------------------------------------
15// Helpers
16//------------------------------------------------------------------------------
17const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
18
19/**
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.
23 */
24function isReachable(segment) {
25 return segment.reachable;
26}
27
eb39fafa
DC
28//------------------------------------------------------------------------------
29// Rule Definition
30//------------------------------------------------------------------------------
31
32module.exports = {
33 meta: {
34 type: "problem",
35
36 docs: {
37 description: "enforce `return` statements in getters",
eb39fafa
DC
38 recommended: true,
39 url: "https://eslint.org/docs/rules/getter-return"
40 },
41
42 fixable: null,
43
44 schema: [
45 {
46 type: "object",
47 properties: {
48 allowImplicit: {
49 type: "boolean",
50 default: false
51 }
52 },
53 additionalProperties: false
54 }
55 ],
56
57 messages: {
58 expected: "Expected to return a value in {{name}}.",
59 expectedAlways: "Expected {{name}} to always return a value."
60 }
61 },
62
63 create(context) {
64
65 const options = context.options[0] || { allowImplicit: false };
56c4a2cb 66 const sourceCode = context.getSourceCode();
eb39fafa
DC
67
68 let funcInfo = {
69 upper: null,
70 codePath: null,
71 hasReturn: false,
72 shouldCheck: false,
73 node: null
74 };
75
76 /**
77 * Checks whether or not the last code path segment is reachable.
78 * Then reports this function if the segment is reachable.
79 *
80 * If the last code path segment is reachable, there are paths which are not
81 * returned or thrown.
82 * @param {ASTNode} node A node to check.
83 * @returns {void}
84 */
85 function checkLastSegment(node) {
86 if (funcInfo.shouldCheck &&
87 funcInfo.codePath.currentSegments.some(isReachable)
88 ) {
89 context.report({
90 node,
56c4a2cb 91 loc: astUtils.getFunctionHeadLoc(node, sourceCode),
eb39fafa
DC
92 messageId: funcInfo.hasReturn ? "expectedAlways" : "expected",
93 data: {
94 name: astUtils.getFunctionNameWithKind(funcInfo.node)
95 }
96 });
97 }
98 }
99
100 /**
101 * Checks whether a node means a getter function.
102 * @param {ASTNode} node a node to check.
103 * @returns {boolean} if node means a getter, return true; else return false.
104 */
105 function isGetter(node) {
106 const parent = node.parent;
107
108 if (TARGET_NODE_TYPE.test(node.type) && node.body.type === "BlockStatement") {
109 if (parent.kind === "get") {
110 return true;
111 }
112 if (parent.type === "Property" && astUtils.getStaticPropertyName(parent) === "get" && parent.parent.type === "ObjectExpression") {
113
114 // Object.defineProperty()
115 if (parent.parent.parent.type === "CallExpression" &&
116 astUtils.getStaticPropertyName(parent.parent.parent.callee) === "defineProperty") {
117 return true;
118 }
119
120 // Object.defineProperties()
121 if (parent.parent.parent.type === "Property" &&
122 parent.parent.parent.parent.type === "ObjectExpression" &&
123 parent.parent.parent.parent.parent.type === "CallExpression" &&
124 astUtils.getStaticPropertyName(parent.parent.parent.parent.parent.callee) === "defineProperties") {
125 return true;
126 }
127 }
128 }
129 return false;
130 }
131 return {
132
133 // Stacks this function's information.
134 onCodePathStart(codePath, node) {
135 funcInfo = {
136 upper: funcInfo,
137 codePath,
138 hasReturn: false,
139 shouldCheck: isGetter(node),
140 node
141 };
142 },
143
144 // Pops this function's information.
145 onCodePathEnd() {
146 funcInfo = funcInfo.upper;
147 },
148
149 // Checks the return statement is valid.
150 ReturnStatement(node) {
151 if (funcInfo.shouldCheck) {
152 funcInfo.hasReturn = true;
153
154 // if allowImplicit: false, should also check node.argument
155 if (!options.allowImplicit && !node.argument) {
156 context.report({
157 node,
158 messageId: "expected",
159 data: {
160 name: astUtils.getFunctionNameWithKind(funcInfo.node)
161 }
162 });
163 }
164 }
165 },
166
167 // Reports a given function if the last path is reachable.
168 "FunctionExpression:exit": checkLastSegment,
169 "ArrowFunctionExpression:exit": checkLastSegment
170 };
171 }
172};