• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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