Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

no-misleading-character-class.js 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /**
  2. * @author Toru Nagashima <https://github.com/mysticatea>
  3. */
  4. "use strict";
  5. const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("eslint-utils");
  6. const { RegExpParser, visitRegExpAST } = require("regexpp");
  7. const { isCombiningCharacter, isEmojiModifier, isRegionalIndicatorSymbol, isSurrogatePair } = require("../util/unicode");
  8. //------------------------------------------------------------------------------
  9. // Helpers
  10. //------------------------------------------------------------------------------
  11. /**
  12. * Iterate character sequences of a given nodes.
  13. *
  14. * CharacterClassRange syntax can steal a part of character sequence,
  15. * so this function reverts CharacterClassRange syntax and restore the sequence.
  16. *
  17. * @param {regexpp.AST.CharacterClassElement[]} nodes The node list to iterate character sequences.
  18. * @returns {IterableIterator<number[]>} The list of character sequences.
  19. */
  20. function *iterateCharacterSequence(nodes) {
  21. let seq = [];
  22. for (const node of nodes) {
  23. switch (node.type) {
  24. case "Character":
  25. seq.push(node.value);
  26. break;
  27. case "CharacterClassRange":
  28. seq.push(node.min.value);
  29. yield seq;
  30. seq = [node.max.value];
  31. break;
  32. case "CharacterSet":
  33. if (seq.length > 0) {
  34. yield seq;
  35. seq = [];
  36. }
  37. break;
  38. // no default
  39. }
  40. }
  41. if (seq.length > 0) {
  42. yield seq;
  43. }
  44. }
  45. const hasCharacterSequence = {
  46. surrogatePairWithoutUFlag(chars) {
  47. return chars.some((c, i) => i !== 0 && isSurrogatePair(chars[i - 1], c));
  48. },
  49. combiningClass(chars) {
  50. return chars.some((c, i) => (
  51. i !== 0 &&
  52. isCombiningCharacter(c) &&
  53. !isCombiningCharacter(chars[i - 1])
  54. ));
  55. },
  56. emojiModifier(chars) {
  57. return chars.some((c, i) => (
  58. i !== 0 &&
  59. isEmojiModifier(c) &&
  60. !isEmojiModifier(chars[i - 1])
  61. ));
  62. },
  63. regionalIndicatorSymbol(chars) {
  64. return chars.some((c, i) => (
  65. i !== 0 &&
  66. isRegionalIndicatorSymbol(c) &&
  67. isRegionalIndicatorSymbol(chars[i - 1])
  68. ));
  69. },
  70. zwj(chars) {
  71. const lastIndex = chars.length - 1;
  72. return chars.some((c, i) => (
  73. i !== 0 &&
  74. i !== lastIndex &&
  75. c === 0x200d &&
  76. chars[i - 1] !== 0x200d &&
  77. chars[i + 1] !== 0x200d
  78. ));
  79. }
  80. };
  81. const kinds = Object.keys(hasCharacterSequence);
  82. //------------------------------------------------------------------------------
  83. // Rule Definition
  84. //------------------------------------------------------------------------------
  85. module.exports = {
  86. meta: {
  87. type: "problem",
  88. docs: {
  89. description: "disallow characters which are made with multiple code points in character class syntax",
  90. category: "Possible Errors",
  91. recommended: false,
  92. url: "https://eslint.org/docs/rules/no-misleading-character-class"
  93. },
  94. schema: [],
  95. messages: {
  96. surrogatePairWithoutUFlag: "Unexpected surrogate pair in character class. Use 'u' flag.",
  97. combiningClass: "Unexpected combined character in character class.",
  98. emojiModifier: "Unexpected modified Emoji in character class.",
  99. regionalIndicatorSymbol: "Unexpected national flag in character class.",
  100. zwj: "Unexpected joined character sequence in character class."
  101. }
  102. },
  103. create(context) {
  104. const parser = new RegExpParser();
  105. /**
  106. * Verify a given regular expression.
  107. * @param {Node} node The node to report.
  108. * @param {string} pattern The regular expression pattern to verify.
  109. * @param {string} flags The flags of the regular expression.
  110. * @returns {void}
  111. */
  112. function verify(node, pattern, flags) {
  113. const patternNode = parser.parsePattern(
  114. pattern,
  115. 0,
  116. pattern.length,
  117. flags.includes("u")
  118. );
  119. const has = {
  120. surrogatePairWithoutUFlag: false,
  121. combiningClass: false,
  122. variationSelector: false,
  123. emojiModifier: false,
  124. regionalIndicatorSymbol: false,
  125. zwj: false
  126. };
  127. visitRegExpAST(patternNode, {
  128. onCharacterClassEnter(ccNode) {
  129. for (const chars of iterateCharacterSequence(ccNode.elements)) {
  130. for (const kind of kinds) {
  131. has[kind] = has[kind] || hasCharacterSequence[kind](chars);
  132. }
  133. }
  134. }
  135. });
  136. for (const kind of kinds) {
  137. if (has[kind]) {
  138. context.report({ node, messageId: kind });
  139. }
  140. }
  141. }
  142. return {
  143. "Literal[regex]"(node) {
  144. verify(node, node.regex.pattern, node.regex.flags);
  145. },
  146. "Program"() {
  147. const scope = context.getScope();
  148. const tracker = new ReferenceTracker(scope);
  149. /*
  150. * Iterate calls of RegExp.
  151. * E.g., `new RegExp()`, `RegExp()`, `new window.RegExp()`,
  152. * `const {RegExp: a} = window; new a()`, etc...
  153. */
  154. for (const { node } of tracker.iterateGlobalReferences({
  155. RegExp: { [CALL]: true, [CONSTRUCT]: true }
  156. })) {
  157. const [patternNode, flagsNode] = node.arguments;
  158. const pattern = getStringIfConstant(patternNode, scope);
  159. const flags = getStringIfConstant(flagsNode, scope);
  160. if (typeof pattern === "string") {
  161. verify(node, pattern, flags || "");
  162. }
  163. }
  164. }
  165. };
  166. }
  167. };