Skip to content

Commit

Permalink
Add prefer-exponentiation-operator rule (#185)
Browse files Browse the repository at this point in the history
Fixes #173
  • Loading branch information
MrHen authored and sindresorhus committed Aug 23, 2018
1 parent 2283cda commit 9f7f811
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 1 deletion.
17 changes: 17 additions & 0 deletions docs/rules/prefer-exponentiation-operator.md
@@ -0,0 +1,17 @@
# Prefer the exponentiation operator over `Math.pow()`

Enforces the use of the [exponentiation operator](http://2ality.com/2016/02/exponentiation-operator.html) over [`Math.pow()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow).


## Fail

```js
Math.pow(2, 4);
```


## Pass

```js
2 ** 4
```
3 changes: 2 additions & 1 deletion index.js
Expand Up @@ -35,7 +35,8 @@ module.exports = {
'unicorn/prefer-spread': 'error',
'unicorn/error-message': 'error',
'unicorn/no-unsafe-regex': 'off',
'unicorn/prefer-add-event-listener': 'error'
'unicorn/prefer-add-event-listener': 'error',
'unicorn/prefer-exponentiation-operator': 'error'
}
}
}
Expand Down
1 change: 1 addition & 0 deletions readme.md
Expand Up @@ -85,6 +85,7 @@ Configure it in `package.json`.
- [error-message](docs/rules/error-message.md) - Enforce passing a `message` value when throwing a built-in error.
- [no-unsafe-regex](docs/rules/no-unsafe-regex.md) - Disallow unsafe regular expressions.
- [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) - Prefer `addEventListener` over `on`-functions. *(fixable)*
- [prefer-exponentiation-operator](docs/rules/prefer-exponentiation-operator.md) - Prefer the exponentiation operator over `Math.pow()` *(fixable)*


## Recommended config
Expand Down
54 changes: 54 additions & 0 deletions rules/prefer-exponentiation-operator.js
@@ -0,0 +1,54 @@
'use strict';
const getDocsUrl = require('./utils/get-docs-url');

const isMathPow = node => {
const {callee} = node;
return (
callee.type === 'MemberExpression' &&
callee.object.type === 'Identifier' &&
callee.object.name === 'Math' &&
callee.property.type === 'Identifier' &&
callee.property.name === 'pow'
);
};

const parseArgument = (context, arg) => {
if (arg.type === 'Identifier') {
return arg.name;
}

return context.getSourceCode().getText(arg);
};

const fix = (context, node, fixer) => {
const base = parseArgument(context, node.arguments[0]);
const exponent = parseArgument(context, node.arguments[1]);

const replacement = `${base} ** ${exponent}`;

return fixer.replaceText(node, replacement);
}

const create = context => {
return {
CallExpression(node) {
if (isMathPow(node)) {
context.report({
node,
message: 'Prefer the exponentiation operator over `Math.pow()`.',
fix: fixer => fix(context, node, fixer),
});
}
}
};
};

module.exports = {
create,
meta: {
docs: {
url: getDocsUrl(__filename)
},
fixable: 'code'
}
};
53 changes: 53 additions & 0 deletions test/prefer-exponentiation-operator.js
@@ -0,0 +1,53 @@
import test from 'ava';
import avaRuleTester from 'eslint-ava-rule-tester';
import rule from '../rules/prefer-exponentiation-operator';

const ruleTester = avaRuleTester(test, {
parserOptions: {
ecmaVersion: 2016
}
});

const message = 'Prefer the exponentiation operator over `Math.pow()`.';

ruleTester.run('prefer-exponentiation-operator', rule, {
valid: [
'a ** b;',
'2 ** 4;',
],
invalid: [
{
code: 'const x = Math.pow(2, 4);',
errors: [{message}],
output: 'const x = 2 ** 4;'
},
{
code: 'const x = Math.pow(-2, (2 - 4) +0 -0.2);',
errors: [{message}],
output: 'const x = -2 ** (2 - 4) +0 -0.2;'
},
{
code: 'const x = Math.pow(Math.pow(2, 4), 8);',
errors: [
{message, column: 11, line: 1},
{message, column: 20, line: 1},
],
output: 'const x = Math.pow(2, 4) ** 8;'
},
{
code: 'const x = Math.pow(2, b);',
errors: [{message}],
output: 'const x = 2 ** b;'
},
{
code: 'const x = Math.pow(c, 4);',
errors: [{message}],
output: 'const x = c ** 4;'
},
{
code: 'const x = Math.pow(foo(), bar());',
errors: [{message}],
output: 'const x = foo() ** bar();'
}
]
});

0 comments on commit 9f7f811

Please sign in to comment.