Skip to content

Commit

Permalink
feat: create object key lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
merceyz committed May 30, 2019
1 parent eea4081 commit 0630c91
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 8 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"dependencies": {
"@babel/generator": "^7.4.4",
"@babel/types": "^7.4.4",
"lodash": "^4.17.11"
"lodash": "^4.17.11",
"object-hash": "^1.3.1"
},
"husky": {
"hooks": {
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import combineStringLiterals from './visitors/combineStringLiterals';
import combineArguments from './visitors/combineArguments';
import createConditionalExpression from './visitors/createConditionalExpression';
import removeUnnecessaryCalls from './visitors/removeUnnecessaryCalls';
import createObjectKeyLookups from './visitors/createObjectKeyLookups';

const visitors = [
findFunctionNames,
Expand All @@ -17,6 +18,7 @@ const visitors = [
combineStringLiterals,
createConditionalExpression,
removeUnnecessaryCalls,
createObjectKeyLookups,
(path, options) => findFunctionNames(path, { ...options, _removeUnusedImports: true }),
];

Expand Down
8 changes: 8 additions & 0 deletions src/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fs from 'fs';
import path from 'path';
import generate from '@babel/generator';
import _ from 'lodash';
import hash from 'object-hash';

export function flattenLogicalOperator(node) {
if (t.isLogicalExpression(node)) {
Expand Down Expand Up @@ -103,6 +104,13 @@ export function compareNodes(obj1, obj2) {
});
}

export function hashNode(node) {
return hash(node, {
excludeKeys: key =>
key === 'start' || key === 'end' || key === 'loc' || key === 'extra' ? true : false,
});
}

export function isSafeConditional(node) {
if (!t.isConditionalExpression(node)) {
return false;
Expand Down
92 changes: 92 additions & 0 deletions src/visitors/createObjectKeyLookups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import * as t from '@babel/types';
import _ from 'lodash';
import { hashNode } from '../utils/helpers';
import generate from '@babel/generator';

function matchLeftOrRight(node, check) {
return check(node.left) || check(node.right);
}

function combineFromArray(arr) {
// x === 'foo', 'foo' === x, x.y === 'foo', 'foo' === x.y
const [match, noMatch] = _.partition(arr, item => {
return (
t.isLogicalExpression(item, { operator: '&&' }) &&
t.isBinaryExpression(item.left, { operator: '===' }) &&
matchLeftOrRight(item.left, t.isStringLiteral) &&
(matchLeftOrRight(item.left, t.isMemberExpression) ||
matchLeftOrRight(item.left, t.isIdentifier))
);
});

if (match.length === 0) {
return arr;
}

// Make sure the string is on the right side of ===
// Makes the rest of the code simpler
const rearranged = match.map(node => {
const tempNode = { ...node };
if (t.isStringLiteral(tempNode.left.left)) {
tempNode.left = t.binaryExpression('===', tempNode.left.right, tempNode.left.left);
}
return tempNode;
});

// Group on whatever the strings are compared to
const grouped = _.groupBy(rearranged, node => hashNode(node.left.left));

const newArgs = [];
_.forOwn(grouped, item => {
const result = item.reduce((acc, node) => {
let key = node.left.right;

// If possible, use a identifier as the key, saves 2 characters
if (/[^A-Za-z]/.test(node.left.right.value) === false) {
key = t.identifier(node.left.right.value);
}

acc.push(t.objectProperty(key, node.right));
return acc;
}, []);

const output = t.memberExpression(t.objectExpression(result), item[0].left.left, true);
if (item.length > 1) {
newArgs.push(output);
return;
}

// If the size is the same, use the original
const a = generate(item[0], { compact: true }).code;
const b = generate(output, { compact: true }).code;
newArgs.push(a.length <= b.length ? item[0] : output);
});

return [...noMatch, ...newArgs];
}

const arrayVisitor = {
ArrayExpression(path) {
path.node.elements = combineFromArray(path.node.elements);

if (path.node.elements.length === 1) {
path.replaceWith(path.node.elements[0]);
}
},
};

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

path.traverse(arrayVisitor);
path.node.arguments = combineFromArray(path.node.arguments);
},
};

export default (path, options) => {
path.traverse(visitor, { options });
};
6 changes: 4 additions & 2 deletions test/fixtures/combine-arguments/nested-match/output.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
clsx(
text && [
classes.text,
color === 'primary' && [classes.text, classes.textPrimary],
color === 'secondary' && classes.textSecondary,
{
primary: [classes.text, classes.textPrimary],
secondary: classes.textSecondary,
}[color],
],
);
8 changes: 5 additions & 3 deletions test/fixtures/combine-arguments/single-match/output.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
clsx(
text && [
classes.text,
color === 'foo' && classes.text,
color === 'bar' && classes.textPrimary,
color === 'baz' && classes.textSecondary,
{
foo: classes.text,
bar: classes.textPrimary,
baz: classes.textSecondary,
}[color],
],
foo && classes.text,
bar && classes.text,
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/create-lookup/different-matches/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
clsx({
[foo.a]: bar === 'up',
[foo.b]: bar === 'down',
[foo.c]: baz === 'left',
[foo.d]: baz === 'right',
});
10 changes: 10 additions & 0 deletions test/fixtures/create-lookup/different-matches/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
clsx(
{
up: foo.a,
down: foo.b,
}[bar],
{
left: foo.c,
right: foo.d,
}[baz],
);
6 changes: 6 additions & 0 deletions test/fixtures/create-lookup/multiple-matches/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
clsx({
[foo.a]: direction === 'up',
[foo.b]: direction === 'down',
[foo.c]: direction === 'left',
[foo.d]: direction === 'right',
});
8 changes: 8 additions & 0 deletions test/fixtures/create-lookup/multiple-matches/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
clsx(
{
up: foo.a,
down: foo.b,
left: foo.c,
right: foo.d,
}[direction],
);
1 change: 1 addition & 0 deletions test/fixtures/create-lookup/same-length/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
clsx(context.alignItems === 'flex-start' && classes.alignItemsFlexStart);
1 change: 1 addition & 0 deletions test/fixtures/create-lookup/same-length/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
clsx(context.alignItems === 'flex-start' && classes.alignItemsFlexStart);
4 changes: 3 additions & 1 deletion test/fixtures/strip-literals/boolean-literal/output.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
clsx(
classes.cellHide,
options.responsive === 'stacked' && classes.cellStacked,
!print && 'datatables-noprint',
{
stacked: classes.cellStacked,
}[options.responsive],
);
4 changes: 3 additions & 1 deletion test/fixtures/strip-literals/string-literal/output.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
clsx(
classes.root,
options.responsive === 'stacked' && classes.cellStacked,
!print && 'datatables-noprint',
{
stacked: classes.cellStacked,
}[options.responsive],
);
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4012,6 +4012,11 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"

object-hash@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df"
integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==

object-keys@^1.0.12:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
Expand Down

0 comments on commit 0630c91

Please sign in to comment.