no-restricted-globals.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /**
  2. * @fileoverview Restrict usage of specified globals.
  3. * @author Benoît Zugmeyer
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Helpers
  8. //------------------------------------------------------------------------------
  9. const DEFAULT_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'.",
  10. CUSTOM_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'. {{customMessage}}";
  11. //------------------------------------------------------------------------------
  12. // Rule Definition
  13. //------------------------------------------------------------------------------
  14. module.exports = {
  15. meta: {
  16. docs: {
  17. description: "disallow specified global variables",
  18. category: "Variables",
  19. recommended: false,
  20. url: "https://eslint.org/docs/rules/no-restricted-globals"
  21. },
  22. schema: {
  23. type: "array",
  24. items: {
  25. oneOf: [
  26. {
  27. type: "string"
  28. },
  29. {
  30. type: "object",
  31. properties: {
  32. name: { type: "string" },
  33. message: { type: "string" }
  34. },
  35. required: ["name"],
  36. additionalProperties: false
  37. }
  38. ]
  39. },
  40. uniqueItems: true,
  41. minItems: 0
  42. }
  43. },
  44. create(context) {
  45. // If no globals are restricted, we don't need to do anything
  46. if (context.options.length === 0) {
  47. return {};
  48. }
  49. const restrictedGlobalMessages = context.options.reduce((memo, option) => {
  50. if (typeof option === "string") {
  51. memo[option] = null;
  52. } else {
  53. memo[option.name] = option.message;
  54. }
  55. return memo;
  56. }, {});
  57. /**
  58. * Report a variable to be used as a restricted global.
  59. * @param {Reference} reference the variable reference
  60. * @returns {void}
  61. * @private
  62. */
  63. function reportReference(reference) {
  64. const name = reference.identifier.name,
  65. customMessage = restrictedGlobalMessages[name],
  66. message = customMessage
  67. ? CUSTOM_MESSAGE_TEMPLATE
  68. : DEFAULT_MESSAGE_TEMPLATE;
  69. context.report({
  70. node: reference.identifier,
  71. message,
  72. data: {
  73. name,
  74. customMessage
  75. }
  76. });
  77. }
  78. /**
  79. * Check if the given name is a restricted global name.
  80. * @param {string} name name of a variable
  81. * @returns {boolean} whether the variable is a restricted global or not
  82. * @private
  83. */
  84. function isRestricted(name) {
  85. return restrictedGlobalMessages.hasOwnProperty(name);
  86. }
  87. return {
  88. Program() {
  89. const scope = context.getScope();
  90. // Report variables declared elsewhere (ex: variables defined as "global" by eslint)
  91. scope.variables.forEach(variable => {
  92. if (!variable.defs.length && isRestricted(variable.name)) {
  93. variable.references.forEach(reportReference);
  94. }
  95. });
  96. // Report variables not declared at all
  97. scope.through.forEach(reference => {
  98. if (isRestricted(reference.identifier.name)) {
  99. reportReference(reference);
  100. }
  101. });
  102. }
  103. };
  104. }
  105. };