No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

no-warning-comments.js 5.4 KiB

hace 3 años
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /**
  2. * @fileoverview Rule that warns about used warning comments
  3. * @author Alexander Schmidt <https://github.com/lxanders>
  4. */
  5. "use strict";
  6. const astUtils = require("../util/ast-utils");
  7. //------------------------------------------------------------------------------
  8. // Rule Definition
  9. //------------------------------------------------------------------------------
  10. module.exports = {
  11. meta: {
  12. docs: {
  13. description: "disallow specified warning terms in comments",
  14. category: "Best Practices",
  15. recommended: false,
  16. url: "https://eslint.org/docs/rules/no-warning-comments"
  17. },
  18. schema: [
  19. {
  20. type: "object",
  21. properties: {
  22. terms: {
  23. type: "array",
  24. items: {
  25. type: "string"
  26. }
  27. },
  28. location: {
  29. enum: ["start", "anywhere"]
  30. }
  31. },
  32. additionalProperties: false
  33. }
  34. ]
  35. },
  36. create(context) {
  37. const sourceCode = context.getSourceCode(),
  38. configuration = context.options[0] || {},
  39. warningTerms = configuration.terms || ["todo", "fixme", "xxx"],
  40. location = configuration.location || "start",
  41. selfConfigRegEx = /\bno-warning-comments\b/;
  42. /**
  43. * Convert a warning term into a RegExp which will match a comment containing that whole word in the specified
  44. * location ("start" or "anywhere"). If the term starts or ends with non word characters, then the match will not
  45. * require word boundaries on that side.
  46. *
  47. * @param {string} term A term to convert to a RegExp
  48. * @returns {RegExp} The term converted to a RegExp
  49. */
  50. function convertToRegExp(term) {
  51. const escaped = term.replace(/[-/\\$^*+?.()|[\]{}]/g, "\\$&");
  52. const wordBoundary = "\\b";
  53. const eitherOrWordBoundary = `|${wordBoundary}`;
  54. let prefix;
  55. /*
  56. * If the term ends in a word character (a-z0-9_), ensure a word
  57. * boundary at the end, so that substrings do not get falsely
  58. * matched. eg "todo" in a string such as "mastodon".
  59. * If the term ends in a non-word character, then \b won't match on
  60. * the boundary to the next non-word character, which would likely
  61. * be a space. For example `/\bFIX!\b/.test('FIX! blah') === false`.
  62. * In these cases, use no bounding match. Same applies for the
  63. * prefix, handled below.
  64. */
  65. const suffix = /\w$/.test(term) ? "\\b" : "";
  66. if (location === "start") {
  67. /*
  68. * When matching at the start, ignore leading whitespace, and
  69. * there's no need to worry about word boundaries.
  70. */
  71. prefix = "^\\s*";
  72. } else if (/^\w/.test(term)) {
  73. prefix = wordBoundary;
  74. } else {
  75. prefix = "";
  76. }
  77. if (location === "start") {
  78. /*
  79. * For location "start" the regex should be
  80. * ^\s*TERM\b. This checks the word boundary
  81. * at the beginning of the comment.
  82. */
  83. return new RegExp(prefix + escaped + suffix, "i");
  84. }
  85. /*
  86. * For location "anywhere" the regex should be
  87. * \bTERM\b|\bTERM\b, this checks the entire comment
  88. * for the term.
  89. */
  90. return new RegExp(prefix + escaped + suffix + eitherOrWordBoundary + term + wordBoundary, "i");
  91. }
  92. const warningRegExps = warningTerms.map(convertToRegExp);
  93. /**
  94. * Checks the specified comment for matches of the configured warning terms and returns the matches.
  95. * @param {string} comment The comment which is checked.
  96. * @returns {Array} All matched warning terms for this comment.
  97. */
  98. function commentContainsWarningTerm(comment) {
  99. const matches = [];
  100. warningRegExps.forEach((regex, index) => {
  101. if (regex.test(comment)) {
  102. matches.push(warningTerms[index]);
  103. }
  104. });
  105. return matches;
  106. }
  107. /**
  108. * Checks the specified node for matching warning comments and reports them.
  109. * @param {ASTNode} node The AST node being checked.
  110. * @returns {void} undefined.
  111. */
  112. function checkComment(node) {
  113. if (astUtils.isDirectiveComment(node) && selfConfigRegEx.test(node.value)) {
  114. return;
  115. }
  116. const matches = commentContainsWarningTerm(node.value);
  117. matches.forEach(matchedTerm => {
  118. context.report({
  119. node,
  120. message: "Unexpected '{{matchedTerm}}' comment.",
  121. data: {
  122. matchedTerm
  123. }
  124. });
  125. });
  126. }
  127. return {
  128. Program() {
  129. const comments = sourceCode.getAllComments();
  130. comments.filter(token => token.type !== "Shebang").forEach(checkComment);
  131. }
  132. };
  133. }
  134. };