Permalink
Cannot retrieve contributors at this time
| /** | |
| * @fileoverview Rule to disallow certain object properties | |
| * @author Will Klein & Eli White | |
| */ | |
| "use strict"; | |
| const astUtils = require("./utils/ast-utils"); | |
| //------------------------------------------------------------------------------ | |
| // Rule Definition | |
| //------------------------------------------------------------------------------ | |
| module.exports = { | |
| meta: { | |
| type: "suggestion", | |
| docs: { | |
| description: "disallow certain properties on certain objects", | |
| category: "Best Practices", | |
| recommended: false, | |
| url: "https://eslint.org/docs/rules/no-restricted-properties" | |
| }, | |
| schema: { | |
| type: "array", | |
| items: { | |
| anyOf: [ // `object` and `property` are both optional, but at least one of them must be provided. | |
| { | |
| type: "object", | |
| properties: { | |
| object: { | |
| type: "string" | |
| }, | |
| property: { | |
| type: "string" | |
| }, | |
| message: { | |
| type: "string" | |
| } | |
| }, | |
| additionalProperties: false, | |
| required: ["object"] | |
| }, | |
| { | |
| type: "object", | |
| properties: { | |
| object: { | |
| type: "string" | |
| }, | |
| property: { | |
| type: "string" | |
| }, | |
| message: { | |
| type: "string" | |
| } | |
| }, | |
| additionalProperties: false, | |
| required: ["property"] | |
| } | |
| ] | |
| }, | |
| uniqueItems: true | |
| } | |
| }, | |
| create(context) { | |
| const restrictedCalls = context.options; | |
| if (restrictedCalls.length === 0) { | |
| return {}; | |
| } | |
| const restrictedProperties = new Map(); | |
| const globallyRestrictedObjects = new Map(); | |
| const globallyRestrictedProperties = new Map(); | |
| restrictedCalls.forEach(option => { | |
| const objectName = option.object; | |
| const propertyName = option.property; | |
| if (typeof objectName === "undefined") { | |
| globallyRestrictedProperties.set(propertyName, { message: option.message }); | |
| } else if (typeof propertyName === "undefined") { | |
| globallyRestrictedObjects.set(objectName, { message: option.message }); | |
| } else { | |
| if (!restrictedProperties.has(objectName)) { | |
| restrictedProperties.set(objectName, new Map()); | |
| } | |
| restrictedProperties.get(objectName).set(propertyName, { | |
| message: option.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * Checks to see whether a property access is restricted, and reports it if so. | |
| * @param {ASTNode} node The node to report | |
| * @param {string} objectName The name of the object | |
| * @param {string} propertyName The name of the property | |
| * @returns {undefined} | |
| */ | |
| function checkPropertyAccess(node, objectName, propertyName) { | |
| if (propertyName === null) { | |
| return; | |
| } | |
| const matchedObject = restrictedProperties.get(objectName); | |
| const matchedObjectProperty = matchedObject ? matchedObject.get(propertyName) : globallyRestrictedObjects.get(objectName); | |
| const globalMatchedProperty = globallyRestrictedProperties.get(propertyName); | |
| if (matchedObjectProperty) { | |
| const message = matchedObjectProperty.message ? ` ${matchedObjectProperty.message}` : ""; | |
| context.report({ | |
| node, | |
| // eslint-disable-next-line eslint-plugin/report-message-format | |
| message: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", | |
| data: { | |
| objectName, | |
| propertyName, | |
| message | |
| } | |
| }); | |
| } else if (globalMatchedProperty) { | |
| const message = globalMatchedProperty.message ? ` ${globalMatchedProperty.message}` : ""; | |
| context.report({ | |
| node, | |
| // eslint-disable-next-line eslint-plugin/report-message-format | |
| message: "'{{propertyName}}' is restricted from being used.{{message}}", | |
| data: { | |
| propertyName, | |
| message | |
| } | |
| }); | |
| } | |
| } | |
| /** | |
| * Checks property accesses in a destructuring assignment expression, e.g. `var foo; ({foo} = bar);` | |
| * @param {ASTNode} node An AssignmentExpression or AssignmentPattern node | |
| * @returns {undefined} | |
| */ | |
| function checkDestructuringAssignment(node) { | |
| if (node.right.type === "Identifier") { | |
| const objectName = node.right.name; | |
| if (node.left.type === "ObjectPattern") { | |
| node.left.properties.forEach(property => { | |
| checkPropertyAccess(node.left, objectName, astUtils.getStaticPropertyName(property)); | |
| }); | |
| } | |
| } | |
| } | |
| return { | |
| MemberExpression(node) { | |
| checkPropertyAccess(node, node.object && node.object.name, astUtils.getStaticPropertyName(node)); | |
| }, | |
| VariableDeclarator(node) { | |
| if (node.init && node.init.type === "Identifier") { | |
| const objectName = node.init.name; | |
| if (node.id.type === "ObjectPattern") { | |
| node.id.properties.forEach(property => { | |
| checkPropertyAccess(node.id, objectName, astUtils.getStaticPropertyName(property)); | |
| }); | |
| } | |
| } | |
| }, | |
| AssignmentExpression: checkDestructuringAssignment, | |
| AssignmentPattern: checkDestructuringAssignment | |
| }; | |
| } | |
| }; |