UNPKG

5.04 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 },
80 schema: [{
81 type: "object",
82 properties: {
83 getWithoutSet: {
84 type: "boolean"
85 },
86 setWithoutGet: {
87 type: "boolean"
88 }
89 },
90 additionalProperties: false
91 }]
92 },
93 create(context) {
94 const config = context.options[0] || {};
95 const checkGetWithoutSet = config.getWithoutSet === true;
96 const checkSetWithoutGet = config.setWithoutGet !== false;
97
98 /**
99 * Checks a object expression to see if it has setter and getter both present or none.
100 * @param {ASTNode} node The node to check.
101 * @returns {void}
102 * @private
103 */
104 function checkLonelySetGet(node) {
105 let isSetPresent = false;
106 let isGetPresent = false;
107 const isDescriptor = isPropertyDescriptor(node);
108
109 for (let i = 0, end = node.properties.length; i < end; i++) {
110 const property = node.properties[i];
111
112 let propToCheck = "";
113
114 if (property.kind === "init") {
115 if (isDescriptor && !property.computed) {
116 propToCheck = property.key.name;
117 }
118 } else {
119 propToCheck = property.kind;
120 }
121
122 switch (propToCheck) {
123 case "set":
124 isSetPresent = true;
125 break;
126
127 case "get":
128 isGetPresent = true;
129 break;
130
131 default:
132
133 // Do nothing
134 }
135
136 if (isSetPresent && isGetPresent) {
137 break;
138 }
139 }
140
141 if (checkSetWithoutGet && isSetPresent && !isGetPresent) {
142 context.report(node, "Getter is not present.");
143 } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) {
144 context.report(node, "Setter is not present.");
145 }
146 }
147
148 return {
149 ObjectExpression(node) {
150 if (checkSetWithoutGet || checkGetWithoutSet) {
151 checkLonelySetGet(node);
152 }
153 }
154 };
155 }
156};