2 * @fileoverview Rule to disallow certain object properties
3 * @author Will Klein & Eli White
8 const astUtils = require("./utils/ast-utils");
10 //------------------------------------------------------------------------------
12 //------------------------------------------------------------------------------
19 description: "disallow certain properties on certain objects",
20 category: "Best Practices",
22 url: "https://eslint.org/docs/rules/no-restricted-properties"
28 anyOf: [ // `object` and `property` are both optional, but at least one of them must be provided.
42 additionalProperties: false,
58 additionalProperties: false,
59 required: ["property"]
67 // eslint-disable-next-line eslint-plugin/report-message-format
68 restrictedObjectProperty: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}",
69 // eslint-disable-next-line eslint-plugin/report-message-format
70 restrictedProperty: "'{{propertyName}}' is restricted from being used.{{message}}"
75 const restrictedCalls = context.options;
77 if (restrictedCalls.length === 0) {
81 const restrictedProperties = new Map();
82 const globallyRestrictedObjects = new Map();
83 const globallyRestrictedProperties = new Map();
85 restrictedCalls.forEach(option => {
86 const objectName = option.object;
87 const propertyName = option.property;
89 if (typeof objectName === "undefined") {
90 globallyRestrictedProperties.set(propertyName, { message: option.message });
91 } else if (typeof propertyName === "undefined") {
92 globallyRestrictedObjects.set(objectName, { message: option.message });
94 if (!restrictedProperties.has(objectName)) {
95 restrictedProperties.set(objectName, new Map());
98 restrictedProperties.get(objectName).set(propertyName, {
99 message: option.message
105 * Checks to see whether a property access is restricted, and reports it if so.
106 * @param {ASTNode} node The node to report
107 * @param {string} objectName The name of the object
108 * @param {string} propertyName The name of the property
109 * @returns {undefined}
111 function checkPropertyAccess(node, objectName, propertyName) {
112 if (propertyName === null) {
115 const matchedObject = restrictedProperties.get(objectName);
116 const matchedObjectProperty = matchedObject ? matchedObject.get(propertyName) : globallyRestrictedObjects.get(objectName);
117 const globalMatchedProperty = globallyRestrictedProperties.get(propertyName);
119 if (matchedObjectProperty) {
120 const message = matchedObjectProperty.message ? ` ${matchedObjectProperty.message}` : "";
124 messageId: "restrictedObjectProperty",
131 } else if (globalMatchedProperty) {
132 const message = globalMatchedProperty.message ? ` ${globalMatchedProperty.message}` : "";
136 messageId: "restrictedProperty",
146 * Checks property accesses in a destructuring assignment expression, e.g. `var foo; ({foo} = bar);`
147 * @param {ASTNode} node An AssignmentExpression or AssignmentPattern node
148 * @returns {undefined}
150 function checkDestructuringAssignment(node) {
151 if (node.right.type === "Identifier") {
152 const objectName = node.right.name;
154 if (node.left.type === "ObjectPattern") {
155 node.left.properties.forEach(property => {
156 checkPropertyAccess(node.left, objectName, astUtils.getStaticPropertyName(property));
163 MemberExpression(node) {
164 checkPropertyAccess(node, node.object && node.object.name, astUtils.getStaticPropertyName(node));
166 VariableDeclarator(node) {
167 if (node.init && node.init.type === "Identifier") {
168 const objectName = node.init.name;
170 if (node.id.type === "ObjectPattern") {
171 node.id.properties.forEach(property => {
172 checkPropertyAccess(node.id, objectName, astUtils.getStaticPropertyName(property));
177 AssignmentExpression: checkDestructuringAssignment,
178 AssignmentPattern: checkDestructuringAssignment