summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/lib/rules/no-control-regex.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/eslint/lib/rules/no-control-regex.js')
-rw-r--r--tools/node_modules/eslint/lib/rules/no-control-regex.js127
1 files changed, 127 insertions, 0 deletions
diff --git a/tools/node_modules/eslint/lib/rules/no-control-regex.js b/tools/node_modules/eslint/lib/rules/no-control-regex.js
new file mode 100644
index 0000000000..14981f4ab1
--- /dev/null
+++ b/tools/node_modules/eslint/lib/rules/no-control-regex.js
@@ -0,0 +1,127 @@
+/**
+ * @fileoverview Rule to forbid control charactes from regular expressions.
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+ meta: {
+ docs: {
+ description: "disallow control characters in regular expressions",
+ category: "Possible Errors",
+ recommended: true
+ },
+
+ schema: []
+ },
+
+ create(context) {
+
+ /**
+ * Get the regex expression
+ * @param {ASTNode} node node to evaluate
+ * @returns {*} Regex if found else null
+ * @private
+ */
+ function getRegExp(node) {
+ if (node.value instanceof RegExp) {
+ return node.value;
+ }
+ if (typeof node.value === "string") {
+
+ const parent = context.getAncestors().pop();
+
+ if ((parent.type === "NewExpression" || parent.type === "CallExpression") &&
+ parent.callee.type === "Identifier" && parent.callee.name === "RegExp"
+ ) {
+
+ // there could be an invalid regular expression string
+ try {
+ return new RegExp(node.value);
+ } catch (ex) {
+ return null;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ const controlChar = /[\x00-\x1f]/g; // eslint-disable-line no-control-regex
+ const consecutiveSlashes = /\\+/g;
+ const consecutiveSlashesAtEnd = /\\+$/g;
+ const stringControlChar = /\\x[01][0-9a-f]/ig;
+ const stringControlCharWithoutSlash = /x[01][0-9a-f]/ig;
+
+ /**
+ * Return a list of the control characters in the given regex string
+ * @param {string} regexStr regex as string to check
+ * @returns {array} returns a list of found control characters on given string
+ * @private
+ */
+ function getControlCharacters(regexStr) {
+
+ // check control characters, if RegExp object used
+ const controlChars = regexStr.match(controlChar) || [];
+
+ let stringControlChars = [];
+
+ // check substr, if regex literal used
+ const subStrIndex = regexStr.search(stringControlChar);
+
+ if (subStrIndex > -1) {
+
+ // is it escaped, check backslash count
+ const possibleEscapeCharacters = regexStr.slice(0, subStrIndex).match(consecutiveSlashesAtEnd);
+
+ const hasControlChars = possibleEscapeCharacters === null || !(possibleEscapeCharacters[0].length % 2);
+
+ if (hasControlChars) {
+ stringControlChars = regexStr.slice(subStrIndex, -1)
+ .split(consecutiveSlashes)
+ .filter(Boolean)
+ .map(x => {
+ const match = x.match(stringControlCharWithoutSlash) || [x];
+
+ return `\\${match[0]}`;
+ });
+ }
+ }
+
+ return controlChars.map(x => {
+ const hexCode = `0${x.charCodeAt(0).toString(16)}`.slice(-2);
+
+ return `\\x${hexCode}`;
+ }).concat(stringControlChars);
+ }
+
+ return {
+ Literal(node) {
+ const regex = getRegExp(node);
+
+ if (regex) {
+ const computedValue = regex.toString();
+
+ const controlCharacters = getControlCharacters(computedValue);
+
+ if (controlCharacters.length > 0) {
+ context.report({
+ node,
+ message: "Unexpected control character(s) in regular expression: {{controlChars}}.",
+ data: {
+ controlChars: controlCharacters.join(", ")
+ }
+ });
+ }
+ }
+ }
+ };
+
+ }
+};