Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement minify-builtins plugin #410

Merged
merged 10 commits into from Feb 16, 2017
4 changes: 4 additions & 0 deletions packages/babel-plugin-transform-built-ins/.npmignore
@@ -0,0 +1,4 @@
src
__tests__
node_modules
*.log
51 changes: 51 additions & 0 deletions packages/babel-plugin-transform-built-ins/README.md
@@ -0,0 +1,51 @@
# babel-plugin-transform-built-ins
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we just call it babel-plugin-minify-builtins

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm.. dono really..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just change it to babel-plugin-minify-builtins

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright


Transform Standard built-in Objects

## Example

**In**

```javascript
Math.floor(a) + Math.floor(b)
```

**Out**

```javascript
var _Mathfloor = Math.floor;

_Mathfloor(a) + _Mathfloor(b);
```

## Installation

```sh
npm install babel-plugin-transform-built-ins
```

## Usage

### Via `.babelrc` (Recommended)

**.babelrc**

```json
{
"plugins": ["transform-built-ins"]
}
```

### Via CLI

```sh
babel --plugins transform-built-ins script.js
```

### Via Node API

```javascript
require("babel-core").transform("code", {
plugins: ["transform-built-ins"]
});
```
@@ -0,0 +1,76 @@
exports[`transform-built-ins should collect and transform no matter any depth 1`] = `
Object {
"_source": "Math.max(a, b) + Math.max(a, b);
function a (){
Math.max(b, a);
return function b() {
const a = Math.floor(c);
Math.min(b, a) * Math.floor(b);
}
}",
"expected": "var _Mathfloor = Math.floor;
var _Mathmax = Math.max;
_Mathmax(a, b) + _Mathmax(a, b);
function a() {
_Mathmax(b, a);
return function b() {
const a = _Mathfloor(c);
Math.min(b, a) * _Mathfloor(b);
};
}",
}
`;

exports[`transform-built-ins should evalaute expressions if applicable and optimize it 1`] = `
Object {
"_source": "const a = Math.max(Math.floor(2), 5);
let b = 1.8;
let x = Math.floor(Math.max(a, b));
foo(x);",
"expected": "const a = 5;
let b = 1.8;
let x = 5;
foo(x);",
}
`;

exports[`transform-built-ins should not transform if its not a built in object 1`] = `
Object {
"_source": "Math.a(2, 1) + Math.a(1, 2);",
"expected": "Math.a(2, 1) + Math.a(1, 2);",
}
`;

exports[`transform-built-ins should take no of occurences in to account 1`] = `
Object {
"_source": "function a() {
return Math.floor(a) + Math.floor(b) + Math.min(a, b);
}
Math.floor(a) + Math.max(a, b);",
"expected": "var _Mathfloor = Math.floor;
function a() {
return _Mathfloor(a) + _Mathfloor(b) + Math.min(a, b);
}
_Mathfloor(a) + Math.max(a, b);",
}
`;

exports[`transform-built-ins should transform standard built in methods 1`] = `
Object {
"_source": "Math.max(a, b) + Math.max(b, a)",
"expected": "var _Mathmax = Math.max;
_Mathmax(a, b) + _Mathmax(b, a);",
}
`;

exports[`transform-built-ins should transform standard built in properties 1`] = `
Object {
"_source": "function a () {
return Math.PI + Math.PI
}",
"expected": "var _MathPI = Math.PI;
function a() {
return _MathPI + _MathPI;
}",
}
`;
@@ -0,0 +1,72 @@
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-built-ins", () => {
it("should transform standard built in methods", () => {
const source = unpad(`
Math.max(a, b) + Math.max(b, a)
`);
// Jest arranges in alphabetical order, So keeping it as _source
expect({_source: source, expected: transform(source)}).toMatchSnapshot();
});

it("should transform standard built in properties", () => {
const source = unpad(`
function a () {
return Math.PI + Math.PI
}
`);
expect({_source: source, expected: transform(source)}).toMatchSnapshot();
});

it("should take no of occurences in to account", () => {
const source = unpad(`
function a() {
return Math.floor(a) + Math.floor(b) + Math.min(a, b);
}
Math.floor(a) + Math.max(a, b);
`);
expect({_source: source, expected: transform(source)}).toMatchSnapshot();
});

it("should collect and transform no matter any depth", () => {
const source = unpad(`
Math.max(a, b) + Math.max(a, b);
function a (){
Math.max(b, a);
return function b() {
const a = Math.floor(c);
Math.min(b, a) * Math.floor(b);
}
}
`);
expect({_source: source, expected: transform(source)}).toMatchSnapshot();
});

it("should not transform if its not a built in object", () => {
const source = unpad(`
Math.a(2, 1) + Math.a(1, 2);
`);
expect({_source: source, expected: transform(source)}).toMatchSnapshot();
});

it("should evalaute expressions if applicable and optimize it", () => {
const source = unpad(`
const a = Math.max(Math.floor(2), 5);
let b = 1.8;
let x = Math.floor(Math.max(a, b));
foo(x);
`);
expect({_source: source, expected: transform(source)}).toMatchSnapshot();
});

});
19 changes: 19 additions & 0 deletions packages/babel-plugin-transform-built-ins/package.json
@@ -0,0 +1,19 @@
{
"name": "babel-plugin-transform-built-ins",
"version": "0.0.1",
"description": "Transform Standard built-in Objects",
"homepage": "https://github.com/babel/babili#readme",
"repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-built-ins",
"main": "lib/index.js",
"bugs": "https://github.com/babel/babili/issues",
"keywords": [
"babel-plugin",
"transform-built-ins"
],
"author": "Vignesh Shanmugam <vignesh.shanmugam22@gmail.com> (https://vigneshh.in)",
"license": "MIT",
"dependencies": {
"babel-helper-evaluate-path": "^0.0.3"
},
"devDependencies": {}
}
79 changes: 79 additions & 0 deletions packages/babel-plugin-transform-built-ins/src/builtins.js
@@ -0,0 +1,79 @@
module.exports = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way babel does this is to maintain only [String, Number, Math]

https://github.com/babel/babel/blob/f8ffe03/packages/babel-traverse/src/path/evaluation.js#L5

So, I think it's relatively safe to assume that Math.x will be a side-effect free evaluation except Math.random

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh good one.. What about Date.x?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can chuck the Date for now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool.. then will update

"properties": [
"Number.EPSILON",
"Number.MAX_SAFE_INTEGER",
"Number.MAX_VALUE",
"Number.MIN_SAFE_INTEGER",
"Number.MIN_VALUE",
"Number.NEGATIVE_INFINITY",
"Number.POSITIVE_INFINITY",
"Number.NAN",
"Math.E",
"Math.LN10",
"Math.LN2",
"Math.LOG10E",
"Math.LOG2E",
"Math.PI",
"Math.SQRT1_2",
"Math.SQRT2"
],
"methods": [
"Number.isFinite",
"Number.isInteger",
"Number.isNaN",
"Number.isSafeInteger",
"Number.parseInt",
"Number.parseFloat",
"Date.now",
"Date.parse",
"Date.UTC",
"Math.min",
"Math.max",
"Math.floor",
"Math.abs",
"Math.acos",
"Math.acosh",
"Math.asin",
"Math.asinh",
"Math.atan",
"Math.atanh",
"Math.atan2",
"Math.ceil",
"Math.cbrt",
"Math.expm1",
"Math.clz32",
"Math.cos",
"Math.cosh",
"Math.exp",
"Math.floor",
"Math.fround",
"Math.hypot",
"Math.imul",
"Math.log",
"Math.log1p",
"Math.log2",
"Math.log10",
"Math.max",
"Math.min",
"Math.pow",
"Math.round",
"Math.sign",
"Math.sin",
"Math.sinh",
"Math.sqrt",
"Math.tan",
"Math.tanh",
"Math.trunc",
"Math.E",
"Math.LN10",
"Math.LN2",
"Math.LOG10E",
"Math.LOG2E",
"Math.PI",
"Math.SQRT1_2",
"Math.SQRT2",
"Math.random"
]
};