Skip to content

Latest commit

 

History

History
452 lines (348 loc) · 11.8 KB

invalid-regex-rule.md

File metadata and controls

452 lines (348 loc) · 11.8 KB

Looks for Invalid regular expressions to be reported for each file

Rule Details

This rule looks for Invalid regular expressions to be reported for each file.

Example of incorrect code for this rule:

/* eslint regex/invalid: ['error', ['"']] */

const text = 'Hello "My Friend"'

Example of correct code for this rule:

/* eslint regex/invalid: ['error', ['"']] */

const text = 'Hello \'My Friend\''

Options

  • array of patterns definitions to analyze. [REQUIRED]
    • Each pattern definition can be 'Short' or 'Detailed'.
  • a string representing the regular expression for ignoring files for all patterns. [OPTIONAL]
    • Slashes (/) are not required in the string, e.g. To get the following regex /.*test\.js/ define the following string ".*test\.js" when using .eslintrc.js or ".*test\\.js" when using .eslintrc.json (backslash needs to de double in a json file).

Short pattern definition

It is specified by just a regular expression string, i.e. "regex"

  • Slashes (/) are not required in the string, e.g. To get the following regex /\bhttp:/ define the following string "\bhttp:" when using .eslintrc.js or "\\bhttp:" when using .eslintrc.json (backslash needs to de double in a json file).

.eslintrc.json:

{
  "plugins": [
    "regex"
  ],
  "rules": {
    "regex/invalid": [
      "error", [
        "invalidRegex1",
        "invalidRegexN"
      ],
      ".*test\\.js"
    ]
  }
}

Detailed pattern definition

It is specified by an object, with the following fields:

  • regex: A required string for regex/required and regex/invalid representing the Regular expression to look for. [REQUIRED]
  • flags: A combination of flags, i, s and/or u, to be used by the Regular Expression. [OPTIONAL]
  • replacement for regex/invalid [1]: [OPTIONAL]
    • An optional string used to replace the invalid found pattern, or
    • An optional object that establish how the invalid found pattern will be replaced:
      • function: used to replace the invalid found pattern.
        • It will receive 3 parameters: text, captured and $, that can be used as desired.
        • It must return a string value, if not, return value will be ignored.
        • Its definition must be only the body of the function.
    • One must be defined, either the string or function.
  • id: An optional string representing the Pattern Id. [OPTIONAL]
  • message: An optional string specifying the Message to be shown when an error happens (invalid regex is found or required regex is not found). [OPTIONAL]
  • files: An optional object specifying which files to analyze: [OPTIONAL]
    • ignore: A string representing Regular expression of the files to be ignored when validating this specific pattern.
    • inspect: A string representing Regular expression of the files to be inspected when validating this specific pattern.
{
  "id": "regexId",
  "regex": "regex",
  "flags": "isu",
  "replacement": "replacementString",
  "message": "errorMessage",
  "files": {
    "ignore": "ignoreFilesRegex",
    "inspect": "inspectFilesRegex"
  }
}
  • regex is the only Required field. Slashes (/) are not required in the string, e.g. To get the following regex /\bhttp:/:
    • when using .eslintrc.js, define the following string "\bhttp:", or
    • when using .eslintrc.json, define "\\bhttp:" (backslash needs to de double in a json file).
  • When ignore and inspect are present, ignore takes precedence.
  • Global ignore file pattern, takes precedence over files patterns.

[1] In order to fix issue eslint must be run with --fix option.

.eslintrc.json:

{
  "plugins": [
    "regex"
  ],
  "rules": {
    "regex/invalid": [
      "error", [{
          "regex": "invalidRegex1",
          "message": "errorMessage1",
          "replacement": "newValue"
        }, {
          "id": "regexIdN",
          "regex": "invalidRegexN",
          "files": {
            "ignore": "ignoreFilesRegexN"
          }
        }
      ]
    ]
  }
}

Definition of the Function used to replace the invalid found pattern

Definition of the function must be done as a string in 1 line, and the following rules apply:

  • It must return a string value, if not, return value will be ignored, i.e. it will silently fail.
  • Its definition must be only the body of the function.
    • For "simple" functions where the return is found at the beginning of the body of the function and the exact word return is not present, return can be omitted.
  • If the function has invalid Javascript code, the function will be ignored, i.e. it will silently fail.

Function will receive 3 parameters, to be used as desired:

  • text: a string with the value of the invalid text found.
  • captured: an array of strings with the values of the captured groups for the regex.
  • $: an array of strings, with the value of the invalid text found plus the values of the captured groups for the regex.
    • $[0] = text: a string with the value of the invalid text found.
    • $[1..] = captured: an array of strings with the values of the captured groups for the regex.
      • $[1] = captured[0] and so on.
    • It allows smaller definitions.

e.g. Using parameter text

"return text.trim()" => only the body of the function + returns a string value based on text

Having the following rule in .eslintrc.json:

{
  "id": "regexIdN",
  "regex": "\\serror\\w*\\s",
  "replacement": {
    "function": "return text.trim()"
  }
}

or using $:

{
  "id": "regexIdN",
  "regex": "\\serror\\w*\\s",
  "replacement": {
    "function": "return $[0].trim()"
  }
}

then, given:

example.js

const exception = " error19 "

when linting with fix, the result will be:

const exception = "error19"

As the body of the function is "simple", i.e. the return is found at the beginning of the body of the function, and besides, the word return is not present, then the definition could be done as:

{
  "id": "regexIdN",
  "regex": "\\serror\\w*\\s",
  "replacement": {
    "function": "text.trim()"
  }
}

or

{
  "id": "regexIdN",
  "regex": "\\serror\\w*\\s",
  "replacement": {
    "function": "$[0].trim()"
  }
}

e.g. Using parameter captured

"return captured[0]" => only the body of the function + returns a string value based on captured

Having the following rule in .eslintrc.json:

{
  "id": "regexIdN",
  "regex": "\\serror(\\w*)\\s",
  "replacement": {
    "function": "return captured[0]"
  }
}

or using $:

{
  "id": "regexIdN",
  "regex": "\\serror(\\w*)\\s",
  "replacement": {
    "function": "return $[1]"
  }
}

then, given:

example.js

const exception = " error19 "

when linting with fix, the result will be:

const exception = "19"

As the body of the function is "simple", i.e. the return is found at the beginning of the body of the function, and besides, the word return is not present, then the definition could be done as:

{
  "id": "regexIdN",
  "regex": "\\serror(\\w*)\\s",
  "replacement": {
    "function": "captured[0]"
  }
}

or

{
  "id": "regexIdN",
  "regex": "\\serror(\\w*)\\s",
  "replacement": {
    "function": "$[1]"
  }
}

e.g. Using parameters text and captured

"return text + ' = ' + captured[0] + ' + ' + captured[1] + ' = ' + (parseInt(captured[0]) + parseInt(captured[1]))" => only the body of the function + returns a string value based on text and captured

Having the following rule in .eslintrc.json:

{
  "id": "regexIdN",
  "regex": "(\\d+)\\+(\\d+)",
  "replacement": {
    "function": "return text + ' = ' + captured[0]  + ' + ' + captured[1] + ' = ' + (parseInt(captured[0]) + parseInt(captured[1]))"
  }
}

or using $:

{
  "id": "regexIdN",
  "regex": "(\\d+)\\+(\\d+)",
  "replacement": {
    "function": "return $[0] + ' = ' + $[1]  + ' + ' + $[2] + ' = ' + (parseInt($[1]) + parseInt($[2]))"
  }
}

or :

{
  "id": "regexIdN",
  "regex": "(\\d+)\\+(\\d+)",
  "replacement": {
    "function": "return text + ' = ' + $[1]  + ' + ' + $[2] + ' = ' + (parseInt($[1]) + parseInt($[2]))"
  }
}

or :

{
  "id": "regexIdN",
  "regex": "(\\d+)\\+(\\d+)",
  "replacement": {
    "function": "return `${text} = ${captured[0]} + ${captured[1]} = ${parseInt($[1]) + parseInt($[2])}`"
  }
}

then, given:

example.js

const sum = "4+5"

when linting with fix, the result will be:

const sum = "4+5 = 4 + 5 = 9"

As the body of the function is "simple", i.e. the return is found at the beginning of the body of the function, and besides, the word return is not present, then the definition could be done as:

{
  "id": "regexIdN",
  "regex": "(\\d+)\\+(\\d+)",
  "replacement": {
    "function": "text + ' = ' + $[1]  + ' + ' + $[2] + ' = ' + (parseInt($[1]) + parseInt($[2]))"
  }
}

or :

{
  "id": "regexIdN",
  "regex": "(\\d+)\\+(\\d+)",
  "replacement": {
    "function": "`${text} = ${captured[0]} + ${captured[1]} = ${parseInt($[1]) + parseInt($[2])}`"
  }
}

e.g. return required

e.g. const result = text === 'superb' ? 'Superb' : text; return result => only the body of the function + returns a string value based on text.

Since the return is not found at the beginning of the body of the function, return cannot be omitted, then rule definition will be as usual:

{
  "id": "regexIdN",
  "regex": "\\w+",
  "replacement": {
    "function": "const result = text === 'superb' ? 'Superb' : text; return result"
  }
}

Some cases may use Comma operator, e.g. "function": "result = text === 'superb' ? 'Superb' : text, result"

e.g. return text === 'return' ? 'Return' : text => only the body of the function + returns a string value based on text.

Since the exact word return is present, this will required return, then rule definition will be as usual:

{
  "id": "regexIdN",
  "regex": "\\w+",
  "replacement": {
    "function": "return text === 'return' ? 'Return' : text"
  }
}

Following case does not required return:

e.g. return text === 'Return' ? 'RETURN' : text => only the body of the function + returns a string value based on text.

Since the exact word return is not present, this will allow the following rule definition to be:

{
  "id": "regexIdN",
  "regex": "\\w+",
  "replacement": {
    "function": "text === 'Return' ? 'RETURN' : text"
  }
}
Debugging of the Replacement Function for invalid found pattern
  • It is possible to add console statements to print some information in the Replacement Function.
{
      regex: '\\serror(\\w*)\\s',
      replacement: {
        function: 'const extract = captured[0]; console.log(extract); return extract'
      }
    }

String to Regular expression conversion

Internally, each string from the array will be converted into a Regular Expression with global and multiline options, e.g.:

"invalidRegex1" will be transformed into /invalidRegex1/gm

When the pattern is found, the error message will reflect the exact location, e.g.:

 34:25  error  Invalid regular expression /invalidRegex1/gm found  regex/invalid

Examples

Check:

Related Rules

More information