no-global-assign.js 2.4 KB

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