no-console.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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/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. /**
  46. * Checks whether the given reference is 'console' or not.
  47. * @param {eslint-scope.Reference} reference The reference to check.
  48. * @returns {boolean} `true` if the reference is 'console'.
  49. */
  50. function isConsole(reference) {
  51. const id = reference.identifier;
  52. return id && id.name === "console";
  53. }
  54. /**
  55. * Checks whether the property name of the given MemberExpression node
  56. * is allowed by options or not.
  57. * @param {ASTNode} node The MemberExpression node to check.
  58. * @returns {boolean} `true` if the property name of the node is allowed.
  59. */
  60. function isAllowed(node) {
  61. const propertyName = astUtils.getStaticPropertyName(node);
  62. return propertyName && allowed.includes(propertyName);
  63. }
  64. /**
  65. * Checks whether the given reference is a member access which is not
  66. * allowed by options or not.
  67. * @param {eslint-scope.Reference} reference The reference to check.
  68. * @returns {boolean} `true` if the reference is a member access which
  69. * is not allowed by options.
  70. */
  71. function isMemberAccessExceptAllowed(reference) {
  72. const node = reference.identifier;
  73. const parent = node.parent;
  74. return (
  75. parent.type === "MemberExpression" &&
  76. parent.object === node &&
  77. !isAllowed(parent)
  78. );
  79. }
  80. /**
  81. * Reports the given reference as a violation.
  82. * @param {eslint-scope.Reference} reference The reference to report.
  83. * @returns {void}
  84. */
  85. function report(reference) {
  86. const node = reference.identifier.parent;
  87. context.report({
  88. node,
  89. loc: node.loc,
  90. messageId: "unexpected"
  91. });
  92. }
  93. return {
  94. "Program:exit"() {
  95. const scope = context.getScope();
  96. const consoleVar = astUtils.getVariableByName(scope, "console");
  97. const shadowed = consoleVar && consoleVar.defs.length > 0;
  98. /*
  99. * 'scope.through' includes all references to undefined
  100. * variables. If the variable 'console' is not defined, it uses
  101. * 'scope.through'.
  102. */
  103. const references = consoleVar
  104. ? consoleVar.references
  105. : scope.through.filter(isConsole);
  106. if (!shadowed) {
  107. references
  108. .filter(isMemberAccessExceptAllowed)
  109. .forEach(report);
  110. }
  111. }
  112. };
  113. }
  114. };