no-unsafe-regex.js 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. 'use strict';
  2. const safeRegex = require('safe-regex');
  3. const {newExpressionSelector} = require('./selectors/index.js');
  4. const {isNewExpression} = require('./ast/index.js');
  5. const MESSAGE_ID = 'no-unsafe-regex';
  6. const messages = {
  7. [MESSAGE_ID]: 'Unsafe regular expression.',
  8. };
  9. const newRegExpSelector = [
  10. newExpressionSelector('RegExp'),
  11. '[arguments.0.type="Literal"]',
  12. ].join('');
  13. /** @param {import('eslint').Rule.RuleContext} context */
  14. const create = () => ({
  15. 'Literal[regex]'(node) {
  16. // Handle regex literal inside RegExp constructor in the other handler
  17. if (isNewExpression(node.parent, {name: 'RegExp'})) {
  18. return;
  19. }
  20. if (!safeRegex(node.value)) {
  21. return {
  22. node,
  23. messageId: MESSAGE_ID,
  24. };
  25. }
  26. },
  27. [newRegExpSelector](node) {
  28. const arguments_ = node.arguments;
  29. const hasRegExp = arguments_[0].regex;
  30. let pattern;
  31. let flags;
  32. if (hasRegExp) {
  33. ({pattern} = arguments_[0].regex);
  34. flags = arguments_[1]?.type === 'Literal'
  35. ? arguments_[1].value
  36. : arguments_[0].regex.flags;
  37. } else {
  38. pattern = arguments_[0].value;
  39. flags = arguments_[1]?.type === 'Literal'
  40. ? arguments_[1].value
  41. : '';
  42. }
  43. if (!safeRegex(`/${pattern}/${flags}`)) {
  44. return {
  45. node,
  46. messageId: MESSAGE_ID,
  47. };
  48. }
  49. },
  50. });
  51. /** @type {import('eslint').Rule.RuleModule} */
  52. module.exports = {
  53. create,
  54. meta: {
  55. type: 'problem',
  56. docs: {
  57. description: 'Disallow unsafe regular expressions.',
  58. },
  59. messages,
  60. },
  61. };