UNPKG

5.22 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 node = node.parent.parent;
62
63 return node.type === "ObjectExpression" && (
64 isArgumentOfMethodCall(node, 1, "Object", "create") ||
65 isArgumentOfMethodCall(node, 1, "Object", "defineProperties")
66 );
67}
68
69//------------------------------------------------------------------------------
70// Rule Definition
71//------------------------------------------------------------------------------
72
73module.exports = {
74 meta: {
75 docs: {
76 description: "enforce getter and setter pairs in objects",
77 category: "Best Practices",
78 recommended: false,
79 url: "https://eslint.org/docs/rules/accessor-pairs"
80 },
81 schema: [{
82 type: "object",
83 properties: {
84 getWithoutSet: {
85 type: "boolean"
86 },
87 setWithoutGet: {
88 type: "boolean"
89 }
90 },
91 additionalProperties: false
92 }],
93 messages: {
94 getter: "Getter is not present.",
95 setter: "Setter is not present."
96 }
97 },
98 create(context) {
99 const config = context.options[0] || {};
100 const checkGetWithoutSet = config.getWithoutSet === true;
101 const checkSetWithoutGet = config.setWithoutGet !== false;
102
103 /**
104 * Checks a object expression to see if it has setter and getter both present or none.
105 * @param {ASTNode} node The node to check.
106 * @returns {void}
107 * @private
108 */
109 function checkLonelySetGet(node) {
110 let isSetPresent = false;
111 let isGetPresent = false;
112 const isDescriptor = isPropertyDescriptor(node);
113
114 for (let i = 0, end = node.properties.length; i < end; i++) {
115 const property = node.properties[i];
116
117 let propToCheck = "";
118
119 if (property.kind === "init") {
120 if (isDescriptor && !property.computed) {
121 propToCheck = property.key.name;
122 }
123 } else {
124 propToCheck = property.kind;
125 }
126
127 switch (propToCheck) {
128 case "set":
129 isSetPresent = true;
130 break;
131
132 case "get":
133 isGetPresent = true;
134 break;
135
136 default:
137
138 // Do nothing
139 }
140
141 if (isSetPresent && isGetPresent) {
142 break;
143 }
144 }
145
146 if (checkSetWithoutGet && isSetPresent && !isGetPresent) {
147 context.report({ node, messageId: "getter" });
148 } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) {
149 context.report({ node, messageId: "setter" });
150 }
151 }
152
153 return {
154 ObjectExpression(node) {
155 if (checkSetWithoutGet || checkGetWithoutSet) {
156 checkLonelySetGet(node);
157 }
158 }
159 };
160 }
161};