prefer-string-replace-all.js 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. 'use strict';
  2. const quoteString = require('./utils/quote-string.js');
  3. const {methodCallSelector} = require('./selectors/index.js');
  4. const {isRegexLiteral} = require('./ast/index.js');
  5. const MESSAGE_ID = 'prefer-string-replace-all';
  6. const messages = {
  7. [MESSAGE_ID]: 'Prefer `String#replaceAll()` over `String#replace()`.',
  8. };
  9. const selector = methodCallSelector({
  10. method: 'replace',
  11. argumentsLength: 2,
  12. });
  13. const isRegexWithGlobalFlag = node =>
  14. isRegexLiteral(node)
  15. && node.regex.flags.replace('u', '') === 'g';
  16. function isLiteralCharactersOnly(node) {
  17. const searchPattern = node.regex.pattern;
  18. return !/[$()*+.?[\\\]^{}]/.test(searchPattern.replace(/\\[$()*+.?[\\\]^{}]/g, ''));
  19. }
  20. function removeEscapeCharacters(regexString) {
  21. let fixedString = regexString;
  22. let index = 0;
  23. do {
  24. index = fixedString.indexOf('\\', index);
  25. if (index >= 0) {
  26. fixedString = fixedString.slice(0, index) + fixedString.slice(index + 1);
  27. index++;
  28. }
  29. } while (index >= 0);
  30. return fixedString;
  31. }
  32. /** @param {import('eslint').Rule.RuleContext} context */
  33. const create = () => ({
  34. [selector](node) {
  35. const {arguments: arguments_, callee} = node;
  36. const [search] = arguments_;
  37. if (!isRegexWithGlobalFlag(search) || !isLiteralCharactersOnly(search)) {
  38. return;
  39. }
  40. return {
  41. node,
  42. messageId: MESSAGE_ID,
  43. fix: fixer => [
  44. fixer.insertTextAfter(callee, 'All'),
  45. fixer.replaceText(search, quoteString(removeEscapeCharacters(search.regex.pattern))),
  46. ],
  47. };
  48. },
  49. });
  50. /** @type {import('eslint').Rule.RuleModule} */
  51. module.exports = {
  52. create,
  53. meta: {
  54. type: 'suggestion',
  55. docs: {
  56. description: 'Prefer `String#replaceAll()` over regex searches with the global flag.',
  57. },
  58. fixable: 'code',
  59. messages,
  60. },
  61. };