UNPKG

4.32 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to suggest using "Reflect" api over Function/Object methods
3 * @author Keith Cirkel <http://keithcirkel.co.uk>
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Rule Definition
9//------------------------------------------------------------------------------
10
11module.exports = {
12 meta: {
13 docs: {
14 description: "require `Reflect` methods where applicable",
15 category: "ECMAScript 6",
16 recommended: false
17 },
18
19 schema: [
20 {
21 type: "object",
22 properties: {
23 exceptions: {
24 type: "array",
25 items: {
26 enum: [
27 "apply",
28 "call",
29 "delete",
30 "defineProperty",
31 "getOwnPropertyDescriptor",
32 "getPrototypeOf",
33 "setPrototypeOf",
34 "isExtensible",
35 "getOwnPropertyNames",
36 "preventExtensions"
37 ]
38 },
39 uniqueItems: true
40 }
41 },
42 additionalProperties: false
43 }
44 ]
45 },
46
47 create(context) {
48 const existingNames = {
49 apply: "Function.prototype.apply",
50 call: "Function.prototype.call",
51 defineProperty: "Object.defineProperty",
52 getOwnPropertyDescriptor: "Object.getOwnPropertyDescriptor",
53 getPrototypeOf: "Object.getPrototypeOf",
54 setPrototypeOf: "Object.setPrototypeOf",
55 isExtensible: "Object.isExtensible",
56 getOwnPropertyNames: "Object.getOwnPropertyNames",
57 preventExtensions: "Object.preventExtensions"
58 };
59
60 const reflectSubsitutes = {
61 apply: "Reflect.apply",
62 call: "Reflect.apply",
63 defineProperty: "Reflect.defineProperty",
64 getOwnPropertyDescriptor: "Reflect.getOwnPropertyDescriptor",
65 getPrototypeOf: "Reflect.getPrototypeOf",
66 setPrototypeOf: "Reflect.setPrototypeOf",
67 isExtensible: "Reflect.isExtensible",
68 getOwnPropertyNames: "Reflect.getOwnPropertyNames",
69 preventExtensions: "Reflect.preventExtensions"
70 };
71
72 const exceptions = (context.options[0] || {}).exceptions || [];
73
74 /**
75 * Reports the Reflect violation based on the `existing` and `substitute`
76 * @param {Object} node The node that violates the rule.
77 * @param {string} existing The existing method name that has been used.
78 * @param {string} substitute The Reflect substitute that should be used.
79 * @returns {void}
80 */
81 function report(node, existing, substitute) {
82 context.report(node, "Avoid using {{existing}}, instead use {{substitute}}.", {
83 existing,
84 substitute
85 });
86 }
87
88 return {
89 CallExpression(node) {
90 const methodName = (node.callee.property || {}).name;
91 const isReflectCall = (node.callee.object || {}).name === "Reflect";
92 const hasReflectSubsitute = reflectSubsitutes.hasOwnProperty(methodName);
93 const userConfiguredException = exceptions.indexOf(methodName) !== -1;
94
95 if (hasReflectSubsitute && !isReflectCall && !userConfiguredException) {
96 report(node, existingNames[methodName], reflectSubsitutes[methodName]);
97 }
98 },
99 UnaryExpression(node) {
100 const isDeleteOperator = node.operator === "delete";
101 const targetsIdentifier = node.argument.type === "Identifier";
102 const userConfiguredException = exceptions.indexOf("delete") !== -1;
103
104 if (isDeleteOperator && !targetsIdentifier && !userConfiguredException) {
105 report(node, "the delete keyword", "Reflect.deleteProperty");
106 }
107 }
108 };
109
110 }
111};