319 lines
6.7 KiB
Markdown
319 lines
6.7 KiB
Markdown
# eslint-ast-utils [](https://travis-ci.org/jfmengels/eslint-ast-utils)
|
|
|
|
> Utility library to manipulate ASTs for ESLint projects
|
|
|
|
|
|
## Install
|
|
|
|
```
|
|
$ npm install --save eslint-ast-utils
|
|
```
|
|
|
|
## Usage
|
|
|
|
```js
|
|
const astUtils = require('eslint-ast-utils');
|
|
```
|
|
|
|
|
|
## API
|
|
|
|
### astUtils.isStaticRequire(node)
|
|
|
|
Checks whether `node` is a call to CommonJS's `require` function.
|
|
|
|
Returns `true` if and only if:
|
|
- `node` is a `CallExpression`
|
|
- `node`'s callee is an `Identifier` named `require`
|
|
- `node` has exactly 1 `Literal` argument whose value is a `string`
|
|
|
|
Example:
|
|
```js
|
|
require('lodash');
|
|
// => true
|
|
require(foo);
|
|
// => false
|
|
foo('lodash');
|
|
// => false
|
|
```
|
|
|
|
Usage example:
|
|
```js
|
|
function create(context) {
|
|
return {
|
|
CallExpression(node) {
|
|
if (astUtils.isStaticRequire(node)) {
|
|
context.report({
|
|
node: node,
|
|
message: 'Use import syntax rather than `require`'
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
### astUtils.getRequireSource(node)
|
|
|
|
Gets the source of a `require()` call. If `node` is not a `require` call (in the definition of [`isStaticRequire`](#astutilsisstaticrequirenode)), it will return `undefined`.
|
|
|
|
Example:
|
|
```js
|
|
require('lodash');
|
|
// => 'lodash'
|
|
require('./foo');
|
|
// => './foo'
|
|
```
|
|
|
|
Usage example:
|
|
```js
|
|
function create(context) {
|
|
return {
|
|
CallExpression(node) {
|
|
if (astUtils.isStaticRequire(node) && astUtils.getRequireSource(node) === 'underscore') {
|
|
context.report({
|
|
node: node,
|
|
message: 'Use `lodash` instead of `underscore`'
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
### astUtils.containsIdentifier(name, node)
|
|
|
|
Checks if there is a reference to a variable named `name` inside of `node`.
|
|
|
|
Returns true if and only if:
|
|
- There is an `Identifier` named `name` inside of `node`
|
|
- That `Identifier` is a variable (i.e. not a static property name for instance)
|
|
- That `Identifier` does not reference a different variable named `name` introduced in a sub-scope of `node`.
|
|
|
|
Example:
|
|
```js
|
|
foo(a);
|
|
// containsIdentifier('a', node) // => true
|
|
// containsIdentifier('b', node) // => true
|
|
|
|
function foo(fn) {
|
|
return function(a) {
|
|
return fn(a);
|
|
};
|
|
}
|
|
// containsIdentifier('a', node) // => false
|
|
```
|
|
|
|
Usage example:
|
|
```js
|
|
function create(context) {
|
|
return {
|
|
FunctionDeclaration(node) {
|
|
node.params.forEach(param => {
|
|
if (param.type === 'Identifier' && !astUtils.containsIdentifier(param.name, node.body)) {
|
|
context.report({
|
|
node: node,
|
|
message: `${name} is never used`
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
### astUtils.someContainIdentifier(name, nodes)
|
|
|
|
Checks if there is a reference to a variable named `name` inside any node of the `nodes` array. Will return `false` if `nodes` is not an array.
|
|
This is a shorthand version of [`containsIdentifier`](#astutilscontainsidentifier) that works for arrays. The following are equivalent:
|
|
|
|
```js
|
|
[node1, node2, node3].some(node => astUtils.containsIdentifier('a', node));
|
|
// equivalent to
|
|
astUtils.someContainIdentifier('a', [node1, node2, node3]);
|
|
```
|
|
|
|
### astUtils.getPropertyName(node)
|
|
|
|
Get the name of a `MemberExpression`'s property. Returns:
|
|
- a `string` if the property is accessed through dot notation.
|
|
- a `string` if the property is accessed through brackets and is a string.
|
|
- a `number` if the property is accessed through brackets and is a number.
|
|
- `undefined` if `node` is not a `MemberExpression`
|
|
- `undefined` if the property name is a hard to compute expression.
|
|
|
|
Example:
|
|
```js
|
|
foo.bar
|
|
// => 'bar'
|
|
foo['bar']
|
|
// => 'bar'
|
|
foo[bar]
|
|
// => undefined
|
|
foo[0]
|
|
// => 0 # Number
|
|
foo[null]
|
|
// => null
|
|
foo[undefined]
|
|
// => undefined
|
|
```
|
|
|
|
Usage example:
|
|
```js
|
|
function create(context) {
|
|
return {
|
|
MemberExpression(node) {
|
|
if (astUtils.getPropertyName(node).startsWith('_')) {
|
|
context.report({
|
|
node: node,
|
|
message: 'Don\'t access "private" fields'
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
### astUtils.computeStaticExpression(node)
|
|
|
|
Get the value of an expression that can be statically computed, i.e. without variables references or expressions too complex.
|
|
|
|
Returns:
|
|
- `undefined` if the value could not be statically computed.
|
|
- An object with a `value` property containing the computed value.
|
|
|
|
Example:
|
|
```js
|
|
foo
|
|
// => undefined
|
|
42
|
|
// => {value: 42}
|
|
'foo'
|
|
// => {value: 'foo'}
|
|
undefined
|
|
// => {value: undefined}
|
|
null
|
|
// => {value: null}
|
|
1 + 2 - 4 + (-1)
|
|
// => {value: -2}
|
|
true ? 1 : 2
|
|
// => {value: 1}
|
|
`foo ${'bar'}`
|
|
// => {value: 'foo bar'}
|
|
```
|
|
|
|
Usage example:
|
|
```js
|
|
function create(context) {
|
|
return {
|
|
TemplateLiteral(node) {
|
|
const expression = astUtils.computeStaticExpression(node);
|
|
if (expression) {
|
|
context.report({
|
|
node: node,
|
|
message: `You can replace this template literal by the regular string '${expression.value}'.`
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
### astUtils.isPromise(node)
|
|
|
|
Checks whether `node` is a Promise.
|
|
|
|
Returns `true` if and only if `node` is one of the following:
|
|
- a call of an expression's `then` or `catch` properties
|
|
- a call to a property of `Promise` (except `cancel`, `promisify`, `promisifyAll` and `is`)
|
|
- a call to `new Promise`
|
|
|
|
If `node` uses unknown properties of a value that would be considered a Promise, `node` itself would not be considered as a Promise.
|
|
|
|
Example:
|
|
```js
|
|
foo.then(fn);
|
|
// => true
|
|
foo.catch(fn);
|
|
// => true
|
|
foo.then(fn).catch(fn);
|
|
// => true
|
|
foo.then(fn).isFulfilled(fn); // isFulfilled(fn) may not return a Promise
|
|
// => false
|
|
|
|
Promise.resolve(value);
|
|
// => true
|
|
Promise.reject(value);
|
|
// => true
|
|
Promise.race(promises);
|
|
// => true
|
|
Promise.all(promises);
|
|
// => true
|
|
Promise.map(promises, fn); // Bluebird method
|
|
// => true
|
|
|
|
new Promise(fn);
|
|
// => true
|
|
new Promise.resolve(value);
|
|
// => false
|
|
```
|
|
|
|
Usage example:
|
|
```js
|
|
function create(context) {
|
|
function reportIfPromise(node) {
|
|
if (astUtils.isPromise(node)) {
|
|
context.report({
|
|
node: node,
|
|
message: 'Prefer using async/await'
|
|
});
|
|
}
|
|
}
|
|
|
|
return {
|
|
CallExpression: reportIfPromise,
|
|
NewExpression: reportIfPromise
|
|
};
|
|
}
|
|
```
|
|
|
|
### astUtils.isFunctionExpression(node)
|
|
|
|
Checks whether `node` is a function expression or an arrow function expression (not a function declaration).
|
|
|
|
If `node` uses unknown properties of a value that would be considered a Promise, `node` itself would not be considered as a Promise.
|
|
|
|
Example:
|
|
```js
|
|
(function foo() {})
|
|
// => true
|
|
() => {}
|
|
// => true
|
|
function foo() {} // function declaration
|
|
// => false
|
|
```
|
|
|
|
Usage example:
|
|
```js
|
|
function create(context) {
|
|
return {
|
|
CallExpression(node) {
|
|
if (node.callee.type === 'Identifier'
|
|
&& node.callee.name === 'test'
|
|
&& !astUtils.isFunctionExpression(node.arguments[0])
|
|
&& !astUtils.isFunctionExpression(node.arguments[1])
|
|
) {
|
|
context.report({
|
|
node: node,
|
|
message: 'You need to pass a function to test()'
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
## License
|
|
|
|
MIT © [Jeroen Engels](https://github.com/jfmengels)
|