UNPKG

5.36 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag wrapping non-iife in parens
3 * @author Gyandeep Singh
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Helpers
10//------------------------------------------------------------------------------
11
12/**
13 * Checks whether or not a given node is an `Identifier` node which was named a given name.
14 * @param {ASTNode} node - A node to check.
15 * @param {string} name - An expected name of the node.
16 * @returns {boolean} `true` if the node is an `Identifier` node which was named as expected.
17 */
18function isIdentifier(node, name) {
19 return node.type === "Identifier" && node.name === name;
20}
21
22/**
23 * Checks whether or not a given node is an argument of a specified method call.
24 * @param {ASTNode} node - A node to check.
25 * @param {number} index - An expected index of the node in arguments.
26 * @param {string} object - An expected name of the object of the method.
27 * @param {string} property - An expected name of the method.
28 * @returns {boolean} `true` if the node is an argument of the specified method call.
29 */
30function isArgumentOfMethodCall(node, index, object, property) {
31 const parent = node.parent;
32
33 return (
34 parent.type === "CallExpression" &&
35 parent.callee.type === "MemberExpression" &&
36 parent.callee.computed === false &&
37 isIdentifier(parent.callee.object, object) &&
38 isIdentifier(parent.callee.property, property) &&
39 parent.arguments[index] === node
40 );
41}
42
43/**
44 * Checks whether or not a given node is a property descriptor.
45 * @param {ASTNode} node - A node to check.
46 * @returns {boolean} `true` if the node is a property descriptor.
47 */
48function isPropertyDescriptor(node) {
49
50 // Object.defineProperty(obj, "foo", {set: ...})
51 if (isArgumentOfMethodCall(node, 2, "Object", "defineProperty") ||
52 isArgumentOfMethodCall(node, 2, "Reflect", "defineProperty")
53 ) {
54 return true;
55 }
56
57 /*
58 * Object.defineProperties(obj, {foo: {set: ...}})
59 * Object.create(proto, {foo: {set: ...}})
60 */
61 const grandparent = node.parent.parent;
62
63 return grandparent.type === "ObjectExpression" && (
64 isArgumentOfMethodCall(grandparent, 1, "Object", "create") ||
65 isArgumentOfMethodCall(grandparent, 1, "Object", "defineProperties")
66 );
67}
68
69//------------------------------------------------------------------------------
70// Rule Definition
71//------------------------------------------------------------------------------
72
73module.exports = {
74 meta: {
75 type: "suggestion",
76
77 docs: {
78 description: "enforce getter and setter pairs in objects",
79 category: "Best Practices",
80 recommended: false,
81 url: "https://eslint.org/docs/rules/accessor-pairs"
82 },
83
84 schema: [{
85 type: "object",
86 properties: {
87 getWithoutSet: {
88 type: "boolean",
89 default: false
90 },
91 setWithoutGet: {
92 type: "boolean",
93 default: true
94 }
95 },
96 additionalProperties: false
97 }],
98
99 messages: {
100 getter: "Getter is not present.",
101 setter: "Setter is not present."
102 }
103 },
104 create(context) {
105 const config = context.options[0] || {};
106 const checkGetWithoutSet = config.getWithoutSet === true;
107 const checkSetWithoutGet = config.setWithoutGet !== false;
108
109 /**
110 * Checks a object expression to see if it has setter and getter both present or none.
111 * @param {ASTNode} node The node to check.
112 * @returns {void}
113 * @private
114 */
115 function checkLonelySetGet(node) {
116 let isSetPresent = false;
117 let isGetPresent = false;
118 const isDescriptor = isPropertyDescriptor(node);
119
120 for (let i = 0, end = node.properties.length; i < end; i++) {
121 const property = node.properties[i];
122
123 let propToCheck = "";
124
125 if (property.kind === "init") {
126 if (isDescriptor && !property.computed) {
127 propToCheck = property.key.name;
128 }
129 } else {
130 propToCheck = property.kind;
131 }
132
133 switch (propToCheck) {
134 case "set":
135 isSetPresent = true;
136 break;
137
138 case "get":
139 isGetPresent = true;
140 break;
141
142 default:
143
144 // Do nothing
145 }
146
147 if (isSetPresent && isGetPresent) {
148 break;
149 }
150 }
151
152 if (checkSetWithoutGet && isSetPresent && !isGetPresent) {
153 context.report({ node, messageId: "getter" });
154 } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) {
155 context.report({ node, messageId: "setter" });
156 }
157 }
158
159 return {
160 ObjectExpression(node) {
161 if (checkSetWithoutGet || checkGetWithoutSet) {
162 checkLonelySetGet(node);
163 }
164 }
165 };
166 }
167};