no-console.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**
  2. * @fileoverview Rule to flag use of console object
  3. * @author Nicholas C. Zakas
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("./utils/ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Rule Definition
  12. //------------------------------------------------------------------------------
  13. /** @type {import('../shared/types').Rule} */
  14. module.exports = {
  15. meta: {
  16. type: "suggestion",
  17. docs: {
  18. description: "Disallow the use of `console`",
  19. recommended: false,
  20. url: "https://eslint.org/docs/latest/rules/no-console"
  21. },
  22. schema: [
  23. {
  24. type: "object",
  25. properties: {
  26. allow: {
  27. type: "array",
  28. items: {
  29. type: "string"
  30. },
  31. minItems: 1,
  32. uniqueItems: true
  33. }
  34. },
  35. additionalProperties: false
  36. }
  37. ],
  38. messages: {
  39. unexpected: "Unexpected console statement."
  40. }
  41. },
  42. create(context) {
  43. const options = context.options[0] || {};
  44. const allowed = options.allow || [];
  45. const sourceCode = context.sourceCode;
  46. /**
  47. * Checks whether the given reference is 'console' or not.
  48. * @param {eslint-scope.Reference} reference The reference to check.
  49. * @returns {boolean} `true` if the reference is 'console'.
  50. */
  51. function isConsole(reference) {
  52. const id = reference.identifier;
  53. return id && id.name === "console";
  54. }
  55. /**
  56. * Checks whether the property name of the given MemberExpression node
  57. * is allowed by options or not.
  58. * @param {ASTNode} node The MemberExpression node to check.
  59. * @returns {boolean} `true` if the property name of the node is allowed.
  60. */
  61. function isAllowed(node) {
  62. const propertyName = astUtils.getStaticPropertyName(node);
  63. return propertyName && allowed.includes(propertyName);
  64. }
  65. /**
  66. * Checks whether the given reference is a member access which is not
  67. * allowed by options or not.
  68. * @param {eslint-scope.Reference} reference The reference to check.
  69. * @returns {boolean} `true` if the reference is a member access which
  70. * is not allowed by options.
  71. */
  72. function isMemberAccessExceptAllowed(reference) {
  73. const node = reference.identifier;
  74. const parent = node.parent;
  75. return (
  76. parent.type === "MemberExpression" &&
  77. parent.object === node &&
  78. !isAllowed(parent)
  79. );
  80. }
  81. /**
  82. * Reports the given reference as a violation.
  83. * @param {eslint-scope.Reference} reference The reference to report.
  84. * @returns {void}
  85. */
  86. function report(reference) {
  87. const node = reference.identifier.parent;
  88. context.report({
  89. node,
  90. loc: node.loc,
  91. messageId: "unexpected"
  92. });
  93. }
  94. return {
  95. "Program:exit"(node) {
  96. const scope = sourceCode.getScope(node);
  97. const consoleVar = astUtils.getVariableByName(scope, "console");
  98. const shadowed = consoleVar && consoleVar.defs.length > 0;
  99. /*
  100. * 'scope.through' includes all references to undefined
  101. * variables. If the variable 'console' is not defined, it uses
  102. * 'scope.through'.
  103. */
  104. const references = consoleVar
  105. ? consoleVar.references
  106. : scope.through.filter(isConsole);
  107. if (!shadowed) {
  108. references
  109. .filter(isMemberAccessExceptAllowed)
  110. .forEach(report);
  111. }
  112. }
  113. };
  114. }
  115. };