UNPKG

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