1/** 2 * @fileoverview Rule to disallow assignments to native objects or read-only global variables 3 * @author Ilya Volodin 4 */ 5 6"use strict"; 7 8//------------------------------------------------------------------------------ 9// Rule Definition 10//------------------------------------------------------------------------------ 11 12module.exports = { 13 meta: { 14 type: "suggestion", 15 16 docs: { 17 description: "disallow assignments to native objects or read-only global variables", 18 category: "Best Practices", 19 recommended: true, 20 url: "https://eslint.org/docs/rules/no-global-assign" 21 }, 22 23 schema: [ 24 { 25 type: "object", 26 properties: { 27 exceptions: { 28 type: "array", 29 items: { type: "string" }, 30 uniqueItems: true 31 } 32 }, 33 additionalProperties: false 34 } 35 ], 36 37 messages: { 38 globalShouldNotBeModified: "Read-only global '{{name}}' should not be modified." 39 } 40 }, 41 42 create(context) { 43 const config = context.options[0]; 44 const exceptions = (config && config.exceptions) || []; 45 46 /** 47 * Reports write references. 48 * @param {Reference} reference A reference to check. 49 * @param {int} index The index of the reference in the references. 50 * @param {Reference[]} references The array that the reference belongs to. 51 * @returns {void} 52 */ 53 function checkReference(reference, index, references) { 54 const identifier = reference.identifier; 55 56 if (reference.init === false && 57 reference.isWrite() && 58 59 /* 60 * Destructuring assignments can have multiple default value, 61 * so possibly there are multiple writeable references for the same identifier. 62 */ 63 (index === 0 || references[index - 1].identifier !== identifier) 64 ) { 65 context.report({ 66 node: identifier, 67 messageId: "globalShouldNotBeModified", 68 data: { 69 name: identifier.name 70 } 71 }); 72 } 73 } 74 75 /** 76 * Reports write references if a given variable is read-only builtin. 77 * @param {Variable} variable A variable to check. 78 * @returns {void} 79 */ 80 function checkVariable(variable) { 81 if (variable.writeable === false && exceptions.indexOf(variable.name) === -1) { 82 variable.references.forEach(checkReference); 83 } 84 } 85 86 return { 87 Program() { 88 const globalScope = context.getScope(); 89 90 globalScope.variables.forEach(checkVariable); 91 } 92 }; 93 } 94}; 95