no-empty-character-class.js 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /**
  2. * @fileoverview Rule to flag the use of empty character classes in regular expressions
  3. * @author Ian Christian Myers
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. const parser = new RegExpParser();
  14. const QUICK_TEST_REGEX = /\[\]/u;
  15. //------------------------------------------------------------------------------
  16. // Rule Definition
  17. //------------------------------------------------------------------------------
  18. /** @type {import('../types').Rule.RuleModule} */
  19. module.exports = {
  20. meta: {
  21. type: "problem",
  22. docs: {
  23. description:
  24. "Disallow empty character classes in regular expressions",
  25. recommended: true,
  26. url: "https://eslint.org/docs/latest/rules/no-empty-character-class",
  27. },
  28. schema: [],
  29. messages: {
  30. unexpected: "Empty class.",
  31. },
  32. },
  33. create(context) {
  34. return {
  35. "Literal[regex]"(node) {
  36. const { pattern, flags } = node.regex;
  37. if (!QUICK_TEST_REGEX.test(pattern)) {
  38. return;
  39. }
  40. let regExpAST;
  41. try {
  42. regExpAST = parser.parsePattern(
  43. pattern,
  44. 0,
  45. pattern.length,
  46. {
  47. unicode: flags.includes("u"),
  48. unicodeSets: flags.includes("v"),
  49. },
  50. );
  51. } catch {
  52. // Ignore regular expressions that regexpp cannot parse
  53. return;
  54. }
  55. visitRegExpAST(regExpAST, {
  56. onCharacterClassEnter(characterClass) {
  57. if (
  58. !characterClass.negate &&
  59. characterClass.elements.length === 0
  60. ) {
  61. context.report({ node, messageId: "unexpected" });
  62. }
  63. },
  64. });
  65. },
  66. };
  67. },
  68. };