Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
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.

prefer-regex-literals.js 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /**
  2. * @fileoverview Rule to disallow use of the `RegExp` constructor in favor of regular expression literals
  3. * @author Milos Djermanovic
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("./utils/ast-utils");
  10. const { CALL, CONSTRUCT, ReferenceTracker, findVariable } = require("eslint-utils");
  11. //------------------------------------------------------------------------------
  12. // Helpers
  13. //------------------------------------------------------------------------------
  14. /**
  15. * Determines whether the given node is a string literal.
  16. * @param {ASTNode} node Node to check.
  17. * @returns {boolean} True if the node is a string literal.
  18. */
  19. function isStringLiteral(node) {
  20. return node.type === "Literal" && typeof node.value === "string";
  21. }
  22. /**
  23. * Determines whether the given node is a regex literal.
  24. * @param {ASTNode} node Node to check.
  25. * @returns {boolean} True if the node is a regex literal.
  26. */
  27. function isRegexLiteral(node) {
  28. return node.type === "Literal" && Object.prototype.hasOwnProperty.call(node, "regex");
  29. }
  30. /**
  31. * Determines whether the given node is a template literal without expressions.
  32. * @param {ASTNode} node Node to check.
  33. * @returns {boolean} True if the node is a template literal without expressions.
  34. */
  35. function isStaticTemplateLiteral(node) {
  36. return node.type === "TemplateLiteral" && node.expressions.length === 0;
  37. }
  38. //------------------------------------------------------------------------------
  39. // Rule Definition
  40. //------------------------------------------------------------------------------
  41. module.exports = {
  42. meta: {
  43. type: "suggestion",
  44. docs: {
  45. description: "disallow use of the `RegExp` constructor in favor of regular expression literals",
  46. category: "Best Practices",
  47. recommended: false,
  48. url: "https://eslint.org/docs/rules/prefer-regex-literals"
  49. },
  50. schema: [
  51. {
  52. type: "object",
  53. properties: {
  54. disallowRedundantWrapping: {
  55. type: "boolean",
  56. default: false
  57. }
  58. },
  59. additionalProperties: false
  60. }
  61. ],
  62. messages: {
  63. unexpectedRegExp: "Use a regular expression literal instead of the 'RegExp' constructor.",
  64. unexpectedRedundantRegExp: "Regular expression literal is unnecessarily wrapped within a 'RegExp' constructor.",
  65. unexpectedRedundantRegExpWithFlags: "Use regular expression literal with flags instead of the 'RegExp' constructor."
  66. }
  67. },
  68. create(context) {
  69. const [{ disallowRedundantWrapping = false } = {}] = context.options;
  70. /**
  71. * Determines whether the given identifier node is a reference to a global variable.
  72. * @param {ASTNode} node `Identifier` node to check.
  73. * @returns {boolean} True if the identifier is a reference to a global variable.
  74. */
  75. function isGlobalReference(node) {
  76. const scope = context.getScope();
  77. const variable = findVariable(scope, node);
  78. return variable !== null && variable.scope.type === "global" && variable.defs.length === 0;
  79. }
  80. /**
  81. * Determines whether the given node is a String.raw`` tagged template expression
  82. * with a static template literal.
  83. * @param {ASTNode} node Node to check.
  84. * @returns {boolean} True if the node is String.raw`` with a static template.
  85. */
  86. function isStringRawTaggedStaticTemplateLiteral(node) {
  87. return node.type === "TaggedTemplateExpression" &&
  88. astUtils.isSpecificMemberAccess(node.tag, "String", "raw") &&
  89. isGlobalReference(astUtils.skipChainExpression(node.tag).object) &&
  90. isStaticTemplateLiteral(node.quasi);
  91. }
  92. /**
  93. * Determines whether the given node is considered to be a static string by the logic of this rule.
  94. * @param {ASTNode} node Node to check.
  95. * @returns {boolean} True if the node is a static string.
  96. */
  97. function isStaticString(node) {
  98. return isStringLiteral(node) ||
  99. isStaticTemplateLiteral(node) ||
  100. isStringRawTaggedStaticTemplateLiteral(node);
  101. }
  102. /**
  103. * Determines whether the relevant arguments of the given are all static string literals.
  104. * @param {ASTNode} node Node to check.
  105. * @returns {boolean} True if all arguments are static strings.
  106. */
  107. function hasOnlyStaticStringArguments(node) {
  108. const args = node.arguments;
  109. if ((args.length === 1 || args.length === 2) && args.every(isStaticString)) {
  110. return true;
  111. }
  112. return false;
  113. }
  114. /**
  115. * Determines whether the arguments of the given node indicate that a regex literal is unnecessarily wrapped.
  116. * @param {ASTNode} node Node to check.
  117. * @returns {boolean} True if the node already contains a regex literal argument.
  118. */
  119. function isUnnecessarilyWrappedRegexLiteral(node) {
  120. const args = node.arguments;
  121. if (args.length === 1 && isRegexLiteral(args[0])) {
  122. return true;
  123. }
  124. if (args.length === 2 && isRegexLiteral(args[0]) && isStaticString(args[1])) {
  125. return true;
  126. }
  127. return false;
  128. }
  129. return {
  130. Program() {
  131. const scope = context.getScope();
  132. const tracker = new ReferenceTracker(scope);
  133. const traceMap = {
  134. RegExp: {
  135. [CALL]: true,
  136. [CONSTRUCT]: true
  137. }
  138. };
  139. for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
  140. if (disallowRedundantWrapping && isUnnecessarilyWrappedRegexLiteral(node)) {
  141. if (node.arguments.length === 2) {
  142. context.report({ node, messageId: "unexpectedRedundantRegExpWithFlags" });
  143. } else {
  144. context.report({ node, messageId: "unexpectedRedundantRegExp" });
  145. }
  146. } else if (hasOnlyStaticStringArguments(node)) {
  147. context.report({ node, messageId: "unexpectedRegExp" });
  148. }
  149. }
  150. }
  151. };
  152. }
  153. };