no-global-assign.js 2.9 KB

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