diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/.npmignore b/packages/babel-plugin-transform-inline-consecutive-adds/.npmignore new file mode 100644 index 000000000..22250660e --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/.npmignore @@ -0,0 +1,4 @@ +src +__tests__ +node_modules +*.log diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/README.md b/packages/babel-plugin-transform-inline-consecutive-adds/README.md new file mode 100644 index 000000000..fd6d6cdca --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/README.md @@ -0,0 +1,66 @@ +# babel-plugin-transform-inline-consecutive-adds + +This plugin inlines consecutive property assignments, array pushes, etc. + +## Example + +**In** + +```javascript +const foo = {}; +foo.a = 42; +foo.b = ["hi"]; +foo.c = bar(); +foo.d = "str"; + +... +const bar = []; +bar.push(1); +bar.push(2); +``` + +**Out** + +```javascript +const foo = { + a: 42, + b: ["hi"], + c: bar(), + d: "str" +}; + +... +const bar = [1, 2]; +``` + +## Installation + +```sh +$ npm install babel-plugin-transform-inline-consecutive-adds +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["transform-inline-consecutive-adds"] +} +``` + +### Via CLI + +```sh +$ babel --plugins transform-inline-consecutive-adds script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["transform-inline-consecutive-adds"] +}); +``` diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/__tests__/transform-inline-consecutive-adds-test.js b/packages/babel-plugin-transform-inline-consecutive-adds/__tests__/transform-inline-consecutive-adds-test.js new file mode 100644 index 000000000..53fb3ed28 --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/__tests__/transform-inline-consecutive-adds-test.js @@ -0,0 +1,309 @@ +jest.autoMockOff(); + +const babel = require("babel-core"); +const unpad = require("../../../utils/unpad"); +const plugin = require("../src/index"); + +function transform(code) { + return babel.transform(code, { + plugins: [plugin], + }).code; +} + +describe("transform-inline-consecutive-adds-plugin", () => { + it("should collapse simple consecutive", () => { + const source = unpad(` + const foo = { + z: 3.0 + }; + foo.a = 42; + foo.b = ["hi"]; + foo.c = bar(); + foo.d = "str"; + `); + const expected = unpad(` + const foo = { + z: 3.0, + a: 42, + b: ["hi"], + c: bar(), + d: "str" + }; + `); + expect(transform(source)).toBe(expected); + }); + + it("should collapse only up to last ExpressionStatement", () => { + const source = unpad(` + const foo = {}; + foo.a = 42; + console.log(foo); + `); + const expected = unpad(` + const foo = { + a: 42 + }; + + console.log(foo); + `); + expect(transform(source)).toBe(expected); + }); + + it("should not collapse if lval is nested MemberExpression", () => { + const source = unpad(` + const foo = {}; + foo.bar.a = 42; + `); + expect(transform(source)).toBe(source); + }); + + it("should not collapse if lval has wrong name", () => { + const source = unpad(` + const foo = {}; + bar.a = 42; + `); + expect(transform(source)).toBe(source); + }); + + it("should not collapse if has direct dependency issues", () => { + const source = unpad(` + const foo = {}; + foo.a = function () { + console.log(3); + }; + foo.b = foo.a(); + `); + const expected = unpad(` + const foo = { + a: function () { + console.log(3); + } + }; + + foo.b = foo.a(); + `); + expect(transform(source)).toBe(expected); + }); + + it("should not collapse if has indirect dependency issues", () => { + const source = unpad(` + var foo = {}; + foo.a = 4; + foo.b = cat(); + function cat() { + return bar(); + } + function bar() { + console.log(foo); + return 0; + } + `); + const expected = unpad(` + var foo = { + a: 4 + }; + + foo.b = cat(); + function cat() { + return bar(); + } + function bar() { + console.log(foo); + return 0; + } + `); + expect(transform(source)).toBe(expected); + }); + + + it("should not collapse if has indirect, nested dependency issues", () => { + const source = unpad(` + var foo = {}; + foo.a = 4; + foo.b = cat(); + function cat() { + return bar(); + function bar() { + console.log(foo); + return 0; + } + } + `); + const expected = unpad(` + var foo = { + a: 4 + }; + + foo.b = cat(); + function cat() { + return bar(); + function bar() { + console.log(foo); + return 0; + } + } + `); + expect(transform(source)).toBe(expected); + }); + + it("should collapse computed properties if they are literals", () => { + const source = unpad(` + var foo = {}; + foo["a"] = 0; + foo[4] = 1; + `); + const expected = unpad(` + var foo = { + "a": 0, + 4: 1 + }; + `); + expect(transform(source)).toBe(expected); + }); + + it("should not collapse computed properties otherwise", () => { + const source = unpad(` + var foo = {}; + foo[global] = 0; + `); + expect(transform(source)).toBe(source); + }); + + it("should not collapse computed properties with dependency issues", () => { + const source = unpad(` + var foo = {}; + foo[bar()] = 0; + function bar() { + console.log(foo); + return 0; + } + `); + expect(transform(source)).toBe(source); + }); + + it("should collapse statements with multiple assignments", () => { + const source = unpad(` + var foo = {}; + foo.a = 0, foo.b = 2; + `); + const expected = unpad(` + var foo = { + a: 0, + b: 2 + }; + `); + expect(transform(source)).toBe(expected); + }); + + it("should not collapse statements with multiple assignments and dependency issues", () => { + const source = unpad(` + var foo = {}; + foo.a = 0, foo.b = bar(); + function bar() { + console.log(foo); + return 0; + } + `); + expect(transform(source)).toBe(source); + }); + + it("should collapse statements for arrays", () => { + const source = unpad(` + var foo = [1, 2]; + foo.push(3, 4), foo.push(5); + foo.push(6); + `); + const expected = unpad(` + var foo = [1, 2, 3, 4, 5, 6]; + `); + expect(transform(source)).toBe(expected); + }); + + it("should collapse statements for sets", () => { + const source = unpad(` + var foo = new Set(); + foo.add(1), foo.add(2); + foo.add(3); + `); + const expected = unpad(` + var foo = new Set([1, 2, 3]); + `); + expect(transform(source)).toBe(expected); + }); + + it("should collapse statements for array-initialized sets", () => { + const source = unpad(` + var foo = new Set([1, 2]); + foo.add(3); + `); + const expected = unpad(` + var foo = new Set([1, 2, 3]); + `); + expect(transform(source)).toBe(expected); + }); + + it("should collapse array property assignments", () => { + const source = unpad(` + var foo = []; + foo[5] = 'blah'; + foo[3] = 'blah'; + foo[7] = 'blah'; + `); + const expected = unpad(` + var foo = [,,, 'blah',, 'blah',, 'blah']; + `); + expect(transform(source)).toBe(expected); + }); + + it("should not collapse array property assignments if long", () => { + const source = unpad(` + var foo = []; + foo[10] = 'blah'; + `); + expect(transform(source)).toBe(source); + }); + + it("should not collapse array property assignments if override initial", () => { + const source = unpad(` + var foo = [1, 2, 3]; + foo[2] = 'blah'; + `); + expect(transform(source)).toBe(source); + }); + + it("should not collapse array property assignments if override dynamic", () => { + const source = unpad(` + var foo = [1, 2]; + foo[2] = 'blah'; + foo[2] = 'ok'; + `); + expect(transform(source)).toBe(source); + }); + + it("should not collapse array property assignments if index is float", () => { + const source = unpad(` + var foo = []; + foo[2.1] = 'blah'; + `); + expect(transform(source)).toBe(source); + }); + + it("should not collapse array property assignments if index is non-int as string", () => { + const source = unpad(` + var foo = []; + foo['2.1'] = 'blah'; + `); + expect(transform(source)).toBe(source); + }); + + it("should collapse array property assignments if index is int as string", () => { + const source = unpad(` + var foo = []; + foo['2'] = 'blah'; + `); + const expected = unpad(` + var foo = [,, 'blah']; + `); + expect(transform(source)).toBe(expected); + }); +}); diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/package.json b/packages/babel-plugin-transform-inline-consecutive-adds/package.json new file mode 100644 index 000000000..744737394 --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/package.json @@ -0,0 +1,16 @@ +{ + "name": "babel-plugin-transform-inline-consecutive-adds", + "version": "0.0.1", + "description": "This plugin inlines consecutive property assignments, array pushes, etc.", + "homepage": "https://github.com/babel/babili#readme", + "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-inline-consecutive-adds", + "bugs": "https://github.com/babel/babili/issues", + "author": "shinew", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/src/array-collapser.js b/packages/babel-plugin-transform-inline-consecutive-adds/src/array-collapser.js new file mode 100644 index 000000000..fbd0be597 --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/src/array-collapser.js @@ -0,0 +1,52 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class ArrayCollapser extends Collapser { + isInitTypeValid(init) { + return init.isArrayExpression(); + } + + isExpressionTypeValid(expr) { + return expr.isCallExpression(); + } + + getExpressionChecker(objName, checkReference) { + return (expr) => { + // checks expr is of form: + // foo.push(rval1, ...nrvals) + + const callee = expr.get("callee"); + + if (!callee.isMemberExpression()) { + return false; + } + + const obj = callee.get("object"), prop = callee.get("property"); + if (!obj.isIdentifier() || + obj.node.name !== objName || + !prop.isIdentifier() || + prop.node.name !== "push" + ) { + return false; + } + + const args = expr.get("arguments"); + if (args.some(checkReference)) { + return false; + } + return true; + }; + } + + extractAssignment(expr) { + return expr.node.arguments; + } + + addSuccessfully(t, args, init) { + args.map((a) => init.elements.push(a)); + return true; + } +} + +module.exports = ArrayCollapser; diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/src/array-property-collapser.js b/packages/babel-plugin-transform-inline-consecutive-adds/src/array-property-collapser.js new file mode 100644 index 000000000..32bad4fc7 --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/src/array-property-collapser.js @@ -0,0 +1,90 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class ArrayPropertyCollapser extends Collapser { + isInitTypeValid(init) { + return init.isArrayExpression(); + } + + isExpressionTypeValid(expr) { + return expr.isAssignmentExpression(); + } + + getExpressionChecker(objName, checkReference) { + return (expr) => { + // checks expr is of form: + // foo[num] = rval + + const left = expr.get("left"); + + if (!left.isMemberExpression()) { + return false; + } + + const obj = left.get("object"), prop = left.get("property"); + if (!obj.isIdentifier() || + obj.node.name !== objName) { + return false; + } + + const checkIndex = (num) => Number.isInteger(num) && num >= 0; + + if (!(prop.isNumericLiteral() || prop.isStringLiteral()) || + !checkIndex(Number(prop.node.value))) { + return false; + } + + const right = expr.get("right"); + if (checkReference(right)) { + return false; + } + + return true; + }; + } + + extractAssignment(expr) { + return [expr.node.left.property.value, expr.get("right")]; + } + + addSuccessfully(t, [index, rval], init) { + const elements = init.elements; + for (let i = elements.length; i <= index; i++) { + elements.push(null); + } + if (elements[index] !== null) { + return false; + } + elements[index] = rval.node; + return true; + } + + isSizeSmaller({ newInit, oldInit, varDecl, assignments, statements }) { + const anyUndefined = (args) => args.some((a) => a === undefined); + + // We make an inexact calculation of how much space we save. + // It's inexact because we don't know how whitespaces will get minimized, + // and other factors. + if (anyUndefined([statements[statements.length - 1].node.end, varDecl.node.end])) { + return false; + } + const statementsLength = statements[statements.length - 1].node.end - varDecl.node.end; + + // Approx. formula of the change in `init`'s length = + // (# commas added) + (size of all the new rvals added), where + // # commas added = (difference between the lengths of the old and new arrays) + + const numCommaAdded = newInit.elements.length - oldInit.elements.length; + if (anyUndefined(assignments.map(([, rval]) => rval.node.end)) || + anyUndefined(assignments.map(([, rval]) => rval.node.start))) { + return false; + } + const sizeOfRvals = assignments.map(([, rval]) => rval.node.end - rval.node.start + 1) // add 1 for space in front + .reduce((a, b) => a + b, 0); // sum + + return (numCommaAdded + sizeOfRvals < statementsLength); + } +} + +module.exports = ArrayPropertyCollapser; diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/src/collapser.js b/packages/babel-plugin-transform-inline-consecutive-adds/src/collapser.js new file mode 100644 index 000000000..7abfb7399 --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/src/collapser.js @@ -0,0 +1,31 @@ +"use strict"; + +const NotImplementedError = Error("NotImplementedError"); + +class Collapser { + isInitTypeValid() { + throw NotImplementedError; + } + + isExpressionTypeValid() { + throw NotImplementedError; + } + + getExpressionChecker() { + throw NotImplementedError; + } + + extractAssignment() { + throw NotImplementedError; + } + + addSuccessfully() { + throw NotImplementedError; + } + + isSizeSmaller() { + return true; + } +} + +module.exports = Collapser; diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/src/index.js b/packages/babel-plugin-transform-inline-consecutive-adds/src/index.js new file mode 100644 index 000000000..517d5858c --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/src/index.js @@ -0,0 +1,199 @@ +"use strict"; + +const COLLAPSERS = [ + require("./object-collapser"), + require("./array-collapser"), + require("./array-property-collapser"), + require("./set-collapser"), +].map((Collapser) => { + return new Collapser(); +}); + +function getFunctionParent(path, scopeParent) { + const parent = path.findParent((p) => p.isFunction()); + // don"t traverse higher than the function the var is defined in. + return parent === scopeParent ? null : parent; +} + +function getFunctionReferences(path, scopeParent, references = new Set()) { + for (let func = getFunctionParent(path, scopeParent); func; func = getFunctionParent(func, scopeParent)) { + const id = func.node.id; + const binding = id && func.scope.getBinding(id.name); + + if (!binding) { + continue; + } + + binding.referencePaths.forEach((path) => { + if (!references.has(path)) { + references.add(path); + getFunctionReferences(path, scopeParent, references); + } + }); + } + return references; +} + +function getIdAndFunctionReferences(name, parent) { + // Returns false if there's an error. Otherwise returns a list of references. + const binding = parent.scope.getBinding(name); + if (!binding) { + return false; + } + + const references = binding.referencePaths + .reduce((references, ref) => { + references.add(ref); + getFunctionReferences(ref, parent, references); + return references; + }, new Set()); + + return Array.from(references); +} + +function validateTopLevel(path) { + // Ensures the structure is of the form (roughly): + // { + // ... + // var foo = expr; + // ... + // } + // returns null if not of this form + // otherwise returns [foo as string, ?rval, index of the variable declaration] + + const declarations = path.get("declarations"); + if (declarations.length !== 1) { + return; + } + + const declaration = declarations[0]; + const id = declaration.get("id"), init = declaration.get("init"); + if (!id.isIdentifier()) { + return; + } + + const parent = path.parentPath; + if (!parent.isBlockParent() || !parent.isScopable()) { + return; + } + + const body = parent.get("body"); + if (!Array.isArray(body)) { + return; + } + const startIndex = body.indexOf(path); + if (startIndex === -1) { + return; + } + + return [id.node.name, init, startIndex]; +} + +function collectExpressions(path, isExprTypeValid) { + // input: ExprStatement => 'a | SequenceExpression + // SequenceExpression => 'a list + // Validates 'a is of the right type + // returns null if found inconsistency, else returns Array<"a> + if (path.isExpressionStatement()) { + const exprs = collectExpressions(path.get("expression"), isExprTypeValid); + return (exprs !== null) ? exprs : null; + } + + if (path.isSequenceExpression()) { + const exprs = path.get("expressions") + .map((p) => collectExpressions(p, isExprTypeValid)); + if (exprs.some((e) => e === null)) { + return null; + } else { + return exprs.reduce((s, n) => s.concat(n), []); // === Array.flatten + } + } + + if (isExprTypeValid(path)) { + return [path]; + } + + return null; +} + +function getContiguousStatementsAndExpressions(body, start, end, isExprTypeValid, checkExpr) { + const statements = []; + let allExprs = []; + for (let i = start; i < end; i++) { + const exprs = collectExpressions(body[i], isExprTypeValid); + if (exprs === null || !exprs.every((e) => checkExpr(e))) { + break; + } + statements.push(body[i]); + allExprs = allExprs.concat(exprs); + } + return [statements, allExprs]; +} + +function getReferenceChecker(references) { + // returns a function s.t. given an expr, returns true iff expr is an ancestor of a reference + return (expr) => references.some((r) => r.isDescendant(expr)); +} + +function tryUseCollapser(t, collapser, varDecl, topLevel, checkReference) { + // Returns true iff successfully used the collapser. Otherwise returns undefined. + const [name, init, startIndex] = topLevel; + const body = varDecl.parentPath.get("body"); + if (!collapser.isInitTypeValid(init)) { + return; + } + + const [statements, exprs] = getContiguousStatementsAndExpressions( + body, + startIndex + 1, + body.length, + collapser.isExpressionTypeValid, + collapser.getExpressionChecker(name, checkReference) + ); + + if (statements.length === 0) { + return; + } + + const assignments = exprs.map((e) => collapser.extractAssignment(e)); + const oldInit = init.node; + const newInit = t.cloneDeep(oldInit); + if (!assignments.every( + (assignment) => collapser.addSuccessfully(t, assignment, newInit))) { + return; + } + + // some collapses may increase the size + if (!collapser.isSizeSmaller({ newInit, oldInit, varDecl, assignments, statements })) { + return; + } + + init.replaceWith(newInit); + statements.forEach((s) => s.remove()); + return true; +} + +module.exports = function({ types: t }) { + return { + name: "transform-inline-consecutive-adds", + visitor: { + VariableDeclaration(varDecl) { + const topLevel = validateTopLevel(varDecl); + if (!topLevel) { + return; + } + + const [name,,] = topLevel; + const references = getIdAndFunctionReferences(name, varDecl.parentPath); + if (references === false) { + return; + } + const checkReference = getReferenceChecker(references); + + if (COLLAPSERS.some((c) => tryUseCollapser(t, c, varDecl, topLevel, checkReference))) { + return; + } + }, + }, + }; +}; diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/src/object-collapser.js b/packages/babel-plugin-transform-inline-consecutive-adds/src/object-collapser.js new file mode 100644 index 000000000..af3d17324 --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/src/object-collapser.js @@ -0,0 +1,55 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class ObjectCollapser extends Collapser { + isInitTypeValid(init) { + return init.isObjectExpression(); + } + + isExpressionTypeValid(expr) { + return expr.isAssignmentExpression(); + } + + getExpressionChecker(objName, checkReference) { + return (expr) => { + // checks expr is of form: + // foo.a = rval | foo[a] = rval + + const left = expr.get("left"); + if (!left.isMemberExpression()) { + return false; + } + + const obj = left.get("object"), prop = left.get("property"); + if (!obj.isIdentifier() || obj.node.name !== objName) { + return false; + } + if (!prop.isIdentifier() && checkReference(prop)) { + return false; + } + if (left.node.computed && + !(prop.isStringLiteral() || prop.isNumericLiteral())) { + return false; + } + + const right = expr.get("right"); + if (checkReference(right)) { + return false; + } + + return true; + }; + } + + extractAssignment(expr) { + return [expr.node.left.property, expr.node.right]; + } + + addSuccessfully(t, [left, right], init) { + init.properties.push(t.objectProperty(left, right)); + return true; + } +} + +module.exports = ObjectCollapser; diff --git a/packages/babel-plugin-transform-inline-consecutive-adds/src/set-collapser.js b/packages/babel-plugin-transform-inline-consecutive-adds/src/set-collapser.js new file mode 100644 index 000000000..a74ab6124 --- /dev/null +++ b/packages/babel-plugin-transform-inline-consecutive-adds/src/set-collapser.js @@ -0,0 +1,63 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class SetCollapser extends Collapser { + isInitTypeValid(init) { + return init.isNewExpression() && + init.get("callee").isIdentifier() && + init.node.callee.name === "Set" && + // other iterables might not be append-able + (init.node.arguments.length === 0 || + (init.node.arguments.length === 1 && init.get("arguments")[0].isArrayExpression())); + } + + isExpressionTypeValid(expr) { + return expr.isCallExpression(); + } + + getExpressionChecker(objName, checkReference) { + return (expr) => { + // checks expr is of form: + // foo.add(rval) + + const callee = expr.get("callee"); + + if (!callee.isMemberExpression()) { + return false; + } + + const obj = callee.get("object"), prop = callee.get("property"); + if (!obj.isIdentifier() || + obj.node.name !== objName || + !prop.isIdentifier() || + prop.node.name !== "add" + ) { + return false; + } + + const args = expr.get("arguments"); + if (args.length !== 1) { + return false; + } + if (checkReference(args)) { + return false; + } + return true; + }; + } + + extractAssignment(expr) { + return expr.node.arguments[0]; + } + + addSuccessfully(t, arg, init) { + if (init.arguments.length === 0) { + init.arguments.push(t.arrayExpression()); + } + init.arguments[0].elements.push(arg); + return true; + } +} + +module.exports = SetCollapser; diff --git a/packages/babel-preset-babili/__tests__/__snapshots__/options-tests.js.snap b/packages/babel-preset-babili/__tests__/__snapshots__/options-tests.js.snap index 80879ed4c..72301e75c 100644 --- a/packages/babel-preset-babili/__tests__/__snapshots__/options-tests.js.snap +++ b/packages/babel-preset-babili/__tests__/__snapshots__/options-tests.js.snap @@ -11,6 +11,7 @@ Object { "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -40,6 +41,7 @@ Object { "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -78,6 +80,7 @@ Object { "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -126,6 +129,7 @@ Object { "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -173,6 +177,7 @@ Object { "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -200,6 +205,7 @@ Object { "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -241,6 +247,7 @@ Object { "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -265,6 +272,7 @@ Array [ "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -288,6 +296,7 @@ Array [ "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", @@ -311,6 +320,7 @@ Array [ "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", diff --git a/packages/babel-preset-babili/__tests__/options-tests.js b/packages/babel-preset-babili/__tests__/options-tests.js index 381684bc7..696597ebd 100644 --- a/packages/babel-preset-babili/__tests__/options-tests.js +++ b/packages/babel-preset-babili/__tests__/options-tests.js @@ -4,23 +4,24 @@ const mocks = [ "babel-plugin-minify-constant-folding", "babel-plugin-minify-dead-code-elimination", "babel-plugin-minify-flip-comparisons", - "babel-plugin-transform-simplify-comparison-operators", "babel-plugin-minify-guarded-expressions", - "babel-plugin-minify-type-constructors", "babel-plugin-minify-infinity", "babel-plugin-minify-mangle-names", "babel-plugin-minify-numeric-literals", "babel-plugin-minify-replace", "babel-plugin-minify-simplify", + "babel-plugin-minify-type-constructors", + "babel-plugin-transform-inline-consecutive-adds", "babel-plugin-transform-member-expression-literals", - "babel-plugin-transform-property-literals", "babel-plugin-transform-merge-sibling-variables", "babel-plugin-transform-minify-booleans", - "babel-plugin-transform-undefined-to-void", + "babel-plugin-transform-property-literals", "babel-plugin-transform-regexp-constructors", - "babel-plugin-transform-remove-debugger", "babel-plugin-transform-remove-console", + "babel-plugin-transform-remove-debugger", "babel-plugin-transform-remove-undefined", + "babel-plugin-transform-simplify-comparison-operators", + "babel-plugin-transform-undefined-to-void", ]; mocks.forEach((mockName) => { @@ -31,7 +32,7 @@ mocks.forEach((mockName) => { const preset = require("../src/index"); function getPlugins(opts) { - return preset({}, opts).plugins; + return preset({}, opts).presets[0].plugins; } function testOpts(opts) { diff --git a/packages/babel-preset-babili/package.json b/packages/babel-preset-babili/package.json index 1d34c418f..06637d3d8 100644 --- a/packages/babel-preset-babili/package.json +++ b/packages/babel-preset-babili/package.json @@ -22,16 +22,17 @@ "babel-plugin-minify-replace": "^0.0.1", "babel-plugin-minify-simplify": "^0.0.5", "babel-plugin-minify-type-constructors": "^0.0.2", + "babel-plugin-transform-inline-consecutive-adds": "^0.0.1", "babel-plugin-transform-member-expression-literals": "^6.8.0", "babel-plugin-transform-merge-sibling-variables": "^6.8.0", "babel-plugin-transform-minify-booleans": "^6.8.0", "babel-plugin-transform-property-literals": "^6.8.0", "babel-plugin-transform-regexp-constructors": "^0.0.4", + "babel-plugin-transform-remove-console": "^6.8.0", + "babel-plugin-transform-remove-debugger": "^6.8.0", "babel-plugin-transform-remove-undefined": "^0.0.3", "babel-plugin-transform-simplify-comparison-operators": "^6.8.0", "babel-plugin-transform-undefined-to-void": "^6.8.0", - "babel-plugin-transform-remove-debugger": "^6.8.0", - "babel-plugin-transform-remove-console": "^6.8.0", "lodash.isplainobject": "^4.0.6" }, "devDependencies": {} diff --git a/packages/babel-preset-babili/src/index.js b/packages/babel-preset-babili/src/index.js index 32622df07..ae26a457b 100644 --- a/packages/babel-preset-babili/src/index.js +++ b/packages/babel-preset-babili/src/index.js @@ -5,25 +5,26 @@ const {group, option, proxy, generate} = require("./options-manager"); // This is to prevent dynamic requires - require('babel-plugin-' + name); // as it suffers during bundling of this code with webpack/browserify const PLUGINS = [ - ["evaluate", require("babel-plugin-minify-constant-folding"), true], + ["booleans", require("babel-plugin-transform-minify-booleans"), true], + ["consecutiveAdds", require("babel-plugin-transform-inline-consecutive-adds"), true], ["deadcode", require("babel-plugin-minify-dead-code-elimination"), true], + ["evaluate", require("babel-plugin-minify-constant-folding"), true], ["flipComparisons", require("babel-plugin-minify-flip-comparisons"), true], ["guards", require("babel-plugin-minify-guarded-expressions"), true], ["infinity", require("babel-plugin-minify-infinity"), true], ["mangle", require("babel-plugin-minify-mangle-names"), true], - ["numericLiterals", require("babel-plugin-minify-numeric-literals"), true], - ["replace", require("babel-plugin-minify-replace"), true], - ["simplify", require("babel-plugin-minify-simplify"), true], - ["typeConstructors", require("babel-plugin-minify-type-constructors"), true], ["memberExpressions", require("babel-plugin-transform-member-expression-literals"), true], ["mergeVars", require("babel-plugin-transform-merge-sibling-variables"), true], - ["booleans", require("babel-plugin-transform-minify-booleans"), true], + ["numericLiterals", require("babel-plugin-minify-numeric-literals"), true], ["propertyLiterals", require("babel-plugin-transform-property-literals"), true], ["regexpConstructors", require("babel-plugin-transform-regexp-constructors"), true], ["removeConsole", require("babel-plugin-transform-remove-console"), false], ["removeDebugger", require("babel-plugin-transform-remove-debugger"), false], ["removeUndefined", require("babel-plugin-transform-remove-undefined"), true], + ["replace", require("babel-plugin-minify-replace"), true], + ["simplify", require("babel-plugin-minify-simplify"), true], ["simplifyComparisons", require("babel-plugin-transform-simplify-comparison-operators"), true], + ["typeConstructors", require("babel-plugin-minify-type-constructors"), true], ["undefinedToVoid", require("babel-plugin-transform-undefined-to-void"), true], ]; @@ -67,6 +68,7 @@ function preset(context, _opts = {}) { optionsMap.simplify, group("properties", [ + optionsMap.consecutiveAdds, optionsMap.memberExpressions, optionsMap.propertyLiterals, ]), @@ -100,6 +102,9 @@ function preset(context, _opts = {}) { return { minified: true, - plugins, + presets: [ + { plugins } + ], + passPerPreset: true, }; }