ESLint and lookbehind assertion

Viewed 419

I have a regular expression with a lookbehind assertion that ESLint doesn't seem to recognise as valid. However lookahead assertions are fine.

I can reproduce this issue with the latest version of ESLint (I've used the online demo) and with very simple and contrived examples.

Lookahead assertion: match b (and only b) if followed by d:

'bd'.match(/b(?=d)/) //=> ['b']
'be'.match(/b(?=d)/) //=> null

ESLint recognises /b(?=d)/ as valid regular expression:

enter image description here

Lookbehind assertion: match b (and only b) if preceded by a:

'ab'.match(/(?<=a)b/) //=> ['b']
'eb'.match(/(?<=a)b/) //=> null

ESLint doesn't recognise /(?<=a)b/ as a valid regular expression:

enter image description here

Question: what's wrong with my regular expression that causes ESLint to complain?


ESLint configuration used in the demos above:

{
    "parserOptions": {
        "ecmaVersion": 5,
        "sourceType": "script",
        "ecmaFeatures": {}
    },
    "rules": {
        "constructor-super": 2,
        "for-direction": 2,
        "getter-return": 2,
        "no-async-promise-executor": 2,
        "no-case-declarations": 2,
        "no-class-assign": 2,
        "no-compare-neg-zero": 2,
        "no-cond-assign": 2,
        "no-const-assign": 2,
        "no-constant-condition": 2,
        "no-control-regex": 2,
        "no-debugger": 2,
        "no-delete-var": 2,
        "no-dupe-args": 2,
        "no-dupe-class-members": 2,
        "no-dupe-else-if": 2,
        "no-dupe-keys": 2,
        "no-duplicate-case": 2,
        "no-empty": 2,
        "no-empty-character-class": 2,
        "no-empty-pattern": 2,
        "no-ex-assign": 2,
        "no-extra-boolean-cast": 2,
        "no-extra-semi": 2,
        "no-fallthrough": 2,
        "no-func-assign": 2,
        "no-global-assign": 2,
        "no-import-assign": 2,
        "no-inner-declarations": 2,
        "no-invalid-regexp": 2,
        "no-irregular-whitespace": 2,
        "no-misleading-character-class": 2,
        "no-mixed-spaces-and-tabs": 2,
        "no-new-symbol": 2,
        "no-obj-calls": 2,
        "no-octal": 2,
        "no-prototype-builtins": 2,
        "no-redeclare": 2,
        "no-regex-spaces": 2,
        "no-self-assign": 2,
        "no-setter-return": 2,
        "no-shadow-restricted-names": 2,
        "no-sparse-arrays": 2,
        "no-this-before-super": 2,
        "no-undef": 2,
        "no-unexpected-multiline": 2,
        "no-unreachable": 2,
        "no-unsafe-finally": 2,
        "no-unsafe-negation": 2,
        "no-unused-labels": 2,
        "no-unused-vars": 2,
        "no-useless-catch": 2,
        "no-useless-escape": 2,
        "no-with": 2,
        "require-yield": 2,
        "use-isnan": 2,
        "valid-typeof": 2
    },
    "env": {}
}
1 Answers

You can refer to the Specifying Parser Options reference:

ecmaVersion - set to 3, 5 (default), 6, 7, 8, 9, 10, 11, or 12 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), 2019 (same as 10), 2020 (same as 11), or 2021 (same as 12) to use the year-based naming.

As you can see, the default value is 5, meaning it only supports ES5. Lookbehinds are compliant with ECMAScript 2018, so you need to make sure you set ecmaVersion to at least 9:

"parserOptions": {
        "ecmaVersion": 9,
        "sourceType": "script",
        "ecmaFeatures": {}
    },
Related