Skip to content

Commit

Permalink
feat: remove unnecessary function calls
Browse files Browse the repository at this point in the history
  • Loading branch information
merceyz committed May 23, 2019
1 parent 0bc7671 commit 3ea3d85
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 1 deletion.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,30 @@ If you want the plugin to match on all functions with a specific name, no matter
]
}
```

---

| Name | Type | Default value |
| ------------------------ | --------- | ------------- |
| `removeUnnecessaryCalls` | `boolean` | `true` |

By default the plugin will remove unnecessary function calls, if for some reason you need to keep them, you can set this option to false.

Example of some unnecessary calls

```javascript
const x = clsx('foo', 'bar');
const y = clsx({ classA: foo === 'a', classB: foo !== 'a' });
const z = clsx({
classA: foo === 'a',
classB: foo !== 'a',
classC: bar === 'c',
classD: bar !== 'c',
});

// Transforms to

const x = 'foo bar';
const y = foo === 'a' ? 'classA' : 'classB';
const z = (foo === 'a' ? 'classA ' : 'classB ') + (bar === 'c' ? 'classC' : 'classD');
```
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const visitors = [
require('./visitors/combineStringLiterals'),
require('./visitors/combineArguments'),
require('./visitors/createConditionalExpression'),
require('./visitors/removeUnnecessaryCalls'),
];

module.exports = () => ({
Expand Down
1 change: 1 addition & 0 deletions src/options.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const DefaultSettings = {
libraries: ['clsx', 'classnames'],
functionNames: [],
removeUnnecessaryCalls: true,
};

module.exports = options => {
Expand Down
65 changes: 65 additions & 0 deletions src/visitors/removeUnnecessaryCalls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const t = require('@babel/types');

const visitor = {
CallExpression(path) {
const c = path.node.callee;
if (!t.isIdentifier(c) || !this.options.functionNames.includes(c.name)) {
return;
}

const argLength = path.node.arguments.length;
if (argLength > 0) {
let arg = path.node.arguments[0];
if (argLength === 1) {
if (t.isStringLiteral(arg)) {
path.replaceWith(arg);
} else if (isSafeConditional(arg)) {
path.replaceWith(arg);
}
} else if (argLength === 2) {
let arg2 = path.node.arguments[1];
if (isSafeConditional(arg) && isSafeConditional(arg2)) {
const newCond = t.conditionalExpression(
arg.test,
t.stringLiteral(arg.consequent.value + ' '),
t.stringLiteral(arg.alternate.value + ' '),
);
path.replaceWith(t.binaryExpression('+', newCond, arg2));
} else if (
(t.isStringLiteral(arg) || t.isStringLiteral(arg2)) &&
(isSafeConditional(arg) || isSafeConditional(arg2))
) {
if (t.isStringLiteral(arg)) {
path.replaceWith(t.binaryExpression('+', t.stringLiteral(arg.value + ' '), arg2));
} else {
path.replaceWith(t.binaryExpression('+', t.stringLiteral(arg2.value + ' '), arg));
}
}
}
} else if (argLength === 0) {
path.replaceWith(t.stringLiteral(''));
}

function isSafeConditional(node) {
return (
t.isConditionalExpression(node) &&
t.isStringLiteral(node.consequent) &&
t.isStringLiteral(node.alternate) &&
node.consequent.value.length > 0 &&
node.alternate.value.length > 0
);
}
},
};

module.exports = (path, options) => {
if (!t.isProgram(path.node)) {
throw new Error('Node has to be a program node');
}

if (!options.removeUnnecessaryCalls) {
return;
}

path.traverse(visitor, { options });
};
3 changes: 2 additions & 1 deletion test/fixtures/options.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"functionNames": ["clsx"]
"functionNames": ["clsx"],
"removeUnnecessaryCalls": false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const baseClass = clsx(foo ? 'a' : 'b');
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const baseClass = foo ? 'a' : 'b';
3 changes: 3 additions & 0 deletions test/fixtures/remove-unnecessary-calls/options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"removeUnnecessaryCalls": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const classA = clsx('foo bar', foo ? 'a' : 'b');
const classB = clsx(foo ? 'a' : 'b', 'foo bar');
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const classA = 'foo bar ' + (foo ? 'a' : 'b');
const classB = 'foo bar ' + (foo ? 'a' : 'b');
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const baseClass = clsx('foo bar');
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const baseClass = 'foo bar';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const baseClass = clsx(foo ? 'a' : 'b', bar ? 'c' : 'd');
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const baseClass = (foo ? 'a ' : 'b ') + (bar ? 'c' : 'd');

0 comments on commit 3ea3d85

Please sign in to comment.