AST utilities
getFunctionHeadLocation
const loc = utils.getFunctionHeadLocation(node, sourceCode)Get the proper location of a given function node to report.
Show the location examples:
- `function foo() {}` ^^^^^^^^^^^^- `(function foo() {})` ^^^^^^^^^^^^- `(function() {})` ^^^^^^^^- `function* foo() {}` ^^^^^^^^^^^^^- `(function* foo() {})` ^^^^^^^^^^^^^- `(function*() {})` ^^^^^^^^^- `() => {}` ^^- `async () => {}` ^^- `({ foo: function foo() {} })` ^^^^^^^^^^^^^^^^^- `({ foo: function() {} })` ^^^^^^^^^^^^^- `({ ['foo']: function() {} })` ^^^^^^^^^^^^^^^^^- `({ [foo]: function() {} })` ^^^^^^^^^^^^^^^- `({ foo() {} })` ^^^- `({ foo: function* foo() {} })` ^^^^^^^^^^^^^^^^^^- `({ foo: function*() {} })` ^^^^^^^^^^^^^^- `({ ['foo']: function*() {} })` ^^^^^^^^^^^^^^^^^^- `({ [foo]: function*() {} })` ^^^^^^^^^^^^^^^^- `({ *foo() {} })` ^^^^- `({ foo: async function foo() {} })` ^^^^^^^^^^^^^^^^^^^^^^^- `({ foo: async function() {} })` ^^^^^^^^^^^^^^^^^^^- `({ ['foo']: async function() {} })` ^^^^^^^^^^^^^^^^^^^^^^^- `({ [foo]: async function() {} })` ^^^^^^^^^^^^^^^^^^^^^- `({ async foo() {} })` ^^^^^^^^^- `({ get foo() {} })` ^^^^^^^- `({ set foo(a) {} })` ^^^^^^^- `class A { constructor() {} }` ^^^^^^^^^^^- `class A { foo() {} }` ^^^- `class A { *foo() {} }` ^^^^- `class A { async foo() {} }` ^^^^^^^^^- `class A { ['foo']() {} }` ^^^^^^^- `class A { *['foo']() {} }` ^^^^^^^^- `class A { async ['foo']() {} }` ^^^^^^^^^^^^^- `class A { [foo]() {} }` ^^^^^- `class A { *[foo]() {} }` ^^^^^^- `class A { async [foo]() {} }` ^^^^^^^^^^^- `class A { get foo() {} }` ^^^^^^^- `class A { set foo(a) {} }` ^^^^^^^- `class A { static foo() {} }` ^^^^^^^^^^- `class A { static *foo() {} }` ^^^^^^^^^^^- `class A { static async foo() {} }` ^^^^^^^^^^^^^^^^- `class A { static get foo() {} }` ^^^^^^^^^^^^^^- `class A { static set foo(a) {} }` ^^^^^^^^^^^^^^- `class A { #foo() {} }` ^^^^- `class A { *#foo() {} }` ^^^^^- `class A { async #foo() {} }` ^^^^^^^^^^- `class A { get #foo() {} }` ^^^^^^^^- `class A { set #foo(a) {} }` ^^^^^^^^- `class A { static #foo() {} }` ^^^^^^^^^^^- `class A { static *#foo() {} }` ^^^^^^^^^^^^- `class A { static async #foo() {} }` ^^^^^^^^^^^^^^^^^- `class A { static get #foo() {} }` ^^^^^^^^^^^^^^^- `class A { static set #foo(a) {} }` ^^^^^^^^^^^^^^^- `class A { foo = function() {} }` ^^^^^^^^^^^^^^- `class A { foo = function*() {} }` ^^^^^^^^^^^^^^^- `class A { foo = async function() {} }` ^^^^^^^^^^^^^^^^^^^^- `class A { static foo = function() {} }` ^^^^^^^^^^^^^^^^^^^^^- `class A { static foo = function*() {} }` ^^^^^^^^^^^^^^^^^^^^^^- `class A { static foo = async function() {} }` ^^^^^^^^^^^^^^^^^^^^^^^^^^^- `class A { #foo = function() {} }` ^^^^^^^^^^^^^^^- `class A { #foo = function*() {} }` ^^^^^^^^^^^^^^^^- `class A { #foo = async function() {} }` ^^^^^^^^^^^^^^^^^^^^^- `class A { static #foo = function() {} }` ^^^^^^^^^^^^^^^^^^^^^^- `class A { static #foo = function*() {} }` ^^^^^^^^^^^^^^^^^^^^^^^- `class A { static #foo = async function() {} }` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^Parameters
| Name | Type | Description |
|---|---|---|
| node | Node | The function node to get the location. This should be any ofFunctionDeclaration,FunctionExpression, andArrowFunctionExpression node. |
| sourceCode | SourceCode | The source code object to get tokens. |
Return value
The location object.
Example
const {getFunctionHeadLocation }= require("@eslint-community/eslint-utils")module.exports = { meta: {}, create(context) { const sourceCode = context.getSourceCode() return { FunctionDeclaration(node) { context.report({ node, loc:getFunctionHeadLocation(node, sourceCode), message:"disallow this function!", }) }, } },}getFunctionNameWithKind
const name = utils.getFunctionNameWithKind(node)Get the name and kind of a given function node.
Show the name and kind examples:
- `function foo() {}` ............................... `function 'foo'`- `(function foo() {})` ............................. `function 'foo'`- `(function() {})` ................................. `function`- `function* foo() {}` .............................. `generator function 'foo'`- `(function* foo() {})` ............................ `generator function 'foo'`- `(function*() {})` ................................ `generator function`- `() => {}` ........................................ `arrow function`- `async () => {}` .................................. `async arrow function`- `const foo = () => {}` ............................ `arrow function 'foo'`- `const foo = async () => {}` ...................... `async arrow function 'foo'`- `foo = () => {}` .................................. `arrow function 'foo'`- `foo = async () => {}` ............................ `async arrow function 'foo'`- `const foo = function() {}` ....................... `function 'foo'`- `const foo = function* () {}` ..................... `generator function 'foo'`- `const foo = async function() {}` ................. `async function 'foo'`- `foo = function() {}` ............................. `function 'foo'`- `foo = function* () {}` ........................... `generator function 'foo'`- `foo = async function() {}` ....................... `async function 'foo'`- `({ foo: function foo() {} })` .................... `method 'foo'`- `({ foo: function() {} })` ........................ `method 'foo'`- `({ ['foo']: function() {} })` .................... `method 'foo'`- `({ [foo]: function() {} })` ...................... `method`- `({ [foo]: function() {} })` ...................... `method [foo]` if sourceCode is present.- `({ foo() {} })` .................................. `method 'foo'`- `({ foo: function* foo() {} })` ................... `generator method 'foo'`- `({ foo: function*() {} })` ....................... `generator method 'foo'`- `({ ['foo']: function*() {} })` ................... `generator method 'foo'`- `({ [foo]: function*() {} })` ..................... `generator method`- `({ [foo]: function*() {} })` ..................... `generator method [foo]` if sourceCode is present.- `({ *foo() {} })` ................................. `generator method 'foo'`- `({ foo: async function foo() {} })` .............. `async method 'foo'`- `({ foo: async function() {} })` .................. `async method 'foo'`- `({ ['foo']: async function() {} })` .............. `async method 'foo'`- `({ [foo]: async function() {} })` ................ `async method`- `({ [foo]: async function() {} })` ................ `async method [foo]` if sourceCode is present.- `({ async foo() {} })` ............................ `async method 'foo'`- `({ get foo() {} })` .............................. `getter 'foo'`- `({ set foo(a) {} })` ............................. `setter 'foo'`- `class A { constructor() {} }` .................... `constructor`- `class A { foo() {} }` ............................ `method 'foo'`- `class A { *foo() {} }` ........................... `generator method 'foo'`- `class A { async foo() {} }` ...................... `async method 'foo'`- `class A { ['foo']() {} }` ........................ `method 'foo'`- `class A { *['foo']() {} }` ....................... `generator method 'foo'`- `class A { async ['foo']() {} }` .................. `async method 'foo'`- `class A { [foo]() {} }` .......................... `method`- `class A { [foo]() {} }` .......................... `method [foo]` if sourceCode is present.- `class A { *[foo]() {} }` ......................... `generator method`- `class A { *[foo]() {} }` ......................... `generator method [foo]` if sourceCode is present.- `class A { async [foo]() {} }` .................... `async method`- `class A { async [foo]() {} }` .................... `async method [foo]` if sourceCode is present.- `class A { get foo() {} }` ........................ `getter 'foo'`- `class A { set foo(a) {} }` ....................... `setter 'foo'`- `class A { static foo() {} }` ..................... `static method 'foo'`- `class A { static *foo() {} }` .................... `static generator method 'foo'`- `class A { static async foo() {} }` ............... `static async method 'foo'`- `class A { static get foo() {} }` ................. `static getter 'foo'`- `class A { static set foo(a) {} }` ................ `static setter 'foo'`- `class A { #foo() {} }` ........................... `private method #foo`- `class A { '#foo'() {} }` ......................... `method '#foo'`- `class A { *#foo() {} }` .......................... `private generator method #foo`- `class A { async #foo() {} }` ..................... `private async method #foo`- `class A { get #foo() {} }` ....................... `private getter #foo`- `class A { set #foo(a) {} }` ...................... `private setter #foo`- `class A { static #foo() {} }` .................... `static private method #foo`- `class A { static *#foo() {} }` ................... `static private generator method #foo`- `class A { static async #foo() {} }` .............. `static private async method #foo`- `class A { static get #foo() {} }` ................ `static private getter #foo`- `class A { static set #foo(a) {} }` ............... `static private setter #foo`- `class A { '#foo' = function() {} }` .............. `method '#foo'"`- `class A { #foo = function() {} }` ................ `private method #foo"`- `class A { #foo = function*() {} }` ............... `private generator method #foo"`- `class A { #foo = async function() {} }` .......... `private async method #foo"`- `class A { static #foo = function() {} }` ......... `static private method #foo"`- `class A { static #foo = function*() {} }` ........ `static private generator method #foo"`- `class A { static #foo = async function() {} }` ... `static private async method #foo"`Parameters
| Name | Type | Description |
|---|---|---|
| node | Node | The function node to get the name and kind. This should be any ofFunctionDeclaration,FunctionExpression, andArrowFunctionExpression node. |
| sourceCode | SourceCode | Optional. The source code object to get the text of computed property keys. |
Return value
The name and kind of the function.
Example
const {getFunctionNameWithKind }= require("@eslint-community/eslint-utils")module.exports = { meta: {}, create(context) { const sourceCode = context.getSourceCode() return { FunctionDeclaration(node) { context.report({ node, message:"disallow this {{name}}!", data: { name:getFunctionNameWithKind(node, sourceCode) } }) }, } },}getPropertyName
const name = utils.getPropertyName(node)const name = utils.getPropertyName(node, initialScope)Get the property name of a given property node.
If the node is a computed property, this tries to compute the property name by thegetStringIfConstant function.
Parameters
| Name | Type | Description |
|---|---|---|
| node | Node | The node to get that name. This shuld be any ofMemberExpression,Property,MethodDefinition, andPropertyDefinition node. |
| initialScope | Scope or undefined | Optional. The scope object to find variables. |
Return value
The property name of the node. If the property name is not constant then it returnsnull.
Example
const {getPropertyName }= require("@eslint-community/eslint-utils")module.exports = { meta: {}, create(context) { return { MemberExpression(node) { const name = getPropertyName(node, context.sourceCode.getScope(node)) // When using ESLint<8.37.0, write as follows: // const name = getPropertyName(node, context.getScope()) }, } },}getStaticValue
const ret1 = utils.getStaticValue(node)const ret2 = utils.getStaticValue(node, initialScope)Get the value of a given node if it can decide the value statically.
If the 2nd parameterinitialScope was given, this function tries to resolve identifier references which are in the given node as much as possible. In the resolving way, it does on the assumption that built-in global objects have not been modified. For example, it considersSymbol.iterator,String.raw`hello`, andObject.freeze({a: 1}).a as static.
For another complex example, this function can evaluate the following cases on AST:
const eventName = "click"const aMap = Object.freeze({ click:777});`on${eventName} : ${aMap[eventName]}` // evaluated to "onclick : 777"Parameters
| Name | Type | Description |
|---|---|---|
| node | Node | The node to get that the value. |
| initialScope | Scope or undefined | Optional. The scope object to find variables. |
Return value
The{ value: any } shaped object. Thevalue property is the static value.
If it couldn't compute the static value of the node, it returnsnull.
Example
const {getStaticValue }= require("@eslint-community/eslint-utils")module.exports = { meta: {}, create(context) { return { ExpressionStatement(node) { const evaluated = getStaticValue(node, context.sourceCode.getScope(node)) // When using ESLint<8.37.0, write as follows: // const evaluated = getStaticValue(node, context.getScope()) if (evaluated) { const staticValue = evaluated.value // ... } }, } },}getStringIfConstant
const str1 = utils.getStringIfConstant(node)const str2 = utils.getStringIfConstant(node, initialScope)Get the string value of a given node.
This function is a tiny wrapper of thegetStaticValue function. I.e., this is the same as below:
function getStringIfConstant(node,initialScope) { const evaluated = getStaticValue(node, initialScope) return evaluated&& String(evaluated.value)}hasSideEffect
const ret = utils.hasSideEffect(node, sourceCode, options)Check whether a given node has any side effect or not.
The side effect means that itmay modify a certain variable or object member. This function considers the node which contains the following types as the node which has side effects:
AssignmentExpressionAwaitExpressionCallExpressionImportExpressionNewExpressionUnaryExpression([operator = "delete"])UpdateExpressionYieldExpression- When
options.considerGettersistrue:MemberExpression
- When
options.considerImplicitTypeConversionistrue:BinaryExpression([operator = "==" | "!=" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "|" | "^" | "&" | "in"])MemberExpression([computed = true])MethodDefinition([computed = true])Property([computed = true])PropertyDefinition([computed = true])UnaryExpression([operator = "-" | "+" | "!" | "~"])
Parameters
| Name | Type | Description |
|---|---|---|
| node | Node | The node to check. |
| sourceCode | SourceCode | The source code object to get visitor keys. |
| options.considerGetters | boolean | Default isfalse. Iftrue then it considers member accesses as the node which has side effects. |
| options.considerImplicitTypeConversion | boolean | Default isfalse. Iftrue then it considers implicit type conversion as the node which has side effects. |
Return value
true if the node has a certain side effect.
Example
const {hasSideEffect }= require("@eslint-community/eslint-utils")module.exports = { meta: {}, create(context) { const sourceCode = context.getSourceCode() return { ":expression"(node) { if (hasSideEffect(node, sourceCode)) { // ... } }, } },}isParenthesized
const ret1 = utils.isParenthesized(times, node, sourceCode)const ret2 = utils.isParenthesized(node, sourceCode)Check whether a given node is parenthesized or not.
This function detects it correctly even if it's parenthesized by specific syntax.
// those `a` are not parenthesized.f(a)new C(a)if (a) {}switch (a) {}while (a) {}do {}while (a)with (a) {}// those `b` are parenthesized.f(b)new C(b)if (b) {}switch (b) {}while (b) {}do {}while (b)with (b) {}Parameters
| Name | Type | Description |
|---|---|---|
| times | number | Optional. The number of redundant parenthesized. Default is1. |
| node | Node | The node to check. |
| sourceCode | SourceCode | The source code object to get tokens. |
Return value
true if the node is parenthesized.
Iftimes was given, it returnstrue only if the node is parenthesized thetimes times. For example,isParenthesized(2, node, sourceCode) returnstrue for((foo)), but not for(foo).
Example
const {isParenthesized }= require("@eslint-community/eslint-utils")module.exports = { meta: {}, create(context) { const sourceCode = context.getSourceCode() return { ":expression"(node) { if (isParenthesized(node, sourceCode)) { // ... } }, } },}PatternMatcher class
const matcher = new utils.PatternMatcher(pattern, options)The class to find a pattern in strings as handling escape sequences.
It ignores the found pattern if it's escaped with\.
Parameters
| Name | Type | Description |
|---|---|---|
| pattern | RegExp | The regular expression pattern to find. |
| options.escaped | boolean | Optional. Default isfalse. Iftrue then this matches to escaped patterns. |
matcher.execAll
const iterator = matcher.execAll(str)Iterate all matched parts in a given string.
Parameters
| Name | Type | Description |
|---|---|---|
| str | string | The string to find this pattern. |
Return value
The generator which iteratesRegExpExecArray object.
Example
const {PatternMatcher }= require("@eslint-community/eslint-utils")const matcher = new PatternMatcher(/\(\?<[_$\w]/g)module.exports = { meta: {}, create(context) { return { "Literal[regex]"(node) { for (const {index }of matcher.execAll(node.regex.pattern)) { context.report({ node, loc: { line: node.loc.start.line, column: node.loc.start.column+ index }, message:"ES2018 RegExp named capture groups", }) } }, } },}matcher.test
const matched = matcher.test(str)Check whether this pattern matches a given string or not.
Parameters
| Name | Type | Description |
|---|---|---|
| str | string | The string to find this pattern. |
Return value
true if this pattern matched the string.
Example
const {PatternMatcher }= require("@eslint-community/eslint-utils")const matcher = new PatternMatcher(/\(\?<[_$\w]/g)module.exports = { meta: {}, create(context) { return { "Literal[regex]"(node) { if (matcher.test(node.regex.pattern)) { context.report({ node, message:"RegExp has ES2018 named capture groups", }) } }, } },}matcher[Symbol.replace]
const replacedStr = str.replace(matcher, replacer)Replace all matched parts by a given replacer.
Parameters
| Name | Type | Description |
|---|---|---|
| str | string | The string to be replaced. |
| replacer | string or function | The string or function to replace each matched part. This is the same as the 2nd parameter ofString.prototype.replace. |
Return value
The replaced result.
Example
const {PatternMatcher }= require("@eslint-community/eslint-utils")const matcher = new PatternMatcher(/\\p{Script=Greek}/g)module.exports = { meta: {}, create(context) { return { "Literal[regex]"(node) { const replacedPattern = node.regex.pattern.replace( matcher, "[\\u0370-\\u0373\\u0375-\\u0377\\u037A-\\u037D\\u037F\\u0384\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03E1\\u03F0-\\u03FF\\u1D26-\\u1D2A\\u1D5D-\\u1D61\\u1D66-\\u1D6A\\u1DBF\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FC4\\u1FC6-\\u1FD3\\u1FD6-\\u1FDB\\u1FDD-\\u1FEF\\u1FF2-\\u1FF4\\u1FF6-\\u1FFE\\u2126\\uAB65]|\\uD800[\\uDD40-\\uDD8E\\uDDA0]|\\uD834[\\uDE00-\\uDE45]" ) }, } },}