├── NPM_OWNERS ├── scripts ├── NPM_OWNERS ├── gcc.jar ├── npm-owner-grant.sh ├── npm-owner-update.sh ├── benchmark_assets │ └── LICENSE-examples ├── plugin-timing.js └── plugin-contribution.js ├── .gitignore ├── packages ├── babel-preset-babili │ ├── .npmignore │ ├── package.json │ ├── __tests__ │ │ ├── preset-tests.js │ │ └── options-tests.js │ ├── src │ │ └── index.js │ └── README.md ├── babili │ ├── bin │ │ └── babili.js │ ├── src │ │ └── index.js │ ├── README.md │ └── package.json ├── babel-helper-is-void-0 │ ├── .npmignore │ ├── README.md │ ├── src │ │ └── index.js │ └── package.json ├── babel-helper-evaluate-path │ ├── .npmignore │ ├── README.md │ ├── src │ │ └── index.js │ └── package.json ├── babel-helper-flip-expressions │ ├── .npmignore │ ├── README.md │ ├── package.json │ └── src │ │ └── index.js ├── babel-helper-remove-or-void │ ├── .npmignore │ ├── README.md │ ├── package.json │ └── src │ │ └── index.js ├── babel-plugin-minify-builtins │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── __tests__ │ │ ├── minify-builtins.js │ │ └── __snapshots__ │ │ │ └── minify-builtins.js.snap │ └── src │ │ └── index.js ├── babel-plugin-minify-infinity │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── index.js │ └── __tests__ │ │ └── infinity-test.js ├── babel-plugin-minify-replace │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── index.js │ └── __tests__ │ │ └── replace-test.js ├── babel-plugin-minify-simplify │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── pattern-match.js │ └── __tests__ │ │ └── pattern-match.js ├── babel-plugin-minify-empty-function │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── __tests__ │ │ └── empty-function-test.js │ └── src │ │ └── index.js ├── babel-plugin-minify-mangle-names │ ├── .npmignore │ ├── package.json │ └── README.md ├── babel-plugin-minify-constant-folding │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── __tests__ │ │ └── constant-folding-test.js │ └── src │ │ └── index.js ├── babel-plugin-minify-flip-comparisons │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── index.js │ └── __tests__ │ │ └── flip-comparisons-test.js ├── babel-plugin-minify-guarded-expressions │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── index.js │ └── __tests__ │ │ └── guarded-expressions-test.js ├── babel-plugin-minify-numeric-literals │ ├── .npmignore │ ├── package.json │ ├── src │ │ └── index.js │ ├── README.md │ └── __tests__ │ │ └── numeric-literals-test.js ├── babel-plugin-minify-type-constructors │ ├── .npmignore │ ├── package.json │ ├── README.md │ └── src │ │ └── index.js ├── babel-plugin-transform-minify-booleans │ ├── .npmignore │ ├── __tests__ │ │ └── booleans-test.js │ ├── src │ │ └── index.js │ ├── package.json │ └── README.md ├── babel-plugin-transform-node-env-inline │ ├── .npmignore │ ├── package.json │ ├── __tests__ │ │ └── node-env-inline-test.js │ ├── src │ │ └── index.js │ └── README.md ├── babel-plugin-transform-remove-console │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── index.js │ └── __tests__ │ │ └── remove-console-test.js ├── babel-plugin-transform-remove-debugger │ ├── .npmignore │ ├── src │ │ └── index.js │ ├── package.json │ ├── README.md │ └── __tests__ │ │ └── remove-debugger-test.js ├── babel-plugin-transform-remove-undefined │ ├── .npmignore │ ├── package.json │ ├── README.md │ └── src │ │ └── index.js ├── babel-plugin-minify-dead-code-elimination │ ├── .npmignore │ ├── package.json │ └── README.md ├── babel-plugin-transform-property-literals │ ├── .npmignore │ ├── package.json │ ├── src │ │ └── index.js │ ├── README.md │ └── __tests__ │ │ └── transform-property-literals-test.js ├── babel-plugin-transform-regexp-constructors │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── index.js │ └── __tests__ │ │ └── transform-regexp-constructors-test.js ├── babel-plugin-transform-undefined-to-void │ ├── .npmignore │ ├── src │ │ └── index.js │ ├── package.json │ ├── __tests__ │ │ └── undefined-test.js │ └── README.md ├── babel-helper-to-multiple-sequence-expressions │ ├── .npmignore │ ├── README.md │ ├── package.json │ └── src │ │ └── index.js ├── babel-plugin-transform-inline-consecutive-adds │ ├── .npmignore │ ├── src │ │ ├── collapser.js │ │ ├── array-collapser.js │ │ ├── object-collapser.js │ │ ├── set-collapser.js │ │ └── array-property-collapser.js │ ├── package.json │ └── README.md ├── babel-plugin-transform-member-expression-literals │ ├── .npmignore │ ├── package.json │ ├── src │ │ └── index.js │ ├── README.md │ └── __tests__ │ │ └── transform-member-expression-literals-test.js ├── babel-plugin-transform-merge-sibling-variables │ ├── .npmignore │ ├── package.json │ ├── README.md │ ├── src │ │ └── index.js │ └── __tests__ │ │ └── transform-merge-sibling-variables-test.js ├── babel-plugin-transform-inline-environment-variables │ ├── .npmignore │ ├── src │ │ └── index.js │ ├── package.json │ ├── __tests__ │ │ └── inline-env-var-test.js │ └── README.md ├── babel-plugin-transform-simplify-comparison-operators │ ├── .npmignore │ ├── package.json │ ├── src │ │ └── index.js │ ├── README.md │ └── __tests__ │ │ └── strict-equals-test.js └── babel-helper-mark-eval-scopes │ ├── README.md │ ├── package.json │ ├── __tests__ │ └── helper-mark-eval-scopes-test.js │ └── src │ └── index.js ├── .babelrc ├── .editorconfig ├── .eslintrc ├── utils └── unpad.js ├── .travis.yml ├── lerna.json ├── LICENSE ├── gulpfile.babel.js ├── CODE_OF_CONDUCT.md ├── package.json └── CONTRIBUTING.md /NPM_OWNERS: -------------------------------------------------------------------------------- 1 | amasad 2 | hzoo 3 | kangax 4 | boopathi 5 | -------------------------------------------------------------------------------- /scripts/NPM_OWNERS: -------------------------------------------------------------------------------- 1 | hzoo 2 | amasad 3 | kangax 4 | boopathi 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .test_gen_* 4 | lib/ 5 | *.log 6 | -------------------------------------------------------------------------------- /packages/babel-preset-babili/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babili/bin/babili.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require("../lib/index"); 4 | -------------------------------------------------------------------------------- /scripts/gcc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josephfrazier/babili/master/scripts/gcc.jar -------------------------------------------------------------------------------- /packages/babel-helper-is-void-0/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-helper-evaluate-path/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-helper-flip-expressions/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-helper-remove-or-void/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-builtins/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-infinity/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-replace/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-simplify/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-empty-function/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-mangle-names/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-constant-folding/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-flip-comparisons/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-guarded-expressions/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-numeric-literals/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-type-constructors/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-minify-booleans/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-node-env-inline/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-console/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-debugger/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-undefined/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-dead-code-elimination/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-property-literals/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-regexp-constructors/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-undefined-to-void/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-helper-to-multiple-sequence-expressions/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-member-expression-literals/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-merge-sibling-variables/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-environment-variables/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-simplify-comparison-operators/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | __tests__ 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "targets": { 5 | "node": 4 6 | } 7 | }] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/babel-helper-is-void-0/README.md: -------------------------------------------------------------------------------- 1 | # babel-helper-is-void-0 2 | 3 | ## Installation 4 | 5 | ```sh 6 | npm install babel-helper-is-void-0 7 | ``` 8 | -------------------------------------------------------------------------------- /packages/babel-helper-remove-or-void/README.md: -------------------------------------------------------------------------------- 1 | # babel-helper-remove-or-void 2 | 3 | ## Installation 4 | 5 | ```sh 6 | npm install babel-helper-remove-or-void 7 | ``` 8 | -------------------------------------------------------------------------------- /packages/babel-helper-flip-expressions/README.md: -------------------------------------------------------------------------------- 1 | # babel-helper-flip-expressions 2 | 3 | ## Installation 4 | 5 | ```sh 6 | npm install babel-helper-flip-expressions 7 | ``` 8 | -------------------------------------------------------------------------------- /packages/babel-helper-to-multiple-sequence-expressions/README.md: -------------------------------------------------------------------------------- 1 | # babel-helper-to-multiple-sequence-expressions 2 | 3 | ## Installation 4 | 5 | ```sh 6 | npm install babel-helper-to-multiple-sequence-expressions 7 | ``` 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | end_of_line = lf 8 | 9 | [*.{js,json}] 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /packages/babel-helper-evaluate-path/README.md: -------------------------------------------------------------------------------- 1 | # # babel-helper-evaluate-path 2 | 3 | `path.evaluate` wrapped in a try catch 4 | 5 | ## Installation 6 | 7 | ```sh 8 | npm install babel-helper-evaluate-path 9 | ``` 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "babel", 3 | "parserOptions": { 4 | "ecmaVersion": 7, 5 | "sourceType": "module" 6 | }, 7 | "env": { 8 | "jest": true 9 | }, 10 | "rules": { 11 | "max-len": [1, 120, 4] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/babel-helper-evaluate-path/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function evaluate(path) { 2 | try { 3 | return path.evaluate(); 4 | } catch (e) { 5 | return { 6 | confident: false, 7 | error: e 8 | }; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /packages/babel-helper-is-void-0/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function(t) { 2 | return function isVoid0(expr) { 3 | return ( 4 | t.isUnaryExpression(expr, { operator: "void" }) && 5 | t.isNumericLiteral(expr.argument, { value: 0 }) 6 | ); 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/babel-helper-mark-eval-scopes/README.md: -------------------------------------------------------------------------------- 1 | # babel-helper-mark-eval-scopes 2 | 3 | Traverse through input path and mark all scopes that contain Direct eval (`eval("")`) calls. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | npm install babel-helper-mark-eval-scopes 9 | ``` 10 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-debugger/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function() { 4 | return { 5 | name: "transform-remove-debugger", 6 | visitor: { 7 | DebuggerStatement(path) { 8 | path.remove(); 9 | }, 10 | }, 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /utils/unpad.js: -------------------------------------------------------------------------------- 1 | // Remove padding from a string. 2 | function unpad(str) { 3 | const lines = str.split('\n'); 4 | const m = lines[1] && lines[1].match(/^\s+/); 5 | if (!m) { 6 | return str; 7 | } 8 | const spaces = m[0].length; 9 | return lines.map( 10 | line => line.slice(spaces) 11 | ).join('\n').trim(); 12 | } 13 | 14 | module.exports = unpad; 15 | -------------------------------------------------------------------------------- /packages/babili/src/index.js: -------------------------------------------------------------------------------- 1 | import child from "child_process"; 2 | 3 | const args = [ 4 | require.resolve("babel-cli/bin/babel.js"), 5 | ...process.argv.slice(2), 6 | `--presets=${require.resolve("babel-preset-babili")}`, 7 | "--no-babelrc", 8 | ]; 9 | 10 | const opts = { 11 | stdio: "inherit", 12 | env: process.env, 13 | }; 14 | 15 | 16 | child.spawn(process.execPath, args, opts); 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | git: 3 | depth: 10 4 | sudo: false 5 | language: node_js 6 | cache: 7 | directories: 8 | - node_modules 9 | 10 | node_js: 11 | - '7' 12 | - '6' 13 | - '4' 14 | 15 | script: 16 | - 'if [ -n "${LINT-}" ]; then npm run lint ; fi' 17 | - npm run bootstrap 18 | - npm run build 19 | - npm run test 20 | 21 | matrix: 22 | fast_finish: true 23 | include: 24 | - node_js: "node" 25 | env: LINT=true 26 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-undefined-to-void/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | const VOID_0 = t.unaryExpression("void", t.numericLiteral(0), true); 5 | 6 | return { 7 | name: "transform-undefined-to-void", 8 | visitor: { 9 | ReferencedIdentifier(path) { 10 | if (path.node.name === "undefined") { 11 | path.replaceWith(VOID_0); 12 | } 13 | }, 14 | }, 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /scripts/npm-owner-grant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | read -p "Username: " username 5 | read -p "Are you sure you want to add $username to all packages (y/n)? " confirm 6 | 7 | if [ "$confirm" != "y" ]; then 8 | echo "Ok bye." 9 | exit 0 10 | fi 11 | 12 | for f in packages/*; do 13 | package=`basename $f` 14 | 15 | if [ -d "$f" ] && [ -e "$f/package.json" ]; then 16 | npm owner add $username $package 17 | fi 18 | done 19 | 20 | echo "$username" >> NPM_OWNERS 21 | 22 | echo "Success." 23 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-minify-booleans/__tests__/booleans-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [plugin], 9 | }).code; 10 | } 11 | 12 | describe("boolean-plugin", () => { 13 | it("should shorten bool", () => { 14 | const source = "true; false;"; 15 | const expected = "!0;!1;"; 16 | expect(transform(source)).toBe(expected); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/babel-helper-is-void-0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-helper-is-void-0", 3 | "version": "0.0.1", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-helper-is-void-0", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-helper-remove-or-void/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-helper-remove-or-void", 3 | "version": "0.0.1", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-helper-remove-or-void", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-infinity/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-infinity", 3 | "version": "0.0.3", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-infinity", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-replace/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-replace", 3 | "version": "0.0.3", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-replace", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /scripts/npm-owner-update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | cat NPM_OWNERS 5 | read -p "Do you want to add the above owners to all packages (y/n)? " confirm 6 | 7 | if [ "$confirm" != "y" ]; then 8 | echo "Ok bye." 9 | exit 0 10 | fi 11 | 12 | while read username 13 | do 14 | for f in packages/*; do 15 | package=`basename $f` 16 | 17 | if [ -d "$f" ] && [ -e "$f/package.json" ]; then 18 | echo "Adding $username to $package." 19 | npm owner add $username $package 20 | fi 21 | done 22 | done < NPM_OWNERS 23 | 24 | echo "Success." 25 | -------------------------------------------------------------------------------- /packages/babel-helper-flip-expressions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-helper-flip-expressions", 3 | "version": "0.0.2", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-helper-flip-expressions", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-environment-variables/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | return { 5 | name: "transform-inline-environment-variables", 6 | visitor: { 7 | MemberExpression(path) { 8 | if (path.get("object").matchesPattern("process.env")) { 9 | const key = path.toComputedKey(); 10 | if (t.isStringLiteral(key)) { 11 | path.replaceWith(t.valueToNode(process.env[key.value])); 12 | } 13 | } 14 | }, 15 | }, 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-minify-booleans/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | const TRUE = t.unaryExpression("!", t.numericLiteral(0), true); 5 | const FALSE = t.unaryExpression("!", t.numericLiteral(1), true); 6 | 7 | return { 8 | name: "transform-minify-booleans", 9 | visitor: { 10 | // shorten booleans to a negation 11 | // true -> !0 12 | // false -> !1 13 | BooleanLiteral(path) { 14 | path.replaceWith(path.node.value ? TRUE : FALSE); 15 | }, 16 | }, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/babel-helper-evaluate-path/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-helper-evaluate-path", 3 | "version": "0.0.3", 4 | "description": "path.evaluate wrapped in a try catch", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-helper-evaluate-path", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "boopathi", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin", 13 | "babili" 14 | ], 15 | "dependencies": {}, 16 | "devDependencies": {} 17 | } 18 | -------------------------------------------------------------------------------- /packages/babel-helper-to-multiple-sequence-expressions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-helper-to-multiple-sequence-expressions", 3 | "version": "0.0.3", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-helper-to-multiple-sequence-expressions", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-console/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-remove-console", 3 | "version": "6.8.0", 4 | "description": "Remove all console.* calls.", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-remove-console", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babili/README.md: -------------------------------------------------------------------------------- 1 | # babili 2 | 3 | [`babili`](/packages/babili) [![npm](https://img.shields.io/npm/v/babili.svg?maxAge=2592000)](https://www.npmjs.com/package/babili) 4 | 5 | Use `babili` if you don't already use babel (as a preset) or want to run it standalone. Equivalent to using `babel-cli` but only for minification. 6 | 7 | ## Installation 8 | 9 | ```sh 10 | npm install babili --save-dev 11 | ``` 12 | 13 | ### Usage 14 | 15 | ```bash 16 | # global 17 | babili src -d lib 18 | # local 19 | ./node_modules/.bin/babili src -d lib 20 | ``` 21 | 22 | Equivalent to: 23 | `babel src -d lib --presets=babili` 24 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-debugger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-remove-debugger", 3 | "version": "6.8.0", 4 | "description": "Remove debugger statements", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-remove-debugger", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-empty-function/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-empty-function", 3 | "version": "0.0.1", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-empty-function", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-remove-or-void": "^0.0.1" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-mangle-names/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-mangle-names", 3 | "version": "0.0.7", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-mangle-names", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-mark-eval-scopes": "^0.0.2" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /packages/babel-helper-mark-eval-scopes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-helper-mark-eval-scopes", 3 | "version": "0.0.2", 4 | "description": "Mark scopes for deopt which contain a direct eval call", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-helper-mark-eval-scopes", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "boopathi", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin", 13 | "babili" 14 | ], 15 | "dependencies": {}, 16 | "devDependencies": {} 17 | } 18 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-flip-comparisons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-flip-comparisons", 3 | "version": "0.0.2", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-flip-comparisons", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-is-void-0": "^0.0.1" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-type-constructors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-type-constructors", 3 | "version": "0.0.3", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-type-constructors", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-is-void-0": "^0.0.1" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-undefined-to-void/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-undefined-to-void", 3 | "version": "6.8.0", 4 | "description": "Replace references to `undefined` with `void 0`", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-undefined-to-void", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babili/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babili", 3 | "version": "0.0.11", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babili", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "bin": { 12 | "babili": "./bin/babili.js" 13 | }, 14 | "keywords": [ 15 | "babel-preset" 16 | ], 17 | "dependencies": { 18 | "babel-preset-babili": "^0.0.11", 19 | "babel-cli": "^6.10.1" 20 | }, 21 | "devDependencies": {} 22 | } 23 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-merge-sibling-variables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-merge-sibling-variables", 3 | "version": "6.8.2", 4 | "description": "Merge sibling variables into one.", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-merge-sibling-variables", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-minify-booleans/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-minify-booleans", 3 | "version": "6.8.0", 4 | "description": "Turn boolean literals into !0 for true and !1 for false.", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-minify-booleans", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-property-literals/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-property-literals", 3 | "version": "6.8.1", 4 | "description": "Turn valid property key literals to plain identifiers", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-property-literals", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-guarded-expressions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-guarded-expressions", 3 | "version": "0.0.4", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-guarded-expressions", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-flip-expressions": "^0.0.2" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-numeric-literals/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-numeric-literals", 3 | "version": "0.0.1", 4 | "description": "Shortens numeric literals using scientific notation", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-numeric-literals", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "kangax", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin", 13 | "babili" 14 | ], 15 | "dependencies": {}, 16 | "devDependencies": {} 17 | } 18 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-environment-variables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-inline-environment-variables", 3 | "version": "0.0.2", 4 | "description": "Inline environment variables.", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-inline-environment-variables", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-node-env-inline/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-node-env-inline", 3 | "version": "0.0.2", 4 | "description": "Inline the `NODE_ENV` environment variable and evaluate it if possible", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-node-env-inline", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-undefined/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-remove-undefined", 3 | "version": "0.0.5", 4 | "description": "This removes rvals that are equivalent to undefined wherever possible", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-remove-undefined", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "shinew", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-constant-folding/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-constant-folding", 3 | "version": "0.0.4", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-constant-folding", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-evaluate-path": "^0.0.3", 16 | "jsesc": "^2.4.0" 17 | }, 18 | "devDependencies": {} 19 | } 20 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/src/collapser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const NotImplementedError = Error("NotImplementedError"); 4 | 5 | class Collapser { 6 | isInitTypeValid() { 7 | throw NotImplementedError; 8 | } 9 | 10 | isExpressionTypeValid() { 11 | throw NotImplementedError; 12 | } 13 | 14 | getExpressionChecker() { 15 | throw NotImplementedError; 16 | } 17 | 18 | extractAssignment() { 19 | throw NotImplementedError; 20 | } 21 | 22 | addSuccessfully() { 23 | throw NotImplementedError; 24 | } 25 | 26 | isSizeSmaller() { 27 | return true; 28 | } 29 | } 30 | 31 | module.exports = Collapser; 32 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-regexp-constructors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-regexp-constructors", 3 | "version": "0.0.5", 4 | "description": "This changes RegExp constructors into literals if the RegExp arguments are strings.", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-regexp-constructors", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "shinew", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-inline-consecutive-adds", 3 | "version": "0.0.2", 4 | "description": "This plugin inlines consecutive property assignments, array pushes, etc.", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-inline-consecutive-adds", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "shinew", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-member-expression-literals/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-member-expression-literals", 3 | "version": "6.8.1", 4 | "description": "Turn valid member expression property literals into plain identifiers", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-member-expression-literals", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-node-env-inline/__tests__/node-env-inline-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [plugin], 9 | }).code; 10 | } 11 | 12 | describe("node-env-inline-plugin", () => { 13 | it("should inline", () => { 14 | const prev = process.env.NODE_ENV; 15 | process.env.NODE_ENV = "development"; 16 | 17 | const source = "process.env.NODE_ENV === \"development\";"; 18 | const expected = "true;"; 19 | expect(transform(source)).toBe(expected); 20 | 21 | process.env.NODE_ENV = prev; 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-node-env-inline/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | return { 5 | name: "transform-node-env-inline", 6 | visitor: { 7 | MemberExpression(path) { 8 | if (path.matchesPattern("process.env.NODE_ENV")) { 9 | path.replaceWith(t.valueToNode(process.env.NODE_ENV)); 10 | 11 | if (path.parentPath.isBinaryExpression()) { 12 | const evaluated = path.parentPath.evaluate(); 13 | if (evaluated.confident) { 14 | path.parentPath.replaceWith(t.valueToNode(evaluated.value)); 15 | } 16 | } 17 | } 18 | }, 19 | }, 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-simplify-comparison-operators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-simplify-comparison-operators", 3 | "version": "6.8.1", 4 | "description": "Convert === and !== to == and != if their types are inferred to be the same.", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-simplify-comparison-operators", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": {}, 15 | "devDependencies": {} 16 | } 17 | -------------------------------------------------------------------------------- /scripts/benchmark_assets/LICENSE-examples: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-present, Facebook, Inc. All rights reserved. 2 | 3 | The examples provided by Facebook are for non-commercial testing and evaluation 4 | purposes only. Facebook reserves all rights not expressly granted. 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 7 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 8 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 9 | FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 10 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 11 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-environment-variables/__tests__/inline-env-var-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [plugin], 9 | }).code; 10 | } 11 | 12 | describe("inline-env-plugin", () => { 13 | it("should inline environment variables", () => { 14 | const prev = process.env.NODE_ENV; 15 | process.env.NODE_ENV = "development"; 16 | 17 | const source = "process.env.NODE_ENV"; 18 | const expected = "\"development\";"; 19 | expect(transform(source)).toBe(expected); 20 | 21 | process.env.NODE_ENV = prev; 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.0.0-beta.37", 3 | "version": "independent", 4 | "publishConfig": { 5 | "ignore": [ 6 | "*.md", 7 | "__tests__" 8 | ] 9 | }, 10 | "changelog": { 11 | "repo": "babel/babili", 12 | "labels": { 13 | "Tag: Spec Compliancy": ":eyeglasses: Spec Compliancy", 14 | "Tag: Breaking Change": ":boom: Breaking Change", 15 | "Tag: New Feature": ":rocket: New Feature", 16 | "Tag: Bug Fix": ":bug: Bug Fix", 17 | "Tag: Polish": ":nail_care: Polish", 18 | "Tag: Docs": ":memo: Documentation", 19 | "Tag: Internal": ":house: Internal", 20 | "Tag: Chore": "Chore" 21 | } 22 | }, 23 | "packages": [ 24 | "packages/*" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-infinity/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-infinity 2 | 3 | ## Example 4 | 5 | **In** 6 | 7 | ```javascript 8 | Infinity; 9 | ``` 10 | 11 | **Out** 12 | 13 | ```javascript 14 | 1 / 0; 15 | ``` 16 | 17 | ## Installation 18 | 19 | ```sh 20 | npm install babel-plugin-minify-infinity 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### Via `.babelrc` (Recommended) 26 | 27 | **.babelrc** 28 | 29 | ```json 30 | { 31 | "plugins": ["minify-infinity"] 32 | } 33 | ``` 34 | 35 | ### Via CLI 36 | 37 | ```sh 38 | babel --plugins minify-infinity script.js 39 | ``` 40 | 41 | ### Via Node API 42 | 43 | ```javascript 44 | require("babel-core").transform("code", { 45 | plugins: ["minify-infinity"] 46 | }); 47 | ``` 48 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-simplify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-simplify", 3 | "version": "0.0.7", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-simplify", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-flip-expressions": "^0.0.2", 16 | "babel-helper-is-nodes-equiv": "^0.0.1", 17 | "babel-helper-to-multiple-sequence-expressions": "^0.0.3" 18 | }, 19 | "devDependencies": {} 20 | } 21 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-builtins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-builtins", 3 | "version": "0.0.1", 4 | "description": "Minify Standard built-in Objects", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-builtins", 7 | "main": "lib/index.js", 8 | "bugs": "https://github.com/babel/babili/issues", 9 | "keywords": [ 10 | "babel-plugin", 11 | "transform-built-ins" 12 | ], 13 | "author": "Vignesh Shanmugam (https://vigneshh.in)", 14 | "license": "MIT", 15 | "dependencies": { 16 | "babel-helper-evaluate-path": "^0.0.3" 17 | }, 18 | "devDependencies": {} 19 | } 20 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-dead-code-elimination/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-minify-dead-code-elimination", 3 | "version": "0.1.3", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-plugin-minify-dead-code-elimination", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-plugin" 13 | ], 14 | "dependencies": { 15 | "babel-helper-mark-eval-scopes": "^0.0.2", 16 | "babel-helper-remove-or-void": "^0.0.1", 17 | "lodash.some": "^4.6.0" 18 | }, 19 | "devDependencies": {} 20 | } 21 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-numeric-literals/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | return { 5 | name: "minify-numeric-literals", 6 | visitor: { 7 | NumericLiteral(path) { 8 | if (!path.node.extra) return; 9 | 10 | const exponential = path.node.value.toExponential() 11 | .replace(/\+/g, "") 12 | .replace(/e0/, ""); 13 | 14 | if (path.node.extra.raw.length > exponential.length) { 15 | const literal = t.numericLiteral(path.node.value); 16 | literal.extra = { 17 | raw: exponential, 18 | rawValue: path.node.value 19 | }; 20 | path.replaceWith(literal); 21 | } 22 | } 23 | }, 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-property-literals/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | return { 5 | name: "transform-property-literals", 6 | visitor: { 7 | // { 'foo': 'bar' } -> { foo: 'bar' } 8 | ObjectProperty: { 9 | exit({ node }) { 10 | const key = node.key; 11 | if (!t.isStringLiteral(key)) { 12 | return; 13 | } 14 | 15 | if (key.value.match(/^\d+$/)) { 16 | node.key = t.numericLiteral(parseInt(node.key.value, 10)); 17 | node.computed = false; 18 | } else if (t.isValidIdentifier(key.value)) { 19 | node.key = t.identifier(key.value); 20 | node.computed = false; 21 | } 22 | }, 23 | }, 24 | }, 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-debugger/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-remove-debugger 2 | 3 | This plugin removes all `debugger;` statements. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | debugger; 11 | ``` 12 | 13 | **Out** 14 | 15 | ```javascript 16 | ``` 17 | 18 | ## Installation 19 | 20 | ```sh 21 | npm install babel-plugin-transform-remove-debugger 22 | ``` 23 | 24 | ## Usage 25 | 26 | ### Via `.babelrc` (Recommended) 27 | 28 | **.babelrc** 29 | 30 | ```json 31 | { 32 | "plugins": ["transform-remove-debugger"] 33 | } 34 | ``` 35 | 36 | ### Via CLI 37 | 38 | ```sh 39 | babel --plugins transform-remove-debugger script.js 40 | ``` 41 | 42 | ### Via Node API 43 | 44 | ```javascript 45 | require("babel-core").transform("code", { 46 | plugins: ["transform-remove-debugger"] 47 | }); 48 | ``` 49 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-undefined-to-void/__tests__/undefined-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [plugin], 9 | }).code; 10 | } 11 | 12 | describe("undefined-plugin", () => { 13 | it("should turn undefined into void 0", () => { 14 | const source = "var foo;foo === undefined;"; 15 | const expected = "var foo;foo === void 0;"; 16 | expect(transform(source)).toBe(expected); 17 | }); 18 | 19 | it("should turn undefined into void 0 in a MemberExpression", () => { 20 | const source = "var foo;foo === undefined.foo;"; 21 | const expected = "var foo;foo === (void 0).foo;"; 22 | expect(transform(source)).toBe(expected); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-guarded-expressions/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-guarded-expressions 2 | 3 | ## Example 4 | 5 | **In** 6 | 7 | ```javascript 8 | !x && foo(); 9 | alert(0 && new Foo()); 10 | ``` 11 | 12 | **Out** 13 | 14 | ```javascript 15 | x || foo(); 16 | alert(0); 17 | ``` 18 | 19 | ## Installation 20 | 21 | ```sh 22 | npm install babel-plugin-minify-guarded-expressions 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Via `.babelrc` (Recommended) 28 | 29 | **.babelrc** 30 | 31 | ```json 32 | { 33 | "plugins": ["minify-guarded-expressions"] 34 | } 35 | ``` 36 | 37 | ### Via CLI 38 | 39 | ```sh 40 | babel --plugins minify-guarded-expressions script.js 41 | ``` 42 | 43 | ### Via Node API 44 | 45 | ```javascript 46 | require("babel-core").transform("code", { 47 | plugins: ["minify-guarded-expressions"] 48 | }); 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-simplify-comparison-operators/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function() { 4 | return { 5 | name: "transform-simplify-comparison-operators", 6 | visitor: { 7 | // simplify comparison operations if we're 100% certain 8 | // that each value will always be of the same type 9 | BinaryExpression(path) { 10 | const { node } = path; 11 | const op = node.operator; 12 | if (op !== "===" && op !== "!==") { 13 | return; 14 | } 15 | 16 | const left = path.get("left"); 17 | const right = path.get("right"); 18 | const strictMatch = left.baseTypeStrictlyMatches(right); 19 | if (strictMatch) { 20 | node.operator = node.operator.slice(0, -1); 21 | } 22 | }, 23 | }, 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-numeric-literals/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-mangle-names 2 | 3 | Shortening of numeric literals via scientific notation 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | [1000, -20000] 11 | ``` 12 | 13 | **Out** 14 | 15 | ```javascript 16 | [1e3, -2e4] 17 | ``` 18 | 19 | ## Installation 20 | 21 | ```sh 22 | npm install babel-plugin-minify-numeric-literals 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Via `.babelrc` (Recommended) 28 | 29 | **.babelrc** 30 | 31 | ```json 32 | { 33 | "plugins": ["minify-numeric-literals"] 34 | } 35 | ``` 36 | 37 | ### Via CLI 38 | 39 | ```sh 40 | babel --plugins minify-numeric-literals script.js 41 | ``` 42 | 43 | ### Via Node API 44 | 45 | ```javascript 46 | require("babel-core").transform("code", { 47 | plugins: ["minify-numeric-literals"] 48 | }); 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-builtins/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-builtins 2 | 3 | Minify Standard built-in Objects 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | Math.floor(a) + Math.floor(b) 11 | ``` 12 | 13 | **Out** 14 | 15 | ```javascript 16 | var _Mathfloor = Math.floor; 17 | 18 | _Mathfloor(a) + _Mathfloor(b); 19 | ``` 20 | 21 | ## Installation 22 | 23 | ```sh 24 | npm install babel-plugin-minify-builtins 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### Via `.babelrc` (Recommended) 30 | 31 | **.babelrc** 32 | 33 | ```json 34 | { 35 | "plugins": ["minify-builtins"] 36 | } 37 | ``` 38 | 39 | ### Via CLI 40 | 41 | ```sh 42 | babel --plugins minify-builtins script.js 43 | ``` 44 | 45 | ### Via Node API 46 | 47 | ```javascript 48 | require("babel-core").transform("code", { 49 | plugins: ["minify-builtins"] 50 | }); 51 | ``` 52 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-console/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-remove-console 2 | 3 | This plugin removes all `console.*` calls. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | console.log("foo"); 11 | console.error("bar"); 12 | ``` 13 | 14 | **Out** 15 | 16 | ```javascript 17 | ``` 18 | 19 | ## Installation 20 | 21 | ```sh 22 | npm install babel-plugin-transform-remove-console 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Via `.babelrc` (Recommended) 28 | 29 | **.babelrc** 30 | 31 | ```json 32 | { 33 | "plugins": ["transform-remove-console"] 34 | } 35 | ``` 36 | 37 | ### Via CLI 38 | 39 | ```sh 40 | babel --plugins transform-remove-console script.js 41 | ``` 42 | 43 | ### Via Node API 44 | 45 | ```javascript 46 | require("babel-core").transform("code", { 47 | plugins: ["transform-remove-console"] 48 | }); 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-member-expression-literals/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | return { 5 | name: "transform-member-expression-literals", 6 | visitor: { 7 | // foo['bar'] -> foo.bar 8 | MemberExpression: { 9 | exit({ node }) { 10 | const prop = node.property; 11 | if (!node.computed || !t.isStringLiteral(prop)) { 12 | return; 13 | } 14 | 15 | if (prop.value.match(/^\d+$/)) { 16 | node.property = t.numericLiteral(parseInt(prop.value, 10)); 17 | node.computed = false; 18 | } else if (t.isValidIdentifier(prop.value)) { 19 | node.property = t.identifier(prop.value); 20 | node.computed = false; 21 | } 22 | }, 23 | }, 24 | }, 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-minify-booleans/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-minify-booleans 2 | 3 | This plugin allows Babel to transform boolean literals into `!0` for `true` and `!1` for `false`. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | true; 11 | false; 12 | ``` 13 | 14 | **Out** 15 | 16 | ```javascript 17 | !0; 18 | !1; 19 | ``` 20 | 21 | ## Installation 22 | 23 | ```sh 24 | npm install babel-plugin-transform-minify-booleans 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### Via `.babelrc` (Recommended) 30 | 31 | **.babelrc** 32 | 33 | ```json 34 | { 35 | "plugins": ["transform-minify-booleans"] 36 | } 37 | ``` 38 | 39 | ### Via CLI 40 | 41 | ```sh 42 | babel --plugins transform-minify-booleans script.js 43 | ``` 44 | 45 | ### Via Node API 46 | 47 | ```javascript 48 | require("babel-core").transform("code", { 49 | plugins: ["transform-minify-booleans"] 50 | }); 51 | ``` 52 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-environment-variables/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-inline-environment-variables 2 | 3 | Inline environment variables 4 | 5 | ## Example 6 | 7 | ### In 8 | 9 | ```js 10 | // assuming process.env.NODE_ENV is actually "development" 11 | process.env.NODE_ENV; 12 | ``` 13 | 14 | ### Out 15 | 16 | ```js 17 | "development"; 18 | ``` 19 | 20 | ## Installation 21 | 22 | ```sh 23 | npm install babel-plugin-transform-inline-environment-variables 24 | ``` 25 | 26 | ## Usage 27 | 28 | ### Via `.babelrc` (Recommended) 29 | 30 | **.babelrc** 31 | 32 | ```json 33 | { 34 | "plugins": ["transform-inline-environment-variables"] 35 | } 36 | ``` 37 | 38 | ### Via CLI 39 | 40 | ```sh 41 | babel --plugins transform-inline-environment-variables script.js 42 | ``` 43 | 44 | ### Via Node API 45 | 46 | ```javascript 47 | require("babel-core").transform("code", { 48 | plugins: ["transform-inline-environment-variables"] 49 | }); 50 | ``` 51 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-infinity/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | const INFINITY = t.binaryExpression("/", t.numericLiteral(1), t.numericLiteral(0)); 5 | return { 6 | name: "minify-infinity", 7 | visitor: { 8 | // Infinity -> 1 / 0 9 | Identifier(path) { 10 | if (path.node.name !== "Infinity") { 11 | return; 12 | } 13 | 14 | // It's a referenced identifier 15 | if (path.scope.getBinding("Infinity")) { 16 | return; 17 | } 18 | 19 | if (path.parentPath.isObjectProperty({ key: path.node })) { 20 | return; 21 | } 22 | 23 | if (path.parentPath.isMemberExpression()) { 24 | return; 25 | } 26 | 27 | if (path.isLVal() && !path.parentPath.isExpressionStatement()) { 28 | return; 29 | } 30 | 31 | path.replaceWith(INFINITY); 32 | }, 33 | }, 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-regexp-constructors/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-regexp-constructors 2 | 3 | This changes RegExp constructors into literals if the RegExp arguments are strings. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | const foo = 'ab+'; 11 | var a = new RegExp(foo+'c', 'i'); 12 | ``` 13 | 14 | **Out** 15 | 16 | ```javascript 17 | const foo = 'ab+'; 18 | var a = /ab+c/i; 19 | ``` 20 | 21 | ## Installation 22 | 23 | ```sh 24 | npm install babel-plugin-transform-regexp-constructors 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### Via `.babelrc` (Recommended) 30 | 31 | **.babelrc** 32 | 33 | ```json 34 | { 35 | "plugins": ["transform-regexp-constructors"] 36 | } 37 | ``` 38 | 39 | ### Via CLI 40 | 41 | ```sh 42 | babel --plugins transform-regexp-constructors script.js 43 | ``` 44 | 45 | ### Via Node API 46 | 47 | ```javascript 48 | require("babel-core").transform("code", { 49 | plugins: ["transform-regexp-constructors"] 50 | }); 51 | ``` 52 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-simplify-comparison-operators/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-simplify-comparison-operators 2 | 3 | Convert `===` and `!==` to `==` and `!=` if their types are inferred to be the same. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | typeof foo === "object"; 11 | ``` 12 | 13 | **Out** 14 | 15 | ```javascript 16 | typeof foo == "object"; 17 | ``` 18 | 19 | ## Installation 20 | 21 | ```sh 22 | npm install babel-plugin-transform-simplify-comparison-operators 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Via `.babelrc` (Recommended) 28 | 29 | **.babelrc** 30 | 31 | ```json 32 | { 33 | "plugins": ["transform-simplify-comparison-operators"] 34 | } 35 | ``` 36 | 37 | ### Via CLI 38 | 39 | ```sh 40 | babel --plugins transform-simplify-comparison-operators script.js 41 | ``` 42 | 43 | ### Via Node API 44 | 45 | ```javascript 46 | require("babel-core").transform("code", { 47 | plugins: ["transform-simplify-comparison-operators"] 48 | }); 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-constant-folding/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-constant-folding 2 | 3 | Tries to evaluate expressions and inline the result. For now only deals with numbers and strings. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | "a" + "b" 11 | 2 * 3; 12 | 4 | 3; 13 | "b" + a + "c" + "d" + g + z + "f" + "h" + "z" 14 | ``` 15 | 16 | **Out** 17 | 18 | ```javascript 19 | "ab"; 20 | 6; 21 | 7; 22 | "b" + a + "cd" + g + z + "fhz"; 23 | ``` 24 | 25 | ## Installation 26 | 27 | ```sh 28 | npm install babel-plugin-minify-constant-folding 29 | ``` 30 | 31 | ## Usage 32 | 33 | ### Via `.babelrc` (Recommended) 34 | 35 | **.babelrc** 36 | 37 | ```json 38 | { 39 | "plugins": ["minify-constant-folding"] 40 | } 41 | ``` 42 | 43 | ### Via CLI 44 | 45 | ```sh 46 | babel --plugins minify-constant-folding script.js 47 | ``` 48 | 49 | ### Via Node API 50 | 51 | ```javascript 52 | require("babel-core").transform("code", { 53 | plugins: ["minify-constant-folding"] 54 | }); 55 | ``` 56 | -------------------------------------------------------------------------------- /packages/babel-helper-remove-or-void/src/index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function(t) { 3 | // If we can't remove the expression we'll just replace it with an empty statement. 4 | function removeOrVoid(path) { 5 | // If we are working with the expression of an expression statement we want to deal 6 | // with the expression statement instead. 7 | if (path.parentPath.isExpressionStatement({ expression: path.node })) { 8 | path = path.parentPath; 9 | } 10 | 11 | // If we are working with a variable declarator and there is only one then 12 | // we need to look at the parent. 13 | if (path.isVariableDeclarator() && path.parent.declarations[0] === path.node && 14 | path.parent.declarations.length === 1 15 | ) { 16 | path = path.parentPath; 17 | } 18 | 19 | if (!path.inList && path.scope.path.type !== "ForStatement") { 20 | path.replaceWith(t.emptyStatement()); 21 | } else { 22 | path.remove(); 23 | } 24 | } 25 | 26 | return removeOrVoid; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-empty-function/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-empty-function 2 | 3 | This is mostly a Facebook-specific transform that removes noop function calls. However, can be generalized to detect and remove noops. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | function emptyFunction(){} 11 | emptyFunction('how long','?'); 12 | foo(emptyFunction('how long', '?')); 13 | ``` 14 | 15 | **Out** 16 | 17 | ```javascript 18 | function emptyFunction(){} 19 | foo(false); 20 | ``` 21 | 22 | ## Installation 23 | 24 | ```sh 25 | npm install babel-plugin-minify-empty-function 26 | ``` 27 | 28 | ## Usage 29 | 30 | ### Via `.babelrc` (Recommended) 31 | 32 | **.babelrc** 33 | 34 | ```json 35 | { 36 | "plugins": ["minify-empty-function"] 37 | } 38 | ``` 39 | 40 | ### Via CLI 41 | 42 | ```sh 43 | babel --plugins minify-empty-function script.js 44 | ``` 45 | 46 | ### Via Node API 47 | 48 | ```javascript 49 | require("babel-core").transform("code", { 50 | plugins: ["minify-empty-function"] 51 | }); 52 | ``` 53 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-flip-comparisons/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-flip-comparisons 2 | 3 | **Note:** while this plugin doesn’t shorten the output in any way, it does optimize it for repetition-based compression algorithms such as gzip. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | const foo = a === 1; 11 | if (bar !== null) { 12 | var baz = 0; 13 | } 14 | ``` 15 | 16 | **Out** 17 | 18 | ```javascript 19 | const foo = 1 === a; 20 | if (null !== bar) { 21 | var baz = 0; 22 | } 23 | ``` 24 | 25 | ## Installation 26 | 27 | ```sh 28 | npm install babel-plugin-minify-flip-comparisons 29 | ``` 30 | 31 | ## Usage 32 | 33 | ### Via `.babelrc` (Recommended) 34 | 35 | **.babelrc** 36 | 37 | ```json 38 | { 39 | "plugins": ["minify-flip-comparisons"] 40 | } 41 | ``` 42 | 43 | ### Via CLI 44 | 45 | ```sh 46 | babel --plugins minify-flip-comparisons script.js 47 | ``` 48 | 49 | ### Via Node API 50 | 51 | ```javascript 52 | require("babel-core").transform("code", { 53 | plugins: ["minify-flip-comparisons"] 54 | }); 55 | ``` 56 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-undefined-to-void/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-undefined-to-void 2 | 3 | Some JavaScript implementations allow undefined to be overwritten, this may lead to peculiar bugs that are extremely hard to track down. 4 | 5 | This plugin transforms `undefined` into `void 0` which returns undefined regardless of if it's been reassigned. 6 | 7 | ## Example 8 | 9 | **In** 10 | 11 | ```javascript 12 | foo === undefined; 13 | ``` 14 | 15 | **Out** 16 | 17 | ```javascript 18 | foo === void 0; 19 | ``` 20 | 21 | ## Installation 22 | 23 | ```sh 24 | npm install babel-plugin-transform-undefined-to-void 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### Via `.babelrc` (Recommended) 30 | 31 | **.babelrc** 32 | 33 | ```json 34 | { 35 | "plugins": ["transform-undefined-to-void"] 36 | } 37 | ``` 38 | 39 | ### Via CLI 40 | 41 | ```sh 42 | babel --plugins transform-undefined-to-void script.js 43 | ``` 44 | 45 | ### Via Node API 46 | 47 | ```javascript 48 | require("babel-core").transform("code", { 49 | plugins: ["transform-undefined-to-void"] 50 | }); 51 | ``` 52 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-member-expression-literals/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-member-expression-literals 2 | 3 | Turn valid member expression property literals into plain identifiers 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | obj["foo"] = "isValid"; 11 | 12 | obj.const = "isKeyword"; 13 | obj["var"] = "isKeyword"; 14 | ``` 15 | 16 | **Out** 17 | 18 | ```javascript 19 | obj.foo = "isValid"; 20 | 21 | obj["const"] = "isKeyword"; 22 | obj["var"] = "isKeyword"; 23 | ``` 24 | 25 | ## Installation 26 | 27 | ```sh 28 | npm install babel-plugin-transform-member-expression-literals 29 | ``` 30 | 31 | ## Usage 32 | 33 | ### Via `.babelrc` (Recommended) 34 | 35 | **.babelrc** 36 | 37 | ```json 38 | { 39 | "plugins": ["transform-member-expression-literals"] 40 | } 41 | ``` 42 | 43 | ### Via CLI 44 | 45 | ```sh 46 | babel --plugins transform-member-expression-literals script.js 47 | ``` 48 | 49 | ### Via Node API 50 | 51 | ```javascript 52 | require("babel-core").transform("code", { 53 | plugins: ["transform-member-expression-literals"] 54 | }); 55 | ``` 56 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-merge-sibling-variables/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-merge-sibling-variables 2 | 3 | Merge sibling variables into one. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | // merge into a single VariableDeclaration 11 | var foo = "bar"; 12 | var bar = "foo"; 13 | foobar(); 14 | 15 | // merge into the next for loop 16 | var i = 0; 17 | for (var x = 0; x < 10; x++) {} 18 | ``` 19 | 20 | **Out** 21 | 22 | ```javascript 23 | var foo = "bar", 24 | bar = "foo"; 25 | foobar(); 26 | 27 | for (var i = 0, x = 0; x < 10; x++) {} 28 | ``` 29 | 30 | ## Installation 31 | 32 | ```sh 33 | npm install babel-plugin-transform-merge-sibling-variables 34 | ``` 35 | 36 | ## Usage 37 | 38 | ### Via `.babelrc` (Recommended) 39 | 40 | **.babelrc** 41 | 42 | ```json 43 | { 44 | "plugins": ["transform-merge-sibling-variables"] 45 | } 46 | ``` 47 | 48 | ### Via CLI 49 | 50 | ```sh 51 | babel --plugins transform-merge-sibling-variables script.js 52 | ``` 53 | 54 | ### Via Node API 55 | 56 | ```javascript 57 | require("babel-core").transform("code", { 58 | plugins: ["transform-merge-sibling-variables"] 59 | }); 60 | ``` 61 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-node-env-inline/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-node-env-inline 2 | 3 | Inline the `NODE_ENV` environment variable and if it's a part of a binary expression 4 | (eg. `process.env.NODE_ENV === "development"`) then statically evaluate and replace it. 5 | 6 | ## Example 7 | 8 | **In** 9 | 10 | ```javascript 11 | process.env.NODE_ENV === "development"; 12 | process.env.NODE_ENV === "production"; 13 | ``` 14 | 15 | **Out** 16 | 17 | ```sh 18 | NODE_ENV=development babel in.js --plugins transform-node-env-inline 19 | ``` 20 | 21 | ```javascript 22 | true; 23 | false; 24 | ``` 25 | 26 | ## Installation 27 | 28 | ```sh 29 | npm install babel-plugin-transform-node-env-inline 30 | ``` 31 | 32 | ## Usage 33 | 34 | ### Via `.babelrc` (Recommended) 35 | 36 | **.babelrc** 37 | 38 | ```json 39 | { 40 | "plugins": ["transform-node-env-inline"] 41 | } 42 | ``` 43 | 44 | ### Via CLI 45 | 46 | ```sh 47 | babel --plugins transform-node-env-inline script.js 48 | ``` 49 | 50 | ### Via Node API 51 | 52 | ```javascript 53 | require("babel-core").transform("code", { 54 | plugins: ["transform-node-env-inline"] 55 | }); 56 | ``` 57 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-undefined/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-remove-undefined 2 | 3 | For variable assignments, this removes rvals that evaluate to `undefined` 4 | (`var`s in functions only). 5 | For functions, this removes return arguments that evaluate to `undefined`. 6 | 7 | ## Example 8 | 9 | **In** 10 | 11 | ```javascript 12 | let a = void 0; 13 | function foo() { 14 | var b = undefined; 15 | return undefined; 16 | } 17 | ``` 18 | 19 | **Out** 20 | 21 | ```javascript 22 | let a; 23 | function foo() { 24 | var b; 25 | return; 26 | } 27 | ``` 28 | 29 | ## Installation 30 | 31 | ```sh 32 | npm install babel-plugin-transform-remove-undefined 33 | ``` 34 | 35 | ## Usage 36 | 37 | ### Via `.babelrc` (Recommended) 38 | 39 | **.babelrc** 40 | 41 | ```json 42 | { 43 | "plugins": ["babel-plugin-transform-remove-undefined"] 44 | } 45 | ``` 46 | 47 | ### Via CLI 48 | 49 | ```sh 50 | babel --plugins babel-plugin-transform-remove-undefined script.js 51 | ``` 52 | 53 | ### Via Node API 54 | 55 | ```javascript 56 | require("babel-core").transform("code", { 57 | plugins: ["babel-plugin-transform-remove-undefined"] 58 | }); 59 | ``` 60 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-empty-function/__tests__/empty-function-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const unpad = require("../../../utils/unpad"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [require("../src/index")], 9 | }).code; 10 | } 11 | 12 | describe("constant-folding-plugin", () => { 13 | it("should remove call expressions", () => { 14 | const source = unpad(` 15 | emptyFunction('how long', '?'); 16 | `); 17 | 18 | const expected = ""; 19 | expect(transform(source)).toBe(expected); 20 | }); 21 | 22 | it("should replace with emptyStatement", () => { 23 | const source = unpad(` 24 | if (1) emptyFunction('how long', '?'); 25 | `); 26 | 27 | const expected = "if (1) ;"; 28 | expect(transform(source)).toBe(expected); 29 | }); 30 | 31 | it("should convert to expressions to false", () => { 32 | const source = unpad(` 33 | foo(emptyFunction('how long', '?')); 34 | `); 35 | 36 | const expected = unpad(` 37 | foo(false); 38 | `); 39 | expect(transform(source)).toBe(expected); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Amjad Masad 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-inline-consecutive-adds 2 | 3 | This plugin inlines consecutive property assignments, array pushes, etc. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | const foo = {}; 11 | foo.a = 42; 12 | foo.b = ["hi"]; 13 | foo.c = bar(); 14 | foo.d = "str"; 15 | 16 | ... 17 | const bar = []; 18 | bar.push(1); 19 | bar.push(2); 20 | ``` 21 | 22 | **Out** 23 | 24 | ```javascript 25 | const foo = { 26 | a: 42, 27 | b: ["hi"], 28 | c: bar(), 29 | d: "str" 30 | }; 31 | 32 | ... 33 | const bar = [1, 2]; 34 | ``` 35 | 36 | ## Installation 37 | 38 | ```sh 39 | npm install babel-plugin-transform-inline-consecutive-adds 40 | ``` 41 | 42 | ## Usage 43 | 44 | ### Via `.babelrc` (Recommended) 45 | 46 | **.babelrc** 47 | 48 | ```json 49 | { 50 | "plugins": ["transform-inline-consecutive-adds"] 51 | } 52 | ``` 53 | 54 | ### Via CLI 55 | 56 | ```sh 57 | babel --plugins transform-inline-consecutive-adds script.js 58 | ``` 59 | 60 | ### Via Node API 61 | 62 | ```javascript 63 | require("babel-core").transform("code", { 64 | plugins: ["transform-inline-consecutive-adds"] 65 | }); 66 | ``` 67 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-property-literals/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-transform-property-literals 2 | 3 | This plugin allows Babel to transform valid identifier property key literals into identifiers. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | var foo = { 11 | // changed 12 | "bar": function () {}, 13 | "1": function () {}, 14 | 15 | // not changed 16 | "default": 1, 17 | [a]: 2, 18 | foo: 1 19 | }; 20 | ``` 21 | 22 | **Out** 23 | 24 | ```javascript 25 | var foo = { 26 | bar: function () {}, 27 | 1: function () {}, 28 | 29 | "default": 1, 30 | [a]: 2, 31 | foo: 1 32 | }; 33 | ``` 34 | 35 | ## Installation 36 | 37 | ```sh 38 | npm install babel-plugin-transform-property-literals 39 | ``` 40 | 41 | ## Usage 42 | 43 | ### Via `.babelrc` (Recommended) 44 | 45 | **.babelrc** 46 | 47 | ```json 48 | { 49 | "plugins": ["transform-property-literals"] 50 | } 51 | ``` 52 | 53 | ### Via CLI 54 | 55 | ```sh 56 | babel --plugins transform-property-literals script.js 57 | ``` 58 | 59 | ### Via Node API 60 | 61 | ```javascript 62 | require("babel-core").transform("code", { 63 | plugins: ["transform-property-literals"] 64 | }); 65 | ``` 66 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-numeric-literals/__tests__/numeric-literals-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [plugin], 9 | }).code; 10 | } 11 | 12 | describe("numeric-literals", () => { 13 | it("should shorten properly", () => { 14 | 15 | let source = "[10, 100, 1000, 10000, -2, -30000];"; 16 | let expected = "[10, 100, 1e3, 1e4, -2, -3e4];"; 17 | 18 | expect(transform(source)).toBe(expected); 19 | 20 | source = "[1e3, -1e4, 1e-5, 1.5e12, 1.23456, .1];"; 21 | expected = "[1e3, -1e4, 1e-5, 1.5e12, 1.23456, .1];"; 22 | 23 | expect(transform(source)).toBe(expected); 24 | 25 | source = "[0x000001, 0o23420, 0b10011100010000];"; 26 | expected = "[1, 1e4, 1e4];"; 27 | 28 | expect(transform(source)).toBe(expected); 29 | 30 | source = "[+0.000000000001, -0.00000000001];"; 31 | // TODO: this seems to be specific to how Babel outputs number 32 | // for some reason it adds + in the beginning 33 | expected = "[+1e-12, -1e-11];"; 34 | 35 | expect(transform(source)).toBe(expected); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-empty-function/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = ({ types: t }) => { 4 | const removeOrVoid = require("babel-helper-remove-or-void")(t); 5 | 6 | const visitor = { 7 | // Remove the call if it stands on it's own. 8 | ExpressionStatement(path) { 9 | const { node } = path; 10 | if (isEmptyFunction(node.expression)) { 11 | removeOrVoid(path); 12 | } 13 | }, 14 | 15 | // If we're not in an expression statement we can't remove 16 | // the call. 17 | CallExpression(path) { 18 | const { node } = path; 19 | if (isEmptyFunction(node)) { 20 | path.replaceWith(t.booleanLiteral(false)); 21 | } 22 | }, 23 | }; 24 | 25 | return { 26 | name: "minify-empty-function", 27 | visitor: { 28 | // Unfortunately we have to do it in a seperate pass to ensure that 29 | // the expression statements are removed otherwise the calls may 30 | // end in conditionals or sequence expressions. 31 | Program(path) { 32 | path.traverse(visitor, {}); 33 | }, 34 | }, 35 | }; 36 | 37 | function isEmptyFunction(node) { 38 | return t.isCallExpression(node) && 39 | t.isIdentifier(node.callee, { name: "emptyFunction" }); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-simplify/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-simplify 2 | 3 | > Simplifies code for minification by reducing statements into expressions and making expressions uniform where possible. 4 | 5 | ## Example 6 | 7 | ### Reduce statement into expression 8 | 9 | **In** 10 | 11 | ```js 12 | function foo() { 13 | if (x) a(); 14 | } 15 | function foo2() { 16 | if (x) a(); 17 | else b(); 18 | } 19 | ``` 20 | 21 | **Out** 22 | 23 | ```js 24 | function foo() { 25 | x && a(); 26 | } 27 | function foo2() { 28 | x ? a() : b(); 29 | } 30 | ``` 31 | 32 | ### Make expression as uniform as possible for better compressibility 33 | 34 | **In** 35 | 36 | ```js 37 | undefined 38 | foo['bar'] 39 | Number(foo) 40 | ``` 41 | 42 | **Out** 43 | 44 | ```js 45 | void 0 46 | foo.bar 47 | +foo 48 | ``` 49 | 50 | 51 | ## Installation 52 | 53 | ```sh 54 | npm install babel-plugin-minify-simplify 55 | ``` 56 | 57 | ## Usage 58 | 59 | ### Via `.babelrc` (Recommended) 60 | 61 | **.babelrc** 62 | 63 | ```json 64 | { 65 | "plugins": ["minify-simplify"] 66 | } 67 | ``` 68 | 69 | ### Via CLI 70 | 71 | ```sh 72 | babel --plugins minify-simplify script.js 73 | ``` 74 | 75 | ### Via Node API 76 | 77 | ```javascript 78 | require("babel-core").transform("code", { 79 | plugins: ["minify-simplify"] 80 | }); 81 | ``` 82 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | const through = require("through2"); 2 | const chalk = require("chalk"); 3 | const newer = require("gulp-newer"); 4 | const babel = require("gulp-babel"); 5 | const gutil = require("gulp-util"); 6 | const gulp = require("gulp"); 7 | const path = require("path"); 8 | 9 | const scripts = "./packages/*/src/**/*.js"; 10 | const dest = "packages"; 11 | 12 | let srcEx, libFragment; 13 | 14 | if (path.win32 === path) { 15 | srcEx = /(packages\\[^\\]+)\\src\\/; 16 | libFragment = "$1\\lib\\"; 17 | } else { 18 | srcEx = new RegExp("(packages/[^/]+)/src/"); 19 | libFragment = "$1/lib/"; 20 | } 21 | 22 | export function build() { 23 | return gulp.src(scripts) 24 | .pipe(through.obj((file, enc, callback) => { 25 | file._path = file.path; 26 | file.path = file.path.replace(srcEx, libFragment); 27 | callback(null, file); 28 | })) 29 | .pipe(newer(dest)) 30 | .pipe(through.obj((file, enc, callback) => { 31 | gutil.log("Compiling", "'" + chalk.cyan(file._path) + "'..."); 32 | callback(null, file); 33 | })) 34 | .pipe(babel()) 35 | .pipe(gulp.dest(dest)); 36 | } 37 | 38 | export const watch = gulp.series(build, () => { 39 | gulp.watch(scripts, { debounceDelay: 200 }, build) 40 | .on('error', () => {}); 41 | }); 42 | 43 | export default build; 44 | -------------------------------------------------------------------------------- /packages/babel-helper-mark-eval-scopes/__tests__/helper-mark-eval-scopes-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const helper = require("../src"); 5 | 6 | function getPath(source) { 7 | let path; 8 | 9 | babel.transform(source, { 10 | babelrc: false, 11 | plugins: [ 12 | function ({traverse}) { 13 | traverse.clearCache(); 14 | return { 15 | visitor: { 16 | Program(programPath) { 17 | path = programPath; 18 | } 19 | } 20 | }; 21 | } 22 | ] 23 | }); 24 | 25 | return path; 26 | } 27 | 28 | describe("babel-helper-mark-eval-scopes", () => { 29 | it("getEvalScopes - should give a set of scopes which contains eval", () => { 30 | const source = ` 31 | function foo() { 32 | function bar() { 33 | eval(";"); 34 | } 35 | function baz() { 36 | noeval(); 37 | } 38 | } 39 | `; 40 | 41 | const program = getPath(source); 42 | const evalScopes = [...helper.getEvalScopes(program)]; 43 | 44 | expect(evalScopes).toContain(program.scope); 45 | expect(evalScopes).toContain(program.get("body.0.body.body.0").scope); 46 | expect(evalScopes).not.toContain(program.get("body.0.body.body.1").scope); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/babel-helper-mark-eval-scopes/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const EVAL_SCOPE_MARKER = Symbol("evalInScope"); 4 | 5 | module.exports = { 6 | EVAL_SCOPE_MARKER, 7 | getEvalScopes, 8 | markEvalScopes, 9 | isMarked, 10 | hasEval, 11 | }; 12 | 13 | function getEvalScopes(path) { 14 | const evalScopes = new Set; 15 | 16 | function add(scope) { 17 | let evalScope = scope; 18 | do { 19 | evalScopes.add(evalScope); 20 | } while (evalScope = evalScope.parent); 21 | } 22 | 23 | path.traverse({ 24 | CallExpression(evalPath) { 25 | const callee = evalPath.get("callee"); 26 | 27 | if (callee.isIdentifier() && callee.node.name === "eval" && !callee.scope.getBinding("eval")) { 28 | add(callee.scope); 29 | } 30 | } 31 | }); 32 | 33 | return evalScopes; 34 | } 35 | 36 | function markEvalScopes(path, key = EVAL_SCOPE_MARKER) { 37 | const evalScopes = getEvalScopes(path); 38 | [...evalScopes].forEach((scope) => { 39 | scope[key] = true; 40 | }); 41 | } 42 | 43 | function isMarked(scope, key = EVAL_SCOPE_MARKER) { 44 | return Object.prototype.hasOwnProperty.call(scope, key); 45 | } 46 | 47 | function hasEval(scope, key = EVAL_SCOPE_MARKER) { 48 | if (!isMarked(scope, key)) { 49 | markEvalScopes(scope, key); 50 | } 51 | return scope[key]; 52 | } 53 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-debugger/__tests__/remove-debugger-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("remove-debugger-plugin", () => { 14 | it("should remove debugger", () => { 15 | const source = "debugger;"; 16 | const expected = ""; 17 | expect(transform(source)).toBe(expected); 18 | }); 19 | 20 | it("should remove debugger only", () => { 21 | const source = "debugger; 1;"; 22 | const expected = "1;"; 23 | expect(transform(source)).toBe(expected); 24 | }); 25 | 26 | it("statement no block", () => { 27 | const source = unpad(` 28 | if (blah) debugger; 29 | for (;;) debugger; 30 | for (var blah in []) debugger; 31 | for (var blah of []) debugger; 32 | while (blah) debugger; 33 | do debugger; while (blah); 34 | `); 35 | 36 | const expected = unpad(` 37 | if (blah) {} 38 | for (;;) {} 39 | for (var blah in []) {} 40 | for (var blah of []) {} 41 | while (blah) {} 42 | do {} while (blah); 43 | `); 44 | expect(transform(source).trim()).toBe(expected); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-type-constructors/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-type-constructors 2 | 3 | **Note:** Not recommended if full support for IE8 and lower is required. [Details](https://github.com/babel/babili/pull/45#discussion_r70181249) 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | Boolean(x); 11 | Number(x); 12 | String(x); 13 | Array(3); 14 | Array(3,1); 15 | Object({foo: 'bar'}); 16 | ``` 17 | 18 | **Out** 19 | 20 | ```javascript 21 | !!x; 22 | +x; 23 | x + ""; 24 | [,,,]; 25 | [3, 1]; 26 | {foo: 'bar'}; 27 | ``` 28 | 29 | ## Installation 30 | 31 | ```sh 32 | npm install babel-plugin-minify-type-constructors 33 | ``` 34 | 35 | ## Usage 36 | 37 | ### Via `.babelrc` (Recommended) 38 | 39 | **.babelrc** 40 | 41 | ```json 42 | { 43 | "plugins": ["minify-type-constructors"] 44 | } 45 | ``` 46 | 47 | ### Via CLI 48 | 49 | ```sh 50 | babel --plugins minify-type-constructors script.js 51 | ``` 52 | 53 | ### Via Node API 54 | 55 | ```javascript 56 | require("babel-core").transform("code", { 57 | plugins: ["minify-type-constructors"] 58 | }); 59 | ``` 60 | 61 | ## Options 62 | 63 | + `array` - prevent plugin from minifying arrays 64 | + `boolean` - prevent plugin from minifying booleans 65 | + `number` — prevent plugin from minifying numbers 66 | + `object` — prevent plugin from minifying objects 67 | + `string` — prevent plugin from minifying strings 68 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/src/array-collapser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Collapser = require("./collapser"); 4 | 5 | class ArrayCollapser extends Collapser { 6 | isInitTypeValid(init) { 7 | return init.isArrayExpression(); 8 | } 9 | 10 | isExpressionTypeValid(expr) { 11 | return expr.isCallExpression(); 12 | } 13 | 14 | getExpressionChecker(objName, checkReference) { 15 | return (expr) => { 16 | // checks expr is of form: 17 | // foo.push(rval1, ...nrvals) 18 | 19 | const callee = expr.get("callee"); 20 | 21 | if (!callee.isMemberExpression()) { 22 | return false; 23 | } 24 | 25 | const obj = callee.get("object"), prop = callee.get("property"); 26 | if (!obj.isIdentifier() || 27 | obj.node.name !== objName || 28 | !prop.isIdentifier() || 29 | prop.node.name !== "push" 30 | ) { 31 | return false; 32 | } 33 | 34 | const args = expr.get("arguments"); 35 | if (args.some(checkReference)) { 36 | return false; 37 | } 38 | return true; 39 | }; 40 | } 41 | 42 | extractAssignment(expr) { 43 | return expr.node.arguments; 44 | } 45 | 46 | addSuccessfully(t, args, init) { 47 | args.map((a) => init.elements.push(a)); 48 | return true; 49 | } 50 | } 51 | 52 | module.exports = ArrayCollapser; 53 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-member-expression-literals/__tests__/transform-member-expression-literals-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("transform-member-expressions-literals-plugin", () => { 14 | it("should work with string literals", () => { 15 | const source = "foo['bar'];"; 16 | const expected = "foo.bar;"; 17 | expect(transform(source)).toBe(expected); 18 | }); 19 | 20 | it("should work with numbers", () => { 21 | const source = "foo['1'];"; 22 | const expected = "foo[1];"; 23 | expect(transform(source)).toBe(expected); 24 | }); 25 | 26 | it("should not transform invalid identifiers", () => { 27 | const source = unpad(` 28 | foo["default"]; 29 | foo["import"]; 30 | `); 31 | expect(transform(source)).toBe(source); 32 | }); 33 | 34 | it("should not transform non-string properties", () => { 35 | const source = "foo[a];"; 36 | expect(transform(source)).toBe(source); 37 | }); 38 | 39 | it("should not transform literals that are not computed", () => { 40 | const source = "foo.bar;"; 41 | expect(transform(source)).toBe(source); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 14 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/src/object-collapser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Collapser = require("./collapser"); 4 | 5 | class ObjectCollapser extends Collapser { 6 | isInitTypeValid(init) { 7 | return init.isObjectExpression(); 8 | } 9 | 10 | isExpressionTypeValid(expr) { 11 | return expr.isAssignmentExpression(); 12 | } 13 | 14 | getExpressionChecker(objName, checkReference) { 15 | return (expr) => { 16 | // checks expr is of form: 17 | // foo.a = rval | foo[a] = rval 18 | 19 | const left = expr.get("left"); 20 | if (!left.isMemberExpression()) { 21 | return false; 22 | } 23 | 24 | const obj = left.get("object"), prop = left.get("property"); 25 | if (!obj.isIdentifier() || obj.node.name !== objName) { 26 | return false; 27 | } 28 | if (!prop.isIdentifier() && checkReference(prop)) { 29 | return false; 30 | } 31 | if (left.node.computed && 32 | !(prop.isStringLiteral() || prop.isNumericLiteral())) { 33 | return false; 34 | } 35 | 36 | const right = expr.get("right"); 37 | if (checkReference(right)) { 38 | return false; 39 | } 40 | 41 | return true; 42 | }; 43 | } 44 | 45 | extractAssignment(expr) { 46 | return [expr.node.left.property, expr.node.right]; 47 | } 48 | 49 | addSuccessfully(t, [left, right], init) { 50 | init.properties.push(t.objectProperty(left, right)); 51 | return true; 52 | } 53 | } 54 | 55 | module.exports = ObjectCollapser; 56 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-replace/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-replace 2 | 3 | Configurable "search and replace" plugin. Replaces matching nodes in the tree with a given replacement node. For example you can replace `process.NODE_ENV` with `"production"`. 4 | 5 | ## Example 6 | 7 | **Options** 8 | 9 | ```javascript 10 | [ 11 | { 12 | identifierName: "__DEV__", 13 | replacement: { 14 | type: "numericLiteral", 15 | value: 0, 16 | }, 17 | }, 18 | ] 19 | ``` 20 | 21 | **In** 22 | 23 | ```javascript 24 | if (!__DEV__) { 25 | foo(); 26 | } 27 | if (a.__DEV__) { 28 | foo(); 29 | } 30 | ``` 31 | 32 | **Out** 33 | 34 | ```javascript 35 | if (!0) { 36 | foo(); 37 | } 38 | if (a.__DEV__) { 39 | foo(); 40 | } 41 | ``` 42 | 43 | ## Installation 44 | 45 | ```sh 46 | npm install babel-plugin-minify-replace 47 | ``` 48 | 49 | ## Usage 50 | 51 | ### Via `.babelrc` (Recommended) 52 | 53 | **.babelrc** 54 | 55 | ```json 56 | // without options 57 | { 58 | "plugins": ["minify-replace"] 59 | } 60 | ``` 61 | 62 | ```json 63 | // with options 64 | { 65 | "plugins": [ 66 | ["minify-replace", { 67 | "replacements": [{ 68 | "identifierName": "__DEV__", 69 | "replacement": { 70 | "type": "booleanLiteral", 71 | "value": true 72 | } 73 | }] 74 | }] 75 | ] 76 | } 77 | ``` 78 | 79 | ### Via CLI 80 | 81 | ```sh 82 | babel --plugins minify-replace script.js 83 | ``` 84 | 85 | ### Via Node API 86 | 87 | ```javascript 88 | require("babel-core").transform("code", { 89 | plugins: ["minify-replace"] 90 | }); 91 | ``` 92 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-dead-code-elimination/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-dead-code-elimination 2 | 3 | Inlines bindings when possible. Tries to evaluate expressions and prunes unreachable as a result. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | function foo() {var x = 1;} 11 | function bar() { var x = f(); } 12 | function baz() { 13 | var x = 1; 14 | console.log(x); 15 | function unused() { 16 | return 5; 17 | } 18 | } 19 | ``` 20 | 21 | **Out** 22 | 23 | ```javascript 24 | function foo() {} 25 | function bar() { f(); } 26 | function baz() { 27 | console.log(1); 28 | } 29 | ``` 30 | 31 | ## Installation 32 | 33 | ```sh 34 | npm install babel-plugin-minify-dead-code-elimination 35 | ``` 36 | 37 | ## Usage 38 | 39 | ### Via `.babelrc` (Recommended) 40 | 41 | **.babelrc** 42 | 43 | ```json 44 | // without options 45 | { 46 | "plugins": ["minify-dead-code-elimination"] 47 | } 48 | 49 | // with options 50 | { 51 | "plugins": ["minify-dead-code-elimination", { "optimizeRawSize": true }] 52 | } 53 | ``` 54 | 55 | ### Via CLI 56 | 57 | ```sh 58 | babel --plugins minify-dead-code-elimination script.js 59 | ``` 60 | 61 | ### Via Node API 62 | 63 | ```javascript 64 | require("babel-core").transform("code", { 65 | plugins: ["minify-dead-code-elimination"] 66 | }); 67 | ``` 68 | 69 | ## Options 70 | 71 | + `keepFnName` - prevent plugin from removing function name. Useful for code depending on `fn.name` 72 | + `keepFnArgs` - prevent plugin from removing function args. Useful for code depending on `fn.length` 73 | + `keepClassName` - prevent mangler from altering class names. 74 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-property-literals/__tests__/transform-property-literals-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("transform-property-literals-plugin", () => { 14 | it("should strip unnecessary property literal qoutes", () => { 15 | const source = "var x = { 'foo': 'bar' };"; 16 | const expected = "var x = { foo: 'bar' };"; 17 | expect(transform(source)).toBe(expected); 18 | }); 19 | 20 | it("should strip unnecessary property literal qoutes for numbers", () => { 21 | const source = "var x = { '1': 'bar' };"; 22 | const expected = "var x = { 1: 'bar' };"; 23 | expect(transform(source)).toBe(expected); 24 | }); 25 | 26 | it("should not transform invalid identifiers", () => { 27 | const source = unpad(` 28 | ({ 29 | "default": null, 30 | "import": null 31 | }); 32 | `); 33 | expect(transform(source)).toBe(source); 34 | }); 35 | 36 | it("should not transform non-string properties", () => { 37 | const source = unpad(` 38 | ({ 39 | foo: null 40 | }); 41 | `); 42 | expect(transform(source)).toBe(source); 43 | }); 44 | 45 | it("should not transform propety keys that are computed", () => { 46 | const source = unpad(` 47 | ({ 48 | [a]: null 49 | }); 50 | `); 51 | expect(transform(source)).toBe(source); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-mangle-names/README.md: -------------------------------------------------------------------------------- 1 | # babel-plugin-minify-mangle-names 2 | 3 | Context- and scope- aware variable renaming. 4 | 5 | ## Example 6 | 7 | **In** 8 | 9 | ```javascript 10 | var globalVariableName = 42; 11 | function foo() { 12 | var longLocalVariableName = 1; 13 | if (longLocalVariableName) { 14 | console.log(longLocalVariableName); 15 | } 16 | } 17 | ``` 18 | 19 | **Out** 20 | 21 | ```javascript 22 | var globalVariableName = 42; 23 | function foo() { 24 | var a = 1; 25 | if (a) { 26 | console.log(a); 27 | } 28 | } 29 | ``` 30 | 31 | ## Installation 32 | 33 | ```sh 34 | npm install babel-plugin-minify-mangle-names 35 | ``` 36 | 37 | ## Usage 38 | 39 | ### Via `.babelrc` (Recommended) 40 | 41 | **.babelrc** 42 | 43 | ```json 44 | // without options 45 | { 46 | "plugins": ["minify-mangle-names"] 47 | } 48 | ``` 49 | 50 | ```json 51 | // with options 52 | { 53 | "plugins": ["minify-mangle-names", { "blacklist": { "foo": true, "bar": true} }] 54 | } 55 | ``` 56 | 57 | ### Via CLI 58 | 59 | ```sh 60 | babel --plugins minify-mangle-names script.js 61 | ``` 62 | 63 | ### Via Node API 64 | 65 | ```javascript 66 | require("babel-core").transform("code", { 67 | plugins: ["minify-mangle-names"] 68 | }); 69 | ``` 70 | 71 | ## Options 72 | 73 | + `blacklist` - A plain JS Object with keys as identifier names and values indicating whether to exclude 74 | + `eval` - mangle identifiers in scopes accessible by eval 75 | + `keepFnName` - prevent mangler from altering function names. Useful for code depending on `fn.name` 76 | + `topLevel` - mangle topLevel Identifiers 77 | + `keepClassName` - prevent mangler from altering class names. 78 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-flip-comparisons/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | const isVoid0 = require("babel-helper-is-void-0")(t); 5 | 6 | return { 7 | name: "minify-flip-comparisons", 8 | visitor: { 9 | // flip comparisons with a pure right hand value, this ensures 10 | // consistency with comparisons and increases the length of 11 | // strings that gzip can match 12 | // typeof blah === 'function' -> 'function' === typeof blah 13 | BinaryExpression(path) { 14 | const { node } = path; 15 | const { right, left } = node; 16 | 17 | // Make sure we have a constant on the right. 18 | if (!t.isLiteral(right) && !isVoid0(right) && 19 | !(t.isUnaryExpression(right) && t.isLiteral(right.argument)) && 20 | !t.isObjectExpression(right) && !t.isArrayExpression(right) 21 | ) { 22 | return; 23 | } 24 | 25 | // Commutative operators. 26 | if (t.EQUALITY_BINARY_OPERATORS.indexOf(node.operator) >= 0 || 27 | ["*", "^", "&", "|"].indexOf(node.operator) >= 0 28 | ) { 29 | node.left = right; 30 | node.right = left; 31 | return; 32 | } 33 | 34 | if (t.BOOLEAN_NUMBER_BINARY_OPERATORS.indexOf(node.operator) >= 0) { 35 | node.left = right; 36 | node.right = left; 37 | let operator; 38 | switch (node.operator) { 39 | case ">": operator = "<"; break; 40 | case "<": operator = ">"; break; 41 | case ">=": operator = "<="; break; 42 | case "<=": operator = ">="; break; 43 | } 44 | node.operator = operator; 45 | return; 46 | } 47 | }, 48 | }, 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-regexp-constructors/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function createRegExpLiteral(args, prettify, t) { 4 | const evaluatedArgs = args.map((a) => a.evaluate()); 5 | if (!evaluatedArgs.every((a) => a.confident === true && 6 | typeof a.value === "string")) { 7 | return; 8 | } 9 | let pattern = (evaluatedArgs.length >= 1 && 10 | evaluatedArgs[0].value !== "") ? 11 | evaluatedArgs[0].value : 12 | "(?:)"; 13 | const flags = evaluatedArgs.length >= 2 ? 14 | evaluatedArgs[1].value : 15 | ""; 16 | 17 | pattern = new RegExp(pattern).source; 18 | if (prettify) { 19 | pattern = pattern.replace(/\n/g, "\\n") 20 | .replace(/\u2028/g, "\\u2028") 21 | .replace(/\u2029/g, "\\u2029") 22 | .replace(/[\b]/g, "[\\b]") 23 | .replace(/\v/g, "\\v") 24 | .replace(/\f/g, "\\f") 25 | .replace(/\r/g, "\\r"); 26 | } 27 | return t.regExpLiteral(pattern, flags); 28 | } 29 | 30 | function maybeReplaceWithRegExpLiteral(path, t) { 31 | if (!t.isIdentifier(path.node.callee, {name: "RegExp"})) { 32 | return; 33 | } 34 | const regExpLiteral = createRegExpLiteral(path.get("arguments"), true, t); 35 | if (regExpLiteral) { 36 | path.replaceWith(regExpLiteral); 37 | } 38 | } 39 | 40 | module.exports = function({ types: t }) { 41 | return { 42 | name: "transform-regexp-constructors", 43 | visitor: { 44 | NewExpression(path) { 45 | maybeReplaceWithRegExpLiteral(path, t); 46 | }, 47 | CallExpression(path) { 48 | // equivalent to `new RegExp()` according to §21.2.3 49 | maybeReplaceWithRegExpLiteral(path, t); 50 | }, 51 | }, 52 | }; 53 | }; 54 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/src/set-collapser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Collapser = require("./collapser"); 4 | 5 | class SetCollapser extends Collapser { 6 | isInitTypeValid(init) { 7 | return init.isNewExpression() && 8 | init.get("callee").isIdentifier() && 9 | init.node.callee.name === "Set" && 10 | // other iterables might not be append-able 11 | (init.node.arguments.length === 0 || 12 | (init.node.arguments.length === 1 && init.get("arguments")[0].isArrayExpression())); 13 | } 14 | 15 | isExpressionTypeValid(expr) { 16 | return expr.isCallExpression(); 17 | } 18 | 19 | getExpressionChecker(objName, checkReference) { 20 | return (expr) => { 21 | // checks expr is of form: 22 | // foo.add(rval) 23 | 24 | const callee = expr.get("callee"); 25 | 26 | if (!callee.isMemberExpression()) { 27 | return false; 28 | } 29 | 30 | const obj = callee.get("object"), prop = callee.get("property"); 31 | if (!obj.isIdentifier() || 32 | obj.node.name !== objName || 33 | !prop.isIdentifier() || 34 | prop.node.name !== "add" 35 | ) { 36 | return false; 37 | } 38 | 39 | const args = expr.get("arguments"); 40 | if (args.length !== 1) { 41 | return false; 42 | } 43 | if (checkReference(args)) { 44 | return false; 45 | } 46 | return true; 47 | }; 48 | } 49 | 50 | extractAssignment(expr) { 51 | return expr.node.arguments[0]; 52 | } 53 | 54 | addSuccessfully(t, arg, init) { 55 | if (init.arguments.length === 0) { 56 | init.arguments.push(t.arrayExpression()); 57 | } 58 | init.arguments[0].elements.push(arg); 59 | return true; 60 | } 61 | } 62 | 63 | module.exports = SetCollapser; 64 | -------------------------------------------------------------------------------- /packages/babel-preset-babili/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-preset-babili", 3 | "version": "0.0.11", 4 | "description": "", 5 | "homepage": "https://github.com/babel/babili#readme", 6 | "repository": "https://github.com/babel/babili/tree/master/packages/babel-preset-babili", 7 | "bugs": "https://github.com/babel/babili/issues", 8 | "author": "amasad", 9 | "license": "MIT", 10 | "main": "lib/index.js", 11 | "keywords": [ 12 | "babel-preset" 13 | ], 14 | "dependencies": { 15 | "babel-plugin-minify-builtins": "^0.0.1", 16 | "babel-plugin-minify-constant-folding": "^0.0.4", 17 | "babel-plugin-minify-dead-code-elimination": "^0.1.3", 18 | "babel-plugin-minify-flip-comparisons": "^0.0.2", 19 | "babel-plugin-minify-guarded-expressions": "^0.0.4", 20 | "babel-plugin-minify-infinity": "^0.0.3", 21 | "babel-plugin-minify-mangle-names": "^0.0.7", 22 | "babel-plugin-minify-numeric-literals": "^0.0.1", 23 | "babel-plugin-minify-replace": "^0.0.1", 24 | "babel-plugin-minify-simplify": "^0.0.7", 25 | "babel-plugin-minify-type-constructors": "^0.0.3", 26 | "babel-plugin-transform-inline-consecutive-adds": "^0.0.2", 27 | "babel-plugin-transform-member-expression-literals": "^6.8.1", 28 | "babel-plugin-transform-merge-sibling-variables": "^6.8.2", 29 | "babel-plugin-transform-minify-booleans": "^6.8.0", 30 | "babel-plugin-transform-property-literals": "^6.8.1", 31 | "babel-plugin-transform-regexp-constructors": "^0.0.5", 32 | "babel-plugin-transform-remove-console": "^6.8.0", 33 | "babel-plugin-transform-remove-debugger": "^6.8.0", 34 | "babel-plugin-transform-remove-undefined": "^0.0.5", 35 | "babel-plugin-transform-simplify-comparison-operators": "^6.8.1", 36 | "babel-plugin-transform-undefined-to-void": "^6.8.0", 37 | "lodash.isplainobject": "^4.0.6" 38 | }, 39 | "devDependencies": {} 40 | } 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "license": "MIT", 4 | "author": "amasad", 5 | "scripts": { 6 | "bootstrap": "lerna bootstrap", 7 | "changelog": "lerna-changelog", 8 | "clean": "lerna clean", 9 | "publish": "git pull origin master --rebase && npm run build && npm test && lerna publish", 10 | "publish-internal": "git pull origin master --rebase && npm run build && NPM_DIST_TAG=internal ./node_modules/.bin/lerna publish --skip-git", 11 | "updated": "lerna updated", 12 | "lint": "eslint packages/*/src packages/*/__tests__ scripts/*.js", 13 | "fix": "eslint packages/*/src packages/*/__tests__ scripts/*.js --fix", 14 | "test": "jest", 15 | "build": "gulp build", 16 | "watch": "gulp watch", 17 | "ci": "npm run lint && npm run bootstrap && jest" 18 | }, 19 | "jest": { 20 | "transform": { 21 | ".*": "/node_modules/babel-jest" 22 | }, 23 | "testEnvironment": "node", 24 | "testPathDirs": [ 25 | "packages" 26 | ], 27 | "transformIgnorePatterns": [ 28 | "/node_modules/" 29 | ] 30 | }, 31 | "devDependencies": { 32 | "babel-core": "^6.22.1", 33 | "babel-eslint": "^7.1.1", 34 | "babel-jest": "^18.0.0", 35 | "babel-plugin-transform-es2015-block-scoping": "^6.22.0", 36 | "babel-preset-env": "^1.1.4", 37 | "babel-traverse": "^6.22.1", 38 | "bytes": "^2.1.0", 39 | "chalk": "^1.1.3", 40 | "cli-table": "^0.3.1", 41 | "closure-compiler": "^0.2.12", 42 | "commander": "^2.9.0", 43 | "eslint": "^3.14.1", 44 | "eslint-config-babel": "^5.0.0", 45 | "eslint-plugin-flowtype": "^2.29.2", 46 | "google-closure-compiler-js": "^20170124.0.0", 47 | "gulp": "github:gulpjs/gulp#4.0", 48 | "gulp-babel": "^6.1.2", 49 | "gulp-newer": "^1.1.0", 50 | "gulp-util": "^3.0.8", 51 | "jest-cli": "^18.0.0", 52 | "lerna": "2.0.0-beta.37", 53 | "lerna-changelog": "^0.3.0", 54 | "through2": "^2.0.1", 55 | "uglify-js": "^2.7.3" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-simplify-comparison-operators/__tests__/strict-equals-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("simplify-comparison-operators-plugin", () => { 14 | it("should simplify comparison", () => { 15 | const source = "'function' === typeof a;"; 16 | const expected = "'function' == typeof a;"; 17 | expect(transform(source)).toBe(expected); 18 | }); 19 | 20 | it("should simplify comparison operations", () => { 21 | const source = "null === null;"; 22 | const expected = "null == null;"; 23 | expect(transform(source)).toBe(expected); 24 | }); 25 | 26 | it("should comparison operations 2", () => { 27 | const source = unpad(` 28 | var x = null; 29 | x === null; 30 | `); 31 | const expected = unpad(` 32 | var x = null; 33 | x == null; 34 | `); 35 | 36 | expect(transform(source)).toBe(expected); 37 | }); 38 | 39 | it("should not simplify comparison", () => { 40 | const source = unpad(` 41 | var x; 42 | x === null; 43 | `); 44 | const expected = unpad(` 45 | var x; 46 | x === null; 47 | `); 48 | 49 | expect(transform(source)).toBe(expected); 50 | }); 51 | 52 | it("should not simplify comparison 2", () => { 53 | const source = unpad(` 54 | var x; 55 | if (wow) x = foo(); 56 | x === null; 57 | `); 58 | const expected = unpad(` 59 | var x; 60 | if (wow) x = foo(); 61 | x === null; 62 | `); 63 | 64 | expect(transform(source)).toBe(expected); 65 | }); 66 | 67 | it("should not simplify comparison if already simplified", function() { 68 | const source = "typeof 1 == \"number\";"; 69 | expect(transform(source)).toBe(source); 70 | }); 71 | 72 | it("should not simplify comparison if not equality check", function() { 73 | const source = "a > b;"; 74 | expect(transform(source)).toBe(source); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-constant-folding/__tests__/constant-folding-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const unpad = require("../../../utils/unpad"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [require("../src/index")], 9 | }).code; 10 | } 11 | 12 | describe("constant-folding-plugin", () => { 13 | it("should evaluate some expressions", () => { 14 | const source = unpad(` 15 | "a" + "b" 16 | 2 * 3; 17 | 1/3; 18 | 4 | 3; 19 | a(), b(); 20 | var x = 1; 21 | foo(x); 22 | "b" + a + "c" + "d" + g + z + "f" + "h" + "z" 23 | `); 24 | 25 | const expected = unpad(` 26 | "ab"; 27 | 6; 28 | 1 / 3; 29 | 7; 30 | a(), b(); 31 | var x = 1; 32 | foo(x); 33 | "b" + a + "cd" + g + z + "fhz"; 34 | `); 35 | expect(transform(source)).toBe(expected); 36 | }); 37 | 38 | it("should skip -0", () => { 39 | const source = unpad(` 40 | -0; 41 | +-0; 42 | +0; 43 | `); 44 | 45 | const expected = unpad(` 46 | -0; 47 | -0; 48 | 0; 49 | `); 50 | expect(transform(source)).toBe(expected); 51 | }); 52 | 53 | it("should handle runtime errors", () => { 54 | const source = unpad(` 55 | try { 56 | x({ 57 | toString: 0 58 | } + ''); 59 | } catch (e) {} 60 | `); 61 | expect(transform(source)).toBe(source); 62 | }); 63 | 64 | it("should handle script escape", () => { 65 | const source = unpad(` 66 | " { 76 | const source = unpad(` 77 | " { 87 | const source = unpad(` 88 | " { 14 | it("should convert infinity to division over 0", () => { 15 | const source = unpad(` 16 | Infinity; 17 | `); 18 | 19 | const expected = unpad(` 20 | 1 / 0; 21 | `); 22 | 23 | expect(transform(source)).toBe(expected); 24 | }); 25 | 26 | it("should not convert infinity when its a property", () => { 27 | const source = unpad(` 28 | var x = { Infinity: 0 }; 29 | `); 30 | 31 | const expected = unpad(` 32 | var x = { Infinity: 0 }; 33 | `); 34 | 35 | expect(transform(source)).toBe(expected); 36 | }); 37 | 38 | it("should not convert infinity when its a property", () => { 39 | const source = unpad(` 40 | x.Infinity; 41 | `); 42 | 43 | const expected = unpad(` 44 | x.Infinity; 45 | `); 46 | 47 | expect(transform(source)).toBe(expected); 48 | }); 49 | 50 | it("should not convert infinity if its a assignment expression", () => { 51 | const source = unpad(` 52 | Infinity = 1; 53 | `); 54 | 55 | const expected = unpad(` 56 | Infinity = 1; 57 | `); 58 | 59 | expect(transform(source)).toBe(expected); 60 | }); 61 | 62 | it("should not convert infinity when its destructed", () => { 63 | const source = unpad(` 64 | ({ Infinity } = 1); 65 | [Infinity] = foo; 66 | [...Infinity] = foo; 67 | `); 68 | 69 | const expected = unpad(` 70 | ({ Infinity } = 1); 71 | [Infinity] = foo; 72 | [...Infinity] = foo; 73 | `); 74 | 75 | expect(transform(source)).toBe(expected); 76 | }); 77 | 78 | it("should not convert infinity when as a function params", () => { 79 | const source = unpad(` 80 | function a(Infinity) {} 81 | function a(...Infinity) {} 82 | function a({ Infinity }) {} 83 | `); 84 | 85 | const expected = unpad(` 86 | function a(Infinity) {} 87 | function a(...Infinity) {} 88 | function a({ Infinity }) {} 89 | `); 90 | 91 | expect(transform(source)).toBe(expected); 92 | }); 93 | 94 | }); 95 | -------------------------------------------------------------------------------- /packages/babel-preset-babili/__tests__/preset-tests.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const unpad = require("../../../utils/unpad"); 5 | 6 | function transform(code, options = {}, sourceType = "script") { 7 | return babel.transform(code, { 8 | sourceType, 9 | minified: false, 10 | presets: [ 11 | require("../src/index") 12 | ], 13 | }).code; 14 | } 15 | 16 | describe("preset", () => { 17 | // https://github.com/babel/babili/issues/122 18 | it ("should fix issue#122", () => { 19 | const source = unpad(` 20 | function foo() { 21 | var a, b, c; 22 | if (a) { 23 | if (b) { 24 | if (c) {} 25 | } 26 | } else { 27 | if (b) { 28 | } else { 29 | if (c) {} 30 | } 31 | } 32 | } 33 | `); 34 | const expected = unpad(` 35 | function foo() { 36 | var d, e, f; 37 | d ? e && f : e || f; 38 | } 39 | `); 40 | expect(transform(source)).toBe(expected); 41 | }); 42 | 43 | it("should fix remove comments", () => { 44 | const source = unpad(` 45 | var asdf = 1; // test 46 | `); 47 | const expected = unpad(` 48 | var asdf = 1; 49 | `); 50 | expect(transform(source)).toBe(expected); 51 | }); 52 | 53 | it("should keep license/preserve annotated comments", () => { 54 | const source = unpad(` 55 | /* @license */ 56 | var asdf = 1; 57 | `); 58 | const expected = unpad(` 59 | /* @license */ 60 | var asdf = 1; 61 | `); 62 | expect(transform(source)).toBe(expected); 63 | }); 64 | 65 | it("should fix issue#385 - impure if statements with Sequence and DCE", () => { 66 | const source = unpad(` 67 | a = b; 68 | c = d; 69 | if (false) { 70 | const x = y 71 | } 72 | `); 73 | const expected = unpad(` 74 | a = b, c = d; 75 | `); 76 | expect(transform(source)).toBe(expected); 77 | }); 78 | 79 | it("should fix issue#402 - lifting var decl & DCE", () => { 80 | const source = unpad(` 81 | function a() { 82 | if (0) { 83 | for (var i;;) { 84 | var something = 5; 85 | } 86 | } 87 | } 88 | a(); 89 | `); 90 | const expected = unpad(` 91 | function a() {} 92 | a(); 93 | `); 94 | expect(transform(source)).toBe(expected); 95 | }); 96 | 97 | }); 98 | -------------------------------------------------------------------------------- /packages/babel-helper-flip-expressions/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const flipSeen = Symbol("flipSeen"); 4 | 5 | module.exports = function(t) { 6 | return { 7 | hasSeen(node) { 8 | return !!node[flipSeen]; 9 | }, 10 | 11 | // Takes an expressions and determines if it has 12 | // more nodes that could benifit from flipping than not. 13 | shouldFlip(topNode, savings = 0) { 14 | visit(topNode); 15 | return savings > 0; 16 | 17 | function visit(node) { 18 | if (t.isUnaryExpression(node, { operator: "!" })) { 19 | savings++; 20 | return; 21 | } 22 | 23 | if (t.isLogicalExpression(node)) { 24 | visit(node.left); 25 | visit(node.right); 26 | return; 27 | } 28 | 29 | if (!(t.isBinaryExpression(node) && t.EQUALITY_BINARY_OPERATORS.indexOf(node.operator) > -1)) { 30 | // Binary expressions wouldn't hurut because we know how to flip them 31 | savings--; 32 | } 33 | } 34 | }, 35 | 36 | flip(node, resultNotUsed) { 37 | let lastNodeDesc; 38 | const ret = visit(node); 39 | 40 | ret[flipSeen] = true; 41 | 42 | if (resultNotUsed && lastNodeDesc) { 43 | const { parent, key } = lastNodeDesc; 44 | if (parent && key && t.isUnaryExpression(parent[key], { operator: "!" })) { 45 | parent[key] = parent[key].argument; 46 | } 47 | } 48 | 49 | return ret; 50 | 51 | function visit(node, parent, key) { 52 | lastNodeDesc = { parent, key }; 53 | 54 | if (t.isUnaryExpression(node, { operator: "!" })) { 55 | return node.argument; 56 | } 57 | 58 | if (t.isLogicalExpression(node)) { 59 | node.operator = node.operator === "&&" ? "||" : "&&"; 60 | node.left = visit(node.left, node, "left"); 61 | node.right = visit(node.right, node, "right"); 62 | return node; 63 | } 64 | 65 | if (t.isBinaryExpression(node)) { 66 | let operator; 67 | switch (node.operator) { 68 | case "!==": operator = "==="; break; 69 | case "===": operator = "!=="; break; 70 | case "!=": operator = "=="; break; 71 | case "==": operator = "!="; break; 72 | } 73 | 74 | if (operator) { 75 | node.operator = operator; 76 | return node; 77 | } 78 | 79 | // Falls through to unary expression 80 | } 81 | 82 | return t.unaryExpression("!", node, true); 83 | } 84 | }, 85 | }; 86 | }; 87 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-flip-comparisons/__tests__/flip-comparisons-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("flip-comparisons", () => { 14 | it("should merge two conditionals if the same consequent", () => { 15 | const source = unpad(` 16 | x === null ? undefined : x === undefined ? undefined : x ? foo(x) : wat(); 17 | `); 18 | 19 | const expected = unpad(` 20 | null === x ? undefined : x === undefined ? undefined : x ? foo(x) : wat(); 21 | `); 22 | 23 | expect(transform(source)).toBe(expected); 24 | }); 25 | 26 | it("should put values first in binary expressions", () => { 27 | const source = "a === 1;"; 28 | const expected = "1 === a;"; 29 | expect(transform(source)).toBe(expected); 30 | }); 31 | 32 | it("should put constants first in binary expressions", () => { 33 | const source = "a === -1;"; 34 | const expected = "-1 === a;"; 35 | expect(transform(source)).toBe(expected); 36 | }); 37 | 38 | it("should put pures first in binary expressions 2", () => { 39 | const source = "a === null;"; 40 | const expected = "null === a;"; 41 | expect(transform(source)).toBe(expected); 42 | }); 43 | 44 | it("should put pures first in binary expressions 3", () => { 45 | const source = unpad(` 46 | function foo() { 47 | if (foo !== null) { 48 | var bar; 49 | bar = baz; 50 | } 51 | x(); 52 | return x; 53 | } 54 | `); 55 | const expected = unpad(` 56 | function foo() { 57 | if (null !== foo) { 58 | var bar; 59 | bar = baz; 60 | } 61 | x(); 62 | return x; 63 | } 64 | `); 65 | expect(transform(source)).toBe(expected); 66 | }); 67 | 68 | it("should put pures first in binary expressions 2", () => { 69 | const source = "a === {};"; 70 | const expected = "({}) === a;"; 71 | expect(transform(source)).toBe(expected); 72 | }); 73 | 74 | it("should put constants first", () => { 75 | const source = unpad(` 76 | x * 100; 77 | x + 100; 78 | x - 100; 79 | x / 100; 80 | x > 100; 81 | x === void 0; 82 | `); 83 | 84 | const expected = unpad(` 85 | 100 * x; 86 | x + 100; 87 | x - 100; 88 | x / 100; 89 | 100 < x; 90 | void 0 === x; 91 | `); 92 | 93 | expect(transform(source)).toBe(expected); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-replace/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = ({ types: t }) => { 4 | const NO_MEMBER = Symbol("no member"); 5 | 6 | const replaceVisitor = { 7 | ReferencedIdentifier(path) { 8 | const { node } = path; 9 | const optionsMap = this.replacements[node.name]; 10 | if (!optionsMap) { 11 | return; 12 | } 13 | 14 | let options; 15 | if (path.parentPath.isMemberExpression({ object: node })) { 16 | const { property } = path.parent; 17 | const key = t.isIdentifier(property) && property.name; 18 | if (typeof key === "string") { 19 | options = optionsMap[key]; 20 | path = path.parentPath; 21 | } 22 | } 23 | 24 | if (!options) { 25 | options = optionsMap[NO_MEMBER]; 26 | } 27 | 28 | if (!options) { 29 | return; 30 | } 31 | 32 | path.replaceWith(options.node); 33 | }, 34 | }; 35 | 36 | return { 37 | name: "minify-replace", 38 | visitor: { 39 | Program(path) { 40 | /** 41 | Replacements is an array of objects like this: 42 | { 43 | identifierName: 'console', 44 | member: 'log', // optional 45 | replacement: { 46 | type: 'identifier', 47 | value: '', 48 | }, 49 | } 50 | **/ 51 | 52 | if (!this.opts.replacements) { 53 | // No replacements. Bail. 54 | return; 55 | } 56 | 57 | const map = Object.create(null); 58 | this.opts.replacements.forEach(({identifierName, replacement, member}) => { 59 | if (path.scope.globals[identifierName]) { 60 | // Convert to a node, we only allow identifiers and literals as replacements 61 | if (!replacement.type.match(/literal|identifier/i)) { 62 | throw new Error( 63 | "Only literals and identifier are supported as replacements" 64 | ); 65 | } 66 | 67 | const node = t[replacement.type](replacement.value); 68 | const options = { 69 | identifierName, 70 | node, 71 | member, 72 | }; 73 | 74 | if (!map[identifierName]) { 75 | map[identifierName] = {}; 76 | } 77 | 78 | if (member && map[identifierName][member]) { 79 | throw new Error(`Replacement collision ${identifierName}.${member}`); 80 | } 81 | map[identifierName][member || NO_MEMBER] = options; 82 | } 83 | }); 84 | 85 | path.traverse(replaceVisitor, { replacements: map }); 86 | }, 87 | }, 88 | }; 89 | }; 90 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-builtins/__tests__/minify-builtins.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const unpad = require("../../../utils/unpad"); 5 | const plugin = require("../src/index"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("minify-builtins", () => { 14 | it("should minify standard built in methods", () => { 15 | const source = unpad(` 16 | Math.max(a, b) + Math.max(b, a); 17 | function c() { 18 | let a = 10; 19 | const d = Number.isNaN(a); 20 | return d && Number.isFinite(a); 21 | } 22 | `); 23 | // Jest arranges in alphabetical order, So keeping it as _source 24 | expect({_source: source, expected: transform(source)}).toMatchSnapshot(); 25 | }); 26 | 27 | it("should minify standard built in properties", () => { 28 | const source = unpad(` 29 | Number.NAN + Number.NAN; 30 | function a () { 31 | return Math.PI + Math.PI + Number.EPSILON + Number.NAN; 32 | } 33 | `); 34 | expect({_source: source, expected: transform(source)}).toMatchSnapshot(); 35 | }); 36 | 37 | it("should take no of occurences in to account", () => { 38 | const source = unpad(` 39 | function a() { 40 | return Math.floor(a) + Math.floor(b) + Math.min(a, b); 41 | } 42 | Math.floor(a) + Math.max(a, b); 43 | `); 44 | expect({_source: source, expected: transform(source)}).toMatchSnapshot(); 45 | }); 46 | 47 | it("should collect and minify no matter any depth", () => { 48 | const source = unpad(` 49 | Math.max(a, b) + Math.max(a, b); 50 | function a (){ 51 | Math.max(b, a); 52 | return function b() { 53 | const a = Math.floor(c); 54 | Math.min(b, a) * Math.floor(b); 55 | } 56 | } 57 | `); 58 | expect({_source: source, expected: transform(source)}).toMatchSnapshot(); 59 | }); 60 | 61 | it("should evalaute expressions if applicable and optimize it", () => { 62 | const source = unpad(` 63 | const a = Math.max(Math.floor(2), 5); 64 | let b = 1.8; 65 | let x = Math.floor(Math.max(a, b)); 66 | foo(x); 67 | `); 68 | expect({_source: source, expected: transform(source)}).toMatchSnapshot(); 69 | }); 70 | 71 | it("should not evaluate if its side effecty", () => { 72 | const source = unpad(` 73 | Math.max(foo(), 1); 74 | Math.random(); 75 | `); 76 | expect({_source: source, expected: transform(source)}).toMatchSnapshot(); 77 | }); 78 | 79 | it("should not minify for computed properties", () => { 80 | const source = unpad(` 81 | let max = "floor"; 82 | Math[max](1.5); 83 | `); 84 | expect({_source: source, expected: transform(source)}).toMatchSnapshot(); 85 | }); 86 | 87 | }); 88 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-builtins/__tests__/__snapshots__/minify-builtins.js.snap: -------------------------------------------------------------------------------- 1 | exports[`minify-builtins should collect and minify no matter any depth 1`] = ` 2 | Object { 3 | "_source": "Math.max(a, b) + Math.max(a, b); 4 | function a (){ 5 | Math.max(b, a); 6 | return function b() { 7 | const a = Math.floor(c); 8 | Math.min(b, a) * Math.floor(b); 9 | } 10 | }", 11 | "expected": "var _Mathfloor = Math.floor; 12 | var _Mathmax = Math.max; 13 | _Mathmax(a, b) + _Mathmax(a, b); 14 | function a() { 15 | _Mathmax(b, a); 16 | return function b() { 17 | const a = _Mathfloor(c); 18 | Math.min(b, a) * _Mathfloor(b); 19 | }; 20 | }", 21 | } 22 | `; 23 | 24 | exports[`minify-builtins should evalaute expressions if applicable and optimize it 1`] = ` 25 | Object { 26 | "_source": "const a = Math.max(Math.floor(2), 5); 27 | let b = 1.8; 28 | let x = Math.floor(Math.max(a, b)); 29 | foo(x);", 30 | "expected": "const a = 5; 31 | let b = 1.8; 32 | let x = 5; 33 | foo(x);", 34 | } 35 | `; 36 | 37 | exports[`minify-builtins should minify standard built in methods 1`] = ` 38 | Object { 39 | "_source": "Math.max(a, b) + Math.max(b, a); 40 | function c() { 41 | let a = 10; 42 | const d = Number.isNaN(a); 43 | return d && Number.isFinite(a); 44 | }", 45 | "expected": "var _Mathmax = Math.max; 46 | _Mathmax(a, b) + _Mathmax(b, a); 47 | function c() { 48 | let a = 10; 49 | const d = false; 50 | return d && true; 51 | }", 52 | } 53 | `; 54 | 55 | exports[`minify-builtins should minify standard built in properties 1`] = ` 56 | Object { 57 | "_source": "Number.NAN + Number.NAN; 58 | function a () { 59 | return Math.PI + Math.PI + Number.EPSILON + Number.NAN; 60 | }", 61 | "expected": "var _MathPI = Math.PI; 62 | var _NumberNAN = Number.NAN; 63 | _NumberNAN + _NumberNAN; 64 | function a() { 65 | return _MathPI + _MathPI + Number.EPSILON + _NumberNAN; 66 | }", 67 | } 68 | `; 69 | 70 | exports[`minify-builtins should not evaluate if its side effecty 1`] = ` 71 | Object { 72 | "_source": "Math.max(foo(), 1); 73 | Math.random();", 74 | "expected": "Math.max(foo(), 1); 75 | Math.random();", 76 | } 77 | `; 78 | 79 | exports[`minify-builtins should not minify for computed properties 1`] = ` 80 | Object { 81 | "_source": "let max = \"floor\"; 82 | Math[max](1.5);", 83 | "expected": "let max = \"floor\"; 84 | Math[max](1.5);", 85 | } 86 | `; 87 | 88 | exports[`minify-builtins should take no of occurences in to account 1`] = ` 89 | Object { 90 | "_source": "function a() { 91 | return Math.floor(a) + Math.floor(b) + Math.min(a, b); 92 | } 93 | Math.floor(a) + Math.max(a, b);", 94 | "expected": "var _Mathfloor = Math.floor; 95 | function a() { 96 | return _Mathfloor(a) + _Mathfloor(b) + Math.min(a, b); 97 | } 98 | _Mathfloor(a) + Math.max(a, b);", 99 | } 100 | `; 101 | -------------------------------------------------------------------------------- /scripts/plugin-timing.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const babel = require("babel-core"); 3 | const preset = require("../packages/babel-preset-babili"); 4 | const fs = require("fs"); 5 | const Table = require("cli-table"); 6 | 7 | const hop = (o, key) => Object.hasOwnProperty.call(o, key); 8 | 9 | class Benchmark { 10 | constructor({ 11 | now = () => process.hrtime(), 12 | diff = (start) => { 13 | const delta = process.hrtime(start); 14 | return delta[0] * 1e3 + delta[1] / 1e6; 15 | } 16 | } = {}) { 17 | this.events = {}; 18 | this.visits = {}; 19 | this.results = {}; 20 | this.now = now; 21 | this.diff = diff; 22 | } 23 | push(name) { 24 | if (!hop(this.events, name)) { 25 | this.events[name] = []; 26 | this.visits[name] = 0; 27 | } 28 | this.events[name].push(this.now()); 29 | this.visits[name]++; 30 | } 31 | pop(name) { 32 | if (hop(this.events, name) && (this.events[name].length > 0)) { 33 | const start = this.events[name].shift(); 34 | const delta = this.diff(start); 35 | 36 | if (!hop(this.results, name)) { 37 | this.results[name] = { 38 | aggregate: 0, 39 | values: [] 40 | }; 41 | } 42 | 43 | this.results[name].aggregate += delta; 44 | this.results[name].values.push(delta); 45 | } 46 | } 47 | } 48 | 49 | run(process.argv[2]); 50 | 51 | function run (file) { 52 | const b = new Benchmark; 53 | babel.transform(fs.readFileSync(file).toString(), { 54 | presets: [preset], 55 | wrapPluginVisitorMethod(pluginAlias, visitorType, callback) { 56 | return function (...args) { 57 | b.push(pluginAlias); 58 | callback.call(this, ...args); 59 | b.pop(pluginAlias); 60 | }; 61 | } 62 | }); 63 | 64 | const table = new Table({ 65 | head: ["pluginAlias", "time(ms)", "# visits", "time/visit(ms)"], 66 | chars: { 67 | top: "", 68 | "top-mid": "", 69 | "top-left": "", 70 | "top-right": "", 71 | bottom: "", 72 | "bottom-mid": "", 73 | "bottom-left": "", 74 | "bottom-right": "", 75 | left: "", 76 | "left-mid": "", 77 | mid: "", 78 | "mid-mid": "", 79 | right: "", 80 | "right-mid": "", 81 | middle: " ", 82 | }, 83 | style: { 84 | "padding-left": 0, 85 | "padding-right": 0, 86 | head: ["bold"], 87 | }, 88 | }); 89 | 90 | const results = Object 91 | .keys(b.results) 92 | .map((name) => [name, b.results[name].aggregate, b.visits[name]]) 93 | .sort((a, b) => { 94 | if (a[1] < b[1]) return 1; 95 | if (a[1] > b[1]) return -1; 96 | return 0; 97 | }) 98 | .map((arr) => [arr[0], arr[1].toFixed(3), arr[2], (arr[1] / arr[2]).toFixed(3)]); 99 | 100 | table.push(...results); 101 | console.log(table.toString()); 102 | } 103 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-simplify/src/pattern-match.js: -------------------------------------------------------------------------------- 1 | const LEAF_NODE = Symbol("LEAF_NODE"); 2 | 3 | module.exports = class PatternMatch { 4 | constructor(patterns) { 5 | this.decisionTree = this.makeDecisionTree(patterns); 6 | } 7 | handle(input, isMatch) { 8 | const result = this.match(input, isMatch); 9 | 10 | if (!result.match) { 11 | throw new Error("No Match Found for " + input.toString()); 12 | } 13 | 14 | if (typeof result.value !== "function") { 15 | throw new Error("Expecting a function. Instead got - " + result.value.toString()); 16 | } 17 | 18 | result.value.call(null, input, result.keys); 19 | } 20 | match(input, isMatch = (a, b) => a === b) { 21 | let current = this.decisionTree; 22 | const result = { 23 | match: false, 24 | value: void 0, 25 | keys: [] 26 | }; 27 | 28 | // to handle falsy keys 29 | const NO_MATCH = Symbol("NO_MATCH"); 30 | 31 | for (let i = 0; i < input.length; i++) { 32 | let matchedKey = NO_MATCH; 33 | 34 | // because map doesn't support custom key equal function 35 | for (const key of current.keys()) { 36 | if (isMatch(key, input[i])) { 37 | matchedKey = key; 38 | result.keys.push(matchedKey); 39 | break; 40 | } 41 | } 42 | 43 | if (matchedKey !== NO_MATCH) { 44 | current = current.get(matchedKey); 45 | 46 | if (i === input.length - 1) { 47 | if (current.has(LEAF_NODE)) { 48 | result.match = true; 49 | result.value = current.get(LEAF_NODE); 50 | } 51 | break; 52 | } 53 | } else { 54 | break; 55 | } 56 | } 57 | return result; 58 | } 59 | makeDecisionTree(patterns) { 60 | // order of keys in a Map is the order of insertion 61 | const root = new Map; 62 | 63 | for (const pattern of patterns) { 64 | make(root, pattern); 65 | } 66 | 67 | return root; 68 | 69 | function make(parent, pattern) { 70 | if (pattern.length < 2) { 71 | throw new Error("at least 2 elements required in a pattern"); 72 | } 73 | 74 | if (pattern.length === 2) { 75 | if (parent.has(pattern[0])) { 76 | const pattern0 = parent.get(pattern[0]); 77 | if (!pattern0.has(LEAF_NODE)) { 78 | pattern0.set(LEAF_NODE, pattern[1]); 79 | } 80 | // here we don't handle duplicates 81 | // this pattern would have already been matched 82 | } else { 83 | parent.set(pattern[0], new Map([ 84 | [LEAF_NODE, pattern[1]] 85 | ])); 86 | } 87 | 88 | return parent; 89 | } 90 | 91 | const [current, ...rest] = pattern; 92 | 93 | if (parent.has(current)) { 94 | make(parent.get(current), rest); 95 | } else { 96 | parent.set(current, make(new Map, rest)); 97 | } 98 | return parent; 99 | } 100 | } 101 | }; 102 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-guarded-expressions/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | const flipExpressions = require("babel-helper-flip-expressions")(t); 5 | 6 | return { 7 | name: "minify-guarded-expressions", 8 | visitor: { 9 | // Convert guarded expressions 10 | // !a && b() --> a || b(); 11 | // This could change the return result of the expression so we only do it 12 | // on things where the result is ignored. 13 | LogicalExpression: { 14 | enter: [ 15 | function(path) { 16 | const { node } = path; 17 | 18 | const left = path.get("left"); 19 | const right = path.get("right"); 20 | 21 | // issues - 171, 174, 176 22 | // we assume that it is returned/assigned/part of a bigger expression 23 | // or utilized somehow 24 | // we check if we shouldBail only when evaluating 25 | // the rightside of the expression; 26 | // if the left side is evaluated to be deterministic, 27 | // we can safely replace the entire expression 28 | const shouldBail = !path.parentPath.isExpressionStatement(); 29 | 30 | if (node.operator === "&&") { 31 | const leftTruthy = left.evaluateTruthy(); 32 | if (leftTruthy === false) { 33 | // Short-circuit 34 | path.replaceWith(node.left); 35 | } else if (leftTruthy === true && left.isPure()) { 36 | path.replaceWith(node.right); 37 | } else if (right.evaluateTruthy() === false && right.isPure() && !shouldBail) { 38 | path.replaceWith(node.left); 39 | } 40 | } else if (node.operator === "||") { 41 | const leftTruthy = left.evaluateTruthy(); 42 | if (leftTruthy === false && left.isPure()) { 43 | path.replaceWith(node.right); 44 | } else if (leftTruthy === true) { 45 | // Short-circuit 46 | path.replaceWith(node.left); 47 | } else if (right.evaluateTruthy() === false && right.isPure() && !shouldBail) { 48 | path.replaceWith(node.left); 49 | } 50 | } 51 | }, 52 | 53 | function (path) { 54 | const { node } = path; 55 | 56 | if (flipExpressions.hasSeen(node)) { 57 | return; 58 | } 59 | 60 | if (!path.parentPath.isExpressionStatement() && 61 | !(path.parentPath.isSequenceExpression() && path.parentPath.parentPath.isExpressionStatement()) 62 | ) { 63 | return; 64 | } 65 | 66 | // Start counting savings from one since we can ignore the last 67 | // expression. 68 | if (flipExpressions.shouldFlip(node, 1)) { 69 | const newNode = flipExpressions.flip(node, true); 70 | path.replaceWith(newNode); 71 | } 72 | }, 73 | ], 74 | }, 75 | }, 76 | }; 77 | }; 78 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-inline-consecutive-adds/src/array-property-collapser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Collapser = require("./collapser"); 4 | 5 | class ArrayPropertyCollapser extends Collapser { 6 | isInitTypeValid(init) { 7 | return init.isArrayExpression(); 8 | } 9 | 10 | isExpressionTypeValid(expr) { 11 | return expr.isAssignmentExpression(); 12 | } 13 | 14 | getExpressionChecker(objName, checkReference) { 15 | return (expr) => { 16 | // checks expr is of form: 17 | // foo[num] = rval 18 | 19 | const left = expr.get("left"); 20 | 21 | if (!left.isMemberExpression()) { 22 | return false; 23 | } 24 | 25 | const obj = left.get("object"), prop = left.get("property"); 26 | if (!obj.isIdentifier() || 27 | obj.node.name !== objName) { 28 | return false; 29 | } 30 | 31 | const checkIndex = (num) => Number.isInteger(num) && num >= 0; 32 | 33 | if (!(prop.isNumericLiteral() || prop.isStringLiteral()) || 34 | !checkIndex(Number(prop.node.value))) { 35 | return false; 36 | } 37 | 38 | const right = expr.get("right"); 39 | if (checkReference(right)) { 40 | return false; 41 | } 42 | 43 | return true; 44 | }; 45 | } 46 | 47 | extractAssignment(expr) { 48 | return [expr.node.left.property.value, expr.get("right")]; 49 | } 50 | 51 | addSuccessfully(t, [index, rval], init) { 52 | const elements = init.elements; 53 | for (let i = elements.length; i <= index; i++) { 54 | elements.push(null); 55 | } 56 | if (elements[index] !== null) { 57 | return false; 58 | } 59 | elements[index] = rval.node; 60 | return true; 61 | } 62 | 63 | isSizeSmaller({ newInit, oldInit, varDecl, assignments, statements }) { 64 | const anyUndefined = (args) => args.some((a) => a === undefined); 65 | 66 | // We make an inexact calculation of how much space we save. 67 | // It's inexact because we don't know how whitespaces will get minimized, 68 | // and other factors. 69 | if (anyUndefined([statements[statements.length - 1].node.end, varDecl.node.end])) { 70 | return false; 71 | } 72 | const statementsLength = statements[statements.length - 1].node.end - varDecl.node.end; 73 | 74 | // Approx. formula of the change in `init`'s length = 75 | // (# commas added) + (size of all the new rvals added), where 76 | // # commas added = (difference between the lengths of the old and new arrays) 77 | 78 | const numCommaAdded = newInit.elements.length - oldInit.elements.length; 79 | if (anyUndefined(assignments.map(([, rval]) => rval.node.end)) || 80 | anyUndefined(assignments.map(([, rval]) => rval.node.start))) { 81 | return false; 82 | } 83 | const sizeOfRvals = assignments.map(([, rval]) => rval.node.end - rval.node.start + 1) // add 1 for space in front 84 | .reduce((a, b) => a + b, 0); // sum 85 | 86 | return (numCommaAdded + sizeOfRvals < statementsLength); 87 | } 88 | } 89 | 90 | module.exports = ArrayPropertyCollapser; 91 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-merge-sibling-variables/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function({ types: t }) { 4 | 5 | function liftDeclaration(path, body, kind) { 6 | if (body[0] && body[0].isVariableDeclaration({ kind: kind })) { 7 | 8 | if (body[0].node.declarations.length > 1) { 9 | return; 10 | } 11 | 12 | if (body[1] && body[1].isVariableDeclaration({ kind: kind })) { 13 | return; 14 | } 15 | 16 | const firstNode = body[0].node.declarations[0]; 17 | 18 | if (!t.isIdentifier(firstNode.id) || !firstNode.init) { 19 | return; 20 | } 21 | 22 | const init = path.get("init"); 23 | if (!init.isVariableDeclaration({ kind: kind })) { 24 | return; 25 | } 26 | 27 | init.pushContainer("declarations", t.variableDeclarator(firstNode.id)); 28 | 29 | body[0].replaceWith(t.assignmentExpression( 30 | "=", 31 | t.clone(firstNode.id), 32 | t.clone(firstNode.init) 33 | )); 34 | } 35 | } 36 | 37 | return { 38 | name: "transform-merge-sibling-variables", 39 | visitor: { 40 | ForStatement(path) { 41 | 42 | // Lift declarations to the loop initializer 43 | let body = path.get("body"); 44 | body = body.isBlockStatement() ? body.get("body") : [ body ]; 45 | 46 | liftDeclaration(path, body, "var"); 47 | liftDeclaration(path, body, "let"); 48 | }, 49 | VariableDeclaration: { 50 | enter: [ 51 | // concat variables of the same kind with their siblings 52 | function (path) { 53 | if (!path.inList) { 54 | return; 55 | } 56 | 57 | const { node } = path; 58 | 59 | while (true) { 60 | const sibling = path.getSibling(path.key + 1); 61 | if (!sibling.isVariableDeclaration({ kind: node.kind })) { 62 | break; 63 | } 64 | 65 | node.declarations = node.declarations.concat(sibling.node.declarations); 66 | sibling.remove(); 67 | } 68 | }, 69 | 70 | // concat `var` declarations next to for loops with it's initialisers. 71 | // block-scoped `let` and `const` are not moved because the for loop 72 | // is a different block scope. 73 | function (path) { 74 | if (!path.inList) { 75 | return; 76 | } 77 | 78 | const { node } = path; 79 | if (node.kind !== "var") { 80 | return; 81 | } 82 | 83 | const next = path.getSibling(path.key + 1); 84 | if (!next.isForStatement()) { 85 | return; 86 | } 87 | 88 | const init = next.get("init"); 89 | if (!init.isVariableDeclaration({ kind: node.kind })) { 90 | return; 91 | } 92 | 93 | init.node.declarations = node.declarations.concat( 94 | init.node.declarations 95 | ); 96 | path.remove(); 97 | }, 98 | ], 99 | }, 100 | }, 101 | }; 102 | }; 103 | -------------------------------------------------------------------------------- /packages/babel-helper-to-multiple-sequence-expressions/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function(t) { 4 | return function toMultipleSequenceExpressions(statements) { 5 | const retStatements = []; 6 | let bailed; 7 | do { 8 | const res = convert(statements); 9 | bailed = res.bailed; 10 | const {seq, bailedAtIndex} = res; 11 | if (seq) { 12 | retStatements.push(t.expressionStatement(seq)); 13 | } 14 | if (bailed && statements[bailedAtIndex]) { 15 | retStatements.push(statements[bailedAtIndex]); 16 | } 17 | if (bailed) { 18 | statements = statements.slice(bailedAtIndex + 1); 19 | if (!statements.length) { 20 | bailed = false; 21 | } 22 | } 23 | } while (bailed); 24 | 25 | return retStatements; 26 | 27 | function convert(nodes) { 28 | const exprs = []; 29 | 30 | for (let i = 0; i < nodes.length; i++) { 31 | const bail = () => { 32 | let seq; 33 | if (exprs.length === 1) { 34 | seq = exprs[0]; 35 | } else if (exprs.length) { 36 | seq = t.sequenceExpression(exprs); 37 | } 38 | 39 | return { 40 | seq, 41 | bailed: true, 42 | bailedAtIndex: i, 43 | }; 44 | }; 45 | 46 | const node = nodes[i]; 47 | if (t.isExpression(node)) { 48 | exprs.push(node); 49 | } else if (t.isExpressionStatement(node)) { 50 | exprs.push(node.expression); 51 | } else if (t.isIfStatement(node)) { 52 | let consequent; 53 | if (node.consequent) { 54 | const res = convert([node.consequent]); 55 | if (res.bailed) { 56 | return bail(); 57 | } 58 | consequent = res.seq; 59 | } 60 | let alternate; 61 | if (node.alternate) { 62 | const res = convert([node.alternate]); 63 | if (res.bailed) { 64 | return bail(); 65 | } 66 | alternate = res.seq; 67 | } 68 | 69 | if (!alternate && !consequent) { 70 | exprs.push(node.test); 71 | } else if (!alternate) { 72 | exprs.push(t.logicalExpression("&&", node.test, consequent)); 73 | } else if (!consequent) { 74 | exprs.push(t.logicalExpression("||", node.test, alternate)); 75 | } else { 76 | exprs.push(t.conditionalExpression(node.test, consequent, alternate)); 77 | } 78 | } else if (t.isBlockStatement(node)) { 79 | const res = convert(node.body); 80 | if (res.bailed) { 81 | return bail(); 82 | } 83 | if (res.seq) { 84 | exprs.push(res.seq); 85 | } 86 | } else { 87 | return bail(); 88 | } 89 | } 90 | 91 | let seq; 92 | if (exprs.length === 1) { 93 | seq = exprs[0]; 94 | } else if (exprs.length) { 95 | seq = t.sequenceExpression(exprs); 96 | } 97 | 98 | /* eslint-disable no-self-assign */ 99 | seq = seq; 100 | return { seq }; 101 | } 102 | }; 103 | }; 104 | -------------------------------------------------------------------------------- /packages/babel-preset-babili/__tests__/options-tests.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const mocks = [ 4 | "babel-plugin-minify-builtins", 5 | "babel-plugin-minify-constant-folding", 6 | "babel-plugin-minify-dead-code-elimination", 7 | "babel-plugin-minify-flip-comparisons", 8 | "babel-plugin-minify-guarded-expressions", 9 | "babel-plugin-minify-infinity", 10 | "babel-plugin-minify-mangle-names", 11 | "babel-plugin-minify-numeric-literals", 12 | "babel-plugin-minify-replace", 13 | "babel-plugin-minify-simplify", 14 | "babel-plugin-minify-type-constructors", 15 | "babel-plugin-transform-inline-consecutive-adds", 16 | "babel-plugin-transform-member-expression-literals", 17 | "babel-plugin-transform-merge-sibling-variables", 18 | "babel-plugin-transform-minify-booleans", 19 | "babel-plugin-transform-property-literals", 20 | "babel-plugin-transform-regexp-constructors", 21 | "babel-plugin-transform-remove-console", 22 | "babel-plugin-transform-remove-debugger", 23 | "babel-plugin-transform-remove-undefined", 24 | "babel-plugin-transform-simplify-comparison-operators", 25 | "babel-plugin-transform-undefined-to-void" 26 | ]; 27 | 28 | mocks.forEach((mockName) => { 29 | // it's called mockName for jest(babel-jest-plugin) workaround 30 | jest.mock(mockName, () => mockName); 31 | }); 32 | 33 | const preset = require("../src/index"); 34 | 35 | function getPlugins(opts) { 36 | return preset({}, opts).presets[0].plugins; 37 | } 38 | 39 | function testOpts(opts) { 40 | expect({ 41 | input: opts, 42 | output: getPlugins(opts) 43 | }).toMatchSnapshot(); 44 | } 45 | 46 | describe("preset-options", () => { 47 | it("should be a function", () => { 48 | expect(typeof preset).toBe("function"); 49 | }); 50 | 51 | it("should return defaults with no options", () => { 52 | expect(getPlugins()).toMatchSnapshot(); 53 | expect(getPlugins({})).toMatchSnapshot(); 54 | expect(getPlugins(null)).toMatchSnapshot(); 55 | }); 56 | 57 | it("should handle simple options", () => { 58 | testOpts({ 59 | mangle: false, 60 | deadcode: false 61 | }); 62 | }); 63 | 64 | it("should pass options to respective plugin when its an object", () => { 65 | testOpts({ 66 | mangle: { 67 | blacklist: ["foo", "bar"] 68 | } 69 | }); 70 | }); 71 | 72 | it("should handle groups - remove entire group", () => { 73 | testOpts({ 74 | unsafe: false 75 | }); 76 | }); 77 | 78 | it("should handle individual items in a group of options", () => { 79 | testOpts({ 80 | unsafe: { 81 | flipComparisons: false 82 | }, 83 | mangle: false 84 | }); 85 | }); 86 | 87 | it("should handle options that are delegated to multiple other options", () => { 88 | testOpts({ 89 | keepFnName: false, 90 | keepClassName: false 91 | }); 92 | testOpts({ 93 | keepFnName: true, 94 | keepClassName: true, 95 | mangle: { 96 | blacklist: ["foo", "bar"] 97 | } 98 | }); 99 | testOpts({ 100 | keepFnName: true, 101 | keepClassName: true, 102 | mangle: { 103 | blacklist: ["baz"], 104 | keepFnName: false, 105 | keepClassName: false, 106 | } 107 | }); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-guarded-expressions/__tests__/guarded-expressions-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("guarded-expressions-plugin", () => { 14 | it("should flip logical expressions", () => { 15 | const source = unpad(` 16 | !x && foo(); 17 | `); 18 | 19 | const expected = unpad(` 20 | x || foo(); 21 | `); 22 | 23 | expect(transform(source).trim()).toBe(expected.trim()); 24 | }); 25 | 26 | it("should simplify falsy logical expressions", function() { 27 | let source = unpad(` 28 | alert(0 && new Foo()); 29 | `); 30 | let expected = unpad(` 31 | alert(0); 32 | `); 33 | expect(transform(source)).toBe(expected); 34 | 35 | source = unpad(` 36 | if (0 && something()) for(;;); 37 | `); 38 | expected = unpad(` 39 | if (0) for (;;); 40 | `); 41 | expect(transform(source)).toBe(expected); 42 | 43 | source = unpad(` 44 | alert(false && new Foo()); 45 | `); 46 | expected = unpad(` 47 | alert(false); 48 | `); 49 | expect(transform(source)).toBe(expected); 50 | 51 | source = unpad(` 52 | alert(undefined && new Foo()); 53 | `); 54 | expected = unpad(` 55 | alert(undefined); 56 | `); 57 | expect(transform(source)).toBe(expected); 58 | 59 | source = unpad(` 60 | alert(null && new Foo()); 61 | `); 62 | expected = unpad(` 63 | alert(null); 64 | `); 65 | expect(transform(source)).toBe(expected); 66 | 67 | source = unpad(` 68 | alert("" && new Foo()); 69 | `); 70 | expected = unpad(` 71 | alert(""); 72 | `); 73 | expect(transform(source)).toBe(expected); 74 | 75 | source = unpad(` 76 | alert(new Foo() || false); 77 | `); 78 | expected = unpad(` 79 | alert(new Foo() || false); 80 | `); 81 | expect(transform(source)).toBe(expected); 82 | }); 83 | 84 | it("should simplify truthy expressions", () => { 85 | let source = unpad(` 86 | alert(1 && new Bar()); 87 | `); 88 | let expected = unpad(` 89 | alert(new Bar()); 90 | `); 91 | expect(transform(source)).toBe(expected); 92 | 93 | source = unpad(` 94 | alert(true && new Bar()); 95 | `); 96 | expected = unpad(` 97 | alert(new Bar()); 98 | `); 99 | expect(transform(source)).toBe(expected); 100 | 101 | source = unpad(` 102 | alert("hello" && new Bar()); 103 | `); 104 | expected = unpad(` 105 | alert(new Bar()); 106 | `); 107 | expect(transform(source)).toBe(expected); 108 | 109 | source = unpad(` 110 | alert(!false && new Bar()); 111 | `); 112 | expected = unpad(` 113 | alert(new Bar()); 114 | `); 115 | expect(transform(source)).toBe(expected); 116 | }); 117 | 118 | it("should not remove reachable impure statements", () => { 119 | let source = unpad(` 120 | a && void alert('Side effect'); 121 | `); 122 | expect(transform(source)).toBe(source); 123 | 124 | source = unpad(` 125 | alert(func() || true); 126 | `); 127 | expect(transform(source)).toBe(source); 128 | }); 129 | }); 130 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-regexp-constructors/__tests__/transform-regexp-constructors-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | 6 | function transform(code) { 7 | return babel.transform(code, { 8 | plugins: [plugin], 9 | }).code; 10 | } 11 | 12 | describe("transform-regexp-constructors-plugin", () => { 13 | it("should not duplicate forward-slash escapes", () => { 14 | const source = String.raw`var x = new RegExp('\\/');`; 15 | const expected = String.raw`var x = /\//;`; 16 | expect(transform(source)).toBe(expected); 17 | }); 18 | 19 | it("should transform newlines fine", () => { 20 | const source = String.raw`var x = new RegExp('\\n');`; 21 | const expected = String.raw`var x = /\n/;`; 22 | expect(transform(source)).toBe(expected); 23 | }); 24 | 25 | it("should transform unicode newlines fine", () => { 26 | const source = String.raw`var x = new RegExp('\u2028\u2029');`; 27 | const expected = String.raw`var x = /\u2028\u2029/;`; 28 | expect(transform(source)).toBe(expected); 29 | }); 30 | 31 | it("should transform RegExp constructors with string literals", () => { 32 | const source = "var x = new RegExp('ab+c');"; 33 | const expected = "var x = /ab+c/;"; 34 | expect(transform(source)).toBe(expected); 35 | }); 36 | 37 | it("should transform RegExp calls with string literals", () => { 38 | const source = "var x = RegExp('ab+c');"; 39 | const expected = "var x = /ab+c/;"; 40 | expect(transform(source)).toBe(expected); 41 | }); 42 | 43 | it("should transform RegExp constructors with flags", () => { 44 | const source = "var x = new RegExp('ab+c', 'gimuy');"; 45 | const expected = "var x = /ab+c/gimuy;"; 46 | expect(transform(source)).toBe(expected); 47 | }); 48 | 49 | it("should transform RegExp escapes", () => { 50 | const source = String.raw`var x = new RegExp('\\w+\\s');`; 51 | const expected = String.raw`var x = /\w+\s/;`; 52 | expect(transform(source)).toBe(expected); 53 | }); 54 | 55 | it("should not transform RegExp constructors with expressions", () => { 56 | const source = "var x = new RegExp(foo(), 'g');"; 57 | const expected = source; 58 | expect(transform(source)).toBe(expected); 59 | }); 60 | 61 | it("should transform empty RegExp constructor", () => { 62 | const source = "var x = new RegExp();"; 63 | const expected = "var x = /(?:)/;"; 64 | expect(transform(source)).toBe(expected); 65 | }); 66 | 67 | it("should transform RegExp constructor with empty string", () => { 68 | const source = "var x = new RegExp('');"; 69 | const expected = "var x = /(?:)/;"; 70 | expect(transform(source)).toBe(expected); 71 | }); 72 | 73 | it("should resolve expressions and const references", () => { 74 | const source = ` 75 | const foo = "ab+"; 76 | const bar = "c\\\\w"; 77 | const flags = "g"; 78 | const ret = new RegExp(foo + bar + "d", flags);`; 79 | const expected = ` 80 | const foo = "ab+"; 81 | const bar = "c\\\\w"; 82 | const flags = "g"; 83 | const ret = /ab+c\\wd/g;`; 84 | expect(transform(source)).toBe(expected); 85 | }); 86 | 87 | it("should prettify special whitespaces", () => { 88 | const source = String.raw`var x = new RegExp('\b\f\v\t\r\n\n');`; 89 | const expected = String.raw`var x = /[\b]\f\v \r\n\n/;`; 90 | expect(transform(source)).toBe(expected); 91 | }); 92 | 93 | it("should escape forward slashes", () => { 94 | const source = String.raw`var x = new RegExp('/x/');`; 95 | const expected = String.raw`var x = /\/x\//;`; 96 | expect(transform(source)).toBe(expected); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-replace/__tests__/replace-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const unpad = require("../../../utils/unpad"); 5 | 6 | function transform(code, replacements) { 7 | return babel.transform(code, { 8 | plugins: [ 9 | [require("../src/index"), {replacements}], 10 | ], 11 | }).code; 12 | } 13 | 14 | describe("replace-plugin", () => { 15 | it("should replace identifiers", () => { 16 | const replacements = [ 17 | { 18 | identifierName: "__DEV__", 19 | replacement: { 20 | type: "numericLiteral", 21 | value: 0, 22 | }, 23 | }, 24 | ]; 25 | 26 | const source = unpad(` 27 | if (__DEV__) { 28 | foo(); 29 | } 30 | if (!__DEV__) { 31 | foo(); 32 | } 33 | `); 34 | 35 | const expected = unpad(` 36 | if (0) { 37 | foo(); 38 | } 39 | if (!0) { 40 | foo(); 41 | } 42 | `); 43 | 44 | expect(transform(source, replacements)).toBe(expected); 45 | }); 46 | 47 | it("should only replace actual full identifiers", () => { 48 | const replacements = [ 49 | { 50 | identifierName: "__DEV__", 51 | replacement: { 52 | type: "numericLiteral", 53 | value: 0, 54 | }, 55 | }, 56 | ]; 57 | 58 | const source = unpad(` 59 | if (__DEV__) { 60 | foo(); 61 | } 62 | if (a.__DEV__) { 63 | foo(); 64 | } 65 | `); 66 | 67 | const expected = unpad(` 68 | if (0) { 69 | foo(); 70 | } 71 | if (a.__DEV__) { 72 | foo(); 73 | } 74 | `); 75 | 76 | expect(transform(source, replacements)).toBe(expected); 77 | }); 78 | 79 | it("should replace with boolean", () => { 80 | const replacements = [ 81 | { 82 | identifierName: "__DEV__", 83 | replacement: { 84 | type: "booleanLiteral", 85 | value: true, 86 | }, 87 | }, 88 | ]; 89 | 90 | const source = unpad(` 91 | if (__DEV__) { 92 | foo(); 93 | } 94 | `); 95 | 96 | const expected = unpad(` 97 | if (true) { 98 | foo(); 99 | } 100 | `); 101 | 102 | expect(transform(source, replacements)).toBe(expected); 103 | }); 104 | 105 | it("should replace member expressions", () => { 106 | const replacements = [ 107 | { 108 | identifierName: "console", 109 | member: "log", 110 | replacement: { 111 | type: "identifier", 112 | value: "emptyFunction", 113 | }, 114 | }, 115 | ]; 116 | 117 | const source = unpad(` 118 | console.log('wat'); 119 | (console.log)('wat'); 120 | `); 121 | 122 | const expected = unpad(` 123 | emptyFunction('wat'); 124 | emptyFunction('wat'); 125 | `); 126 | 127 | expect(transform(source, replacements)).toBe(expected); 128 | }); 129 | 130 | it("should replace multiple member expressions", () => { 131 | const replacements = [ 132 | { 133 | identifierName: "console", 134 | member: "log", 135 | replacement: { 136 | type: "identifier", 137 | value: "emptyFunction", 138 | }, 139 | }, 140 | { 141 | identifierName: "console", 142 | member: "error", 143 | replacement: { 144 | type: "identifier", 145 | value: "emptyFunction", 146 | }, 147 | }, 148 | ]; 149 | 150 | const source = unpad(` 151 | console.log('wat'); 152 | (console.log)('wat'); 153 | console.error('wat'); 154 | `); 155 | 156 | const expected = unpad(` 157 | emptyFunction('wat'); 158 | emptyFunction('wat'); 159 | emptyFunction('wat'); 160 | `); 161 | 162 | expect(transform(source, replacements)).toBe(expected); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-console/__tests__/remove-console-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("remove-console-plugin", () => { 14 | it("statement-nested", () => { 15 | const source = unpad(` 16 | function foo() { 17 | console.log("foo"); 18 | blah(); 19 | } 20 | `); 21 | 22 | const expected = unpad(` 23 | function foo() { 24 | blah(); 25 | } 26 | `); 27 | expect(transform(source)).toBe(expected); 28 | }); 29 | 30 | it("expression-nested", () => { 31 | const source = unpad(` 32 | function foo() { 33 | true && console.log("foo"); 34 | blah(); 35 | } 36 | `); 37 | 38 | const expected = unpad(` 39 | function foo() { 40 | true && void 0; 41 | blah(); 42 | } 43 | `); 44 | expect(transform(source)).toBe(expected); 45 | }); 46 | 47 | it("expression-top-level", () => { 48 | const source = unpad(` 49 | true && console.log("foo"); 50 | blah(); 51 | `); 52 | 53 | const expected = unpad(` 54 | true && void 0; 55 | blah(); 56 | `); 57 | expect(transform(source)).toBe(expected); 58 | }); 59 | 60 | it("statement-top-level", () => { 61 | const source = unpad(` 62 | console.log("foo"); 63 | blah(); 64 | `); 65 | 66 | const expected = unpad(` 67 | blah(); 68 | `); 69 | expect(transform(source).trim()).toBe(expected); 70 | }); 71 | 72 | it("statement no block", () => { 73 | const source = unpad(` 74 | if (blah) console.log(blah); 75 | for (;;) console.log(blah); 76 | for (var blah in []) console.log(blah); 77 | for (var blah of []) console.log(blah); 78 | while (blah) console.log(blah); 79 | do console.log(blah); while (blah); 80 | `); 81 | 82 | const expected = unpad(` 83 | if (blah) {} 84 | for (;;) {} 85 | for (var blah in []) {} 86 | for (var blah of []) {} 87 | while (blah) {} 88 | do {} while (blah); 89 | `); 90 | expect(transform(source).trim()).toBe(expected); 91 | }); 92 | 93 | it("should remove console.* assignments to other variables", () => { 94 | const source = unpad(` 95 | const a = console.log; 96 | a(); 97 | const b = console.log.bind(console); 98 | b("asdf"); 99 | var x = console.log ? console.log('log') : foo(); 100 | function foo() { 101 | if (console.error) { 102 | console.error("Errored"); 103 | } 104 | } 105 | console.log.call(console, "foo"); 106 | console.log.apply(null, {}); 107 | `); 108 | const expected = unpad(` 109 | const a = function () {}; 110 | a(); 111 | const b = function () {}; 112 | b("asdf"); 113 | var x = function () {} ? void 0 : foo(); 114 | function foo() { 115 | if (function () {}) {} 116 | } 117 | `); 118 | expect(transform(source)).toBe(expected); 119 | }); 120 | 121 | it("should NOT remove local bindings of name console", () => { 122 | const source = unpad(` 123 | function foo(console) { 124 | console.foo("hi"); 125 | const bar = console.foo.bind(console); 126 | } 127 | function bar(a) { 128 | const { console } = a; 129 | a.b = console => console.bar("bar"); 130 | if (console.foo.call(console, "bar")) { 131 | return; 132 | } 133 | } 134 | `); 135 | expect(transform(source)).toBe(source); 136 | }); 137 | 138 | it("should convert assigments to no-op", () => { 139 | const source = unpad(` 140 | function foo() { 141 | console.foo = function foo() { 142 | console.log("foo"); 143 | }; 144 | console.error = myConsoleError; 145 | console.foo(); 146 | console.error("asdf"); 147 | } 148 | `); 149 | const expected = unpad(` 150 | function foo() { 151 | console.foo = function () {}; 152 | console.error = function () {}; 153 | } 154 | `); 155 | expect(transform(source)).toBe(expected); 156 | }); 157 | }); 158 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-builtins/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const evaluate = require("babel-helper-evaluate-path"); 4 | // Assuming all the static methods from below array are side effect free evaluation 5 | // except Math.random 6 | const VALID_CALLEES = ["String", "Number", "Math"]; 7 | const INVALID_METHODS = ["random"]; 8 | 9 | module.exports = function({ types: t }) { 10 | 11 | class BuiltInReplacer { 12 | constructor(program) { 13 | this.program = program; 14 | this.pathsToUpdate = new Map; 15 | } 16 | 17 | run() { 18 | this.collect(); 19 | this.replace(); 20 | } 21 | 22 | collect() { 23 | const context = this; 24 | 25 | const collectVisitor = { 26 | MemberExpression(path) { 27 | if (path.parentPath.isCallExpression()) { 28 | return; 29 | } 30 | 31 | if (!isComputed(path) && isBuiltin(path)) { 32 | const expName = memberToString(path.node); 33 | 34 | if (!context.pathsToUpdate.has(expName)) { 35 | context.pathsToUpdate.set(expName, []); 36 | } 37 | context.pathsToUpdate.get(expName).push(path); 38 | } 39 | }, 40 | 41 | CallExpression: { 42 | exit(path) { 43 | const callee = path.get("callee"); 44 | if (!callee.isMemberExpression()) { 45 | return; 46 | } 47 | 48 | // computed property should be not optimized 49 | // Math[max]() -> Math.max() 50 | if (!isComputed(callee) && isBuiltin(callee)) { 51 | const result = evaluate(path); 52 | // deopt when we have side effecty evaluate-able arguments 53 | // Math.max(foo(), 1) --> untouched 54 | // Math.floor(1) --> 1 55 | if (result.confident && hasPureArgs(path)) { 56 | path.replaceWith(t.valueToNode(result.value)); 57 | } else { 58 | const expName = memberToString(callee.node); 59 | 60 | if (!context.pathsToUpdate.has(expName)) { 61 | context.pathsToUpdate.set(expName, []); 62 | } 63 | context.pathsToUpdate.get(expName).push(callee); 64 | } 65 | } 66 | } 67 | } 68 | }; 69 | 70 | this.program.traverse(collectVisitor); 71 | } 72 | 73 | replace() { 74 | for (const [ expName, paths ] of this.pathsToUpdate) { 75 | // Should only transform if there is more than 1 occurence 76 | if (paths.length > 1) { 77 | const uniqueIdentifier = this.program.scope.generateUidIdentifier(expName); 78 | const newNode = t.variableDeclaration("var", [ 79 | t.variableDeclarator(uniqueIdentifier, paths[0].node) 80 | ]); 81 | 82 | for (const path of paths) { 83 | path.replaceWith(uniqueIdentifier); 84 | } 85 | // hoist the created var to top of the program 86 | this.program.unshiftContainer("body", newNode); 87 | } 88 | } 89 | } 90 | } 91 | 92 | return { 93 | name: "minify-builtins", 94 | visitor: { 95 | Program(path) { 96 | const builtInReplacer = new BuiltInReplacer(path); 97 | builtInReplacer.run(); 98 | } 99 | }, 100 | }; 101 | 102 | function memberToString(memberExpr) { 103 | const { object, property } = memberExpr; 104 | let result = ""; 105 | 106 | if (t.isIdentifier(object)) result += object.name; 107 | if (t.isMemberExpression(object)) result += memberToString(object); 108 | if (t.isIdentifier(property)) result += property.name; 109 | 110 | return result; 111 | } 112 | 113 | function isBuiltin(memberExpr) { 114 | const { object, property } = memberExpr.node; 115 | 116 | if (t.isIdentifier(object) && t.isIdentifier(property) 117 | && VALID_CALLEES.indexOf(object.name) >= 0 118 | && INVALID_METHODS.indexOf(property.name) < 0) { 119 | return true; 120 | } 121 | return false; 122 | } 123 | 124 | }; 125 | 126 | function hasPureArgs(path) { 127 | const args = path.get("arguments"); 128 | for (const arg of args) { 129 | if (!arg.isPure()) { 130 | return false; 131 | } 132 | } 133 | return true; 134 | } 135 | 136 | function isComputed(path) { 137 | const { node } = path; 138 | return node.computed; 139 | } 140 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-constant-folding/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const evaluate = require("babel-helper-evaluate-path"); 4 | const jsesc = require("jsesc"); 5 | 6 | module.exports = ({ types: t, traverse }) => { 7 | const seen = Symbol("seen"); 8 | 9 | return { 10 | name: "minify-constant-folding", 11 | visitor: { 12 | 13 | // Evaluate string expressions that are next to each other 14 | // but are not actually a binary expression. 15 | // "a" + b + "c" + "d" -> "a" + b + "cd" 16 | BinaryExpression(path) { 17 | let literal, bin; 18 | if (path.get("right").isStringLiteral()) { 19 | literal = path.get("right"); 20 | if (path.get("left").isBinaryExpression({ operator: "+" })) { 21 | bin = path.get("left"); 22 | } else { 23 | return; 24 | } 25 | } else if (path.get("left").isStringLiteral()) { 26 | literal = path.get("left"); 27 | if (path.get("right").isBinaryExpression({ operator: "+" })) { 28 | bin = path.get("right"); 29 | } else { 30 | return; 31 | } 32 | } else { 33 | return; 34 | } 35 | 36 | const relevant = getLeaf(bin, literal.key); 37 | 38 | if (!relevant) { 39 | return; 40 | } 41 | 42 | const value = literal.key === "right" 43 | ? relevant.node.value + literal.node.value 44 | : literal.node.value + relevant.node.value; 45 | 46 | relevant.replaceWith(t.stringLiteral(value)); 47 | path.replaceWith(bin.node); 48 | 49 | function getLeaf(path, direction) { 50 | if (path.isStringLiteral()) { 51 | return path; 52 | } else if (path.isBinaryExpression({ operator: "+" })) { 53 | return getLeaf(path.get(direction), direction); 54 | } 55 | } 56 | }, 57 | 58 | // TODO: look into evaluating binding too (could result in more code, but gzip?) 59 | Expression(path) { 60 | const { node } = path; 61 | 62 | if (node[seen]) { 63 | return; 64 | } 65 | 66 | if (path.isLiteral()) { 67 | return; 68 | } 69 | 70 | if (!path.isPure()) { 71 | return; 72 | } 73 | 74 | if (traverse.hasType(node, path.scope, "Identifier", t.FUNCTION_TYPES)) { 75 | return; 76 | } 77 | 78 | // -0 maybe compared via dividing and then checking against -Infinity 79 | // Also -X will always be -X. 80 | if (t.isUnaryExpression(node, { operator: "-" }) && t.isNumericLiteral(node.argument)) { 81 | return; 82 | } 83 | 84 | // We have a transform that converts true/false to !0/!1 85 | if (t.isUnaryExpression(node, { operator: "!" }) && t.isNumericLiteral(node.argument)) { 86 | if (node.argument.value === 0 || node.argument.value === 1) { 87 | return; 88 | } 89 | } 90 | 91 | // void 0 is used for undefined. 92 | if (t.isUnaryExpression(node, { operator: "void" }) && 93 | t.isNumericLiteral(node.argument, { value: 0 }) 94 | ) { 95 | return; 96 | } 97 | 98 | const res = evaluate(path); 99 | if (res.confident) { 100 | // Avoid fractions because they can be longer than the original expression. 101 | // There is also issues with number percision? 102 | if (typeof res.value === "number" && !Number.isInteger(res.value)) { 103 | return; 104 | } 105 | 106 | // Preserve -0 107 | if (typeof res.value === "number" && res.value === 0) { 108 | if (1 / res.value === -Infinity) { 109 | const node = t.unaryExpression("-", t.numericLiteral(0), true); 110 | node[seen] = true; 111 | path.replaceWith(node); 112 | return; 113 | } 114 | } 115 | 116 | // https://github.com/babel/babili/issues/382 117 | if (typeof res.value === "string") { 118 | res.value = jsesc(res.value, { 119 | isScriptContext: true 120 | }); 121 | } 122 | 123 | const node = t.valueToNode(res.value); 124 | node[seen] = true; 125 | path.replaceWith(node); 126 | } 127 | }, 128 | }, 129 | }; 130 | }; 131 | -------------------------------------------------------------------------------- /scripts/plugin-contribution.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require("fs"); 4 | const path = require("path"); 5 | const {transform} = require("babel-core"); 6 | const Table = require("cli-table"); 7 | const zlib = require("zlib"); 8 | const chalk = require("chalk"); 9 | // const vm = require("vm"); 10 | 11 | run(process.argv[2]); 12 | 13 | function run(inputFile) { 14 | const input = fs.readFileSync(inputFile).toString(); 15 | const table = new Table(Object.assign({ 16 | head: [ 17 | "name", 18 | "output(bytes)", 19 | "output gzip(bytes)", 20 | "raw compression (%)", 21 | "gzip win (%)", 22 | "gzip % (%)", 23 | "parse time Δ (ms)" 24 | ], 25 | }, tableStyle())); 26 | 27 | const baseOutput = transform(input, { 28 | minified: true, 29 | compact: true, 30 | comments: false, 31 | }).code; 32 | 33 | const baseGzip = zlib.gzipSync(baseOutput); 34 | 35 | const baseParseTime = getParseTime(baseOutput); 36 | 37 | const plugins = getPlugins(); 38 | let current = 1; 39 | 40 | plugins.forEach(({name, plugin}) => { 41 | process.stdout.write(`Plugin ${current++}/${plugins.length}\r`); 42 | 43 | const output = transform(baseOutput, { 44 | plugins: [plugin], 45 | minified: true, 46 | compact: true, 47 | comments: false, 48 | }).code; 49 | 50 | const gzippedOutput = zlib.gzipSync(output); 51 | 52 | const parseTime = getParseTime(output); 53 | 54 | const percentage = (1 - len(output) / len(baseOutput)) * 100; 55 | const gzipWin = (1 - len(gzippedOutput) / len(baseGzip)) * 100; 56 | const gzipPercentage = (1 - len(gzippedOutput) / len(output)) * 100; 57 | 58 | const parseTimeDiff = baseParseTime - parseTime; 59 | 60 | table.push([ 61 | name.split("babel-plugin-")[1], 62 | len(output), 63 | len(gzippedOutput), 64 | percentage.toFixed(3), 65 | gzipWin < 0 ? chalk.red(gzipWin.toFixed(3)) : gzipWin.toFixed(3), 66 | gzipPercentage.toFixed(3), 67 | chalk[parseTimeDiff < 0 ? "green" : "red"](parseTimeDiff), 68 | ]); 69 | }); 70 | 71 | const wcWin = (1 - len(baseOutput) / len(input)) * 100; 72 | 73 | console.log(` 74 | input: input file with white space and comments removed 75 | 76 | input size (bytes) : ${len(baseOutput)} 77 | input gzip size (bytes) : ${len(baseGzip)} 78 | 79 | raw compression : % decrease from input -> output 80 | gzip win : % decrease from gzipInput -> gzipOutput 81 | gzip % : % decrease from output -> gzipOutput 82 | 83 | Whitespaces and comments win (raw compression): ${wcWin} 84 | `); 85 | 86 | console.log(table.toString()); 87 | } 88 | 89 | function getPlugins() { 90 | return fs.readdirSync(path.join(__dirname, "../packages")) 91 | .filter((dir) => { 92 | if (!isDir(path.join(__dirname, "../packages", dir))) return false; 93 | if (dir.indexOf("babel-plugin-") !== 0) return false; 94 | try { 95 | require(`../packages/${dir}`); 96 | return true; 97 | } catch (e) { 98 | return false; 99 | } 100 | }) 101 | .map((pluginName) => ({ 102 | name: pluginName, 103 | plugin: require(`../packages/${pluginName}`) 104 | })); 105 | } 106 | 107 | function getParseTime(code) { 108 | // const context = vm.createContext(); 109 | // const script = new vm.Script(code); 110 | 111 | const parseStart = process.hrtime(); 112 | new Function(code + ";void(" + Math.random() + ");"); 113 | // script.runInContext(context); 114 | const diff = process.hrtime(parseStart); 115 | return diff[1] / 1000000; 116 | } 117 | 118 | function isDir(p) { 119 | try { 120 | return fs.statSync(p).isDirectory(); 121 | } catch (e) { 122 | return false; 123 | } 124 | } 125 | 126 | function len(str) { 127 | return Buffer.byteLength(str, "utf-8"); 128 | } 129 | 130 | // just to keep it at the bottom 131 | function tableStyle() { 132 | return { 133 | chars: { 134 | top: "", 135 | "top-mid": "", 136 | "top-left": "", 137 | "top-right": "", 138 | bottom: "", 139 | "bottom-mid": "", 140 | "bottom-left": "", 141 | "bottom-right": "", 142 | left: "", 143 | "left-mid": "", 144 | mid: "", 145 | "mid-mid": "", 146 | right: "", 147 | "right-mid": "", 148 | middle: " ", 149 | }, 150 | style: { 151 | "padding-left": 0, 152 | "padding-right": 0, 153 | head: ["bold"], 154 | } 155 | }; 156 | } 157 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-merge-sibling-variables/__tests__/transform-merge-sibling-variables-test.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const babel = require("babel-core"); 4 | const plugin = require("../src/index"); 5 | const unpad = require("../../../utils/unpad"); 6 | 7 | function transform(code) { 8 | return babel.transform(code, { 9 | plugins: [plugin], 10 | }).code; 11 | } 12 | 13 | describe("transform-merge-sibling-variables-plugin", () => { 14 | it("concat vars", () => { 15 | const source = unpad(` 16 | var i = 0; 17 | var x = 0; 18 | var y = 0; 19 | `); 20 | const expected = unpad(` 21 | var i = 0, 22 | x = 0, 23 | y = 0; 24 | `); 25 | 26 | expect(transform(source)).toBe(expected); 27 | }); 28 | 29 | it("concat vars in for loops", () => { 30 | const source = unpad(` 31 | var i = 0; 32 | var j = 0; 33 | for (var x = 0; x < 10; x++) console.log(i + x); 34 | `); 35 | const expected = "for (var i = 0, j = 0, x = 0; x < 10; x++) console.log(i + x);"; 36 | 37 | expect(transform(source).trim()).toBe(expected); 38 | }); 39 | 40 | it("don't concat block-scoped variables in for loops", () => { 41 | const source = unpad(` 42 | let i = 0; 43 | for (let x = 0; x < 10; x++) console.log(i + x); 44 | `); 45 | 46 | expect(transform(source)).toBe(source); 47 | }); 48 | 49 | it("don't concat constants in for loops", () => { 50 | const source = unpad(` 51 | const j = 0; 52 | for (const x = 0;;) console.log(j + x); 53 | `); 54 | 55 | expect(transform(source)).toBe(source); 56 | }); 57 | 58 | it("concat block-scoped vars next to, but not into for loops", () => { 59 | const source = unpad(` 60 | let i = 0; 61 | let y = 0; 62 | for (let x = 0; x < 10; x++) console.log(i + x); 63 | `); 64 | const expected = unpad(` 65 | let i = 0, 66 | y = 0; 67 | 68 | for (let x = 0; x < 10; x++) console.log(i + x); 69 | `); 70 | 71 | expect(transform(source)).toBe(expected); 72 | }); 73 | 74 | it("lift var declarations to loop intializer", () => { 75 | const source = unpad(` 76 | for (var i = 0; i < 0; i++) { 77 | var j = jj(); 78 | } 79 | for (var i=0;;) var j = 0; 80 | `); 81 | const expected = unpad(` 82 | for (var i = 0, j; i < 0; i++) { 83 | j = jj(); 84 | } 85 | for (var i = 0, j;;) j = 0; 86 | `); 87 | 88 | expect(transform(source)).toBe(expected); 89 | }); 90 | 91 | it("lift let declarations to loop intializer", () => { 92 | const source = unpad(` 93 | for (let i = 0; i < 0; i++) { 94 | let j = jj(); 95 | } 96 | `); 97 | const expected = unpad(` 98 | for (let i = 0, j; i < 0; i++) { 99 | j = jj(); 100 | } 101 | `); 102 | 103 | expect(transform(source)).toBe(expected); 104 | }); 105 | 106 | it("dont lift declarations on object/array pattern", () => { 107 | const source = unpad(` 108 | for (var i = 0; i < 0; i++) { 109 | var [j] = jj(); 110 | } 111 | for (var i = 0; i < 0; i++) { 112 | var { j } = jj(); 113 | } 114 | `); 115 | 116 | expect(transform(source)).toBe(source); 117 | }); 118 | 119 | it("dont lift declarations when no body is present", () => { 120 | const source = unpad(` 121 | for (;;) {} 122 | for (;;) var i = 0; 123 | `); 124 | 125 | expect(transform(source)).toBe(source); 126 | }); 127 | 128 | it("dont lift when the declarations are of different kind", () => { 129 | const source = unpad(` 130 | for (let i = 0; i < 0; i++) { 131 | var i = 0; 132 | } 133 | `); 134 | 135 | expect(transform(source)).toBe(source); 136 | }); 137 | 138 | it("dont lift when the declarations are not initialized", () => { 139 | const source = unpad(` 140 | for (var i = 0;;) { 141 | var i; 142 | } 143 | `); 144 | 145 | expect(transform(source)).toBe(source); 146 | }); 147 | 148 | it("dont lift when there are multiple declarations", () => { 149 | const source = unpad(` 150 | for (var i = 0; i < 0; i++) { 151 | var i = 0, k = 0; 152 | } 153 | `); 154 | 155 | const expected = unpad(` 156 | for (var i = 0; i < 0; i++) { 157 | var i = 0, 158 | k = 0; 159 | } 160 | `); 161 | 162 | expect(transform(source)).toBe(expected); 163 | }); 164 | 165 | }); 166 | -------------------------------------------------------------------------------- /packages/babel-plugin-transform-remove-undefined/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function isPureAndUndefined(rval, scope = { hasBinding: () => false }) { 4 | 5 | if (rval.isIdentifier() && rval.node.name === "undefined") { 6 | // deopt right away if undefined is a local binding 7 | if (scope.hasBinding(rval.node.name, true /* no globals */)) { 8 | return false; 9 | } 10 | return true; 11 | } 12 | 13 | if (!rval.isPure()) { 14 | return false; 15 | } 16 | const evaluation = rval.evaluate(); 17 | return evaluation.confident === true && evaluation.value === undefined; 18 | } 19 | 20 | function getLoopParent(path, scopeParent) { 21 | const parent = path.findParent((p) => p.isLoop() || p === scopeParent); 22 | // don't traverse higher than the function the var is defined in. 23 | return parent === scopeParent ? null : parent; 24 | } 25 | 26 | function getFunctionParent(path, scopeParent) { 27 | const parent = path.findParent((p) => p.isFunction()); 28 | // don't traverse higher than the function the var is defined in. 29 | return parent === scopeParent ? null : parent; 30 | } 31 | 32 | function getFunctionReferences(path, scopeParent, references = new Set()) { 33 | for (let func = getFunctionParent(path, scopeParent); func; func = getFunctionParent(func, scopeParent)) { 34 | const id = func.node.id; 35 | const binding = id && func.scope.getBinding(id.name); 36 | 37 | if (!binding) { 38 | continue; 39 | } 40 | 41 | binding.referencePaths.forEach((path) => { 42 | if (!references.has(path)) { 43 | references.add(path); 44 | getFunctionReferences(path, scopeParent, references); 45 | } 46 | }); 47 | } 48 | return references; 49 | } 50 | 51 | function hasViolation(declarator, scope, start) { 52 | const binding = scope.getBinding(declarator.node.id.name); 53 | if (!binding) { 54 | return true; 55 | } 56 | 57 | const scopeParent = declarator.getFunctionParent(); 58 | 59 | const violation = binding.constantViolations.some((v) => { 60 | // return 'true' if we cannot guarantee the violation references 61 | // the initialized identifier after 62 | const violationStart = v.node.start; 63 | if (violationStart === undefined || violationStart < start) { 64 | return true; 65 | } 66 | 67 | const references = getFunctionReferences(v, scopeParent); 68 | for (const ref of references) { 69 | if (ref.node.start === undefined || ref.node.start < start) { 70 | return true; 71 | } 72 | } 73 | 74 | for (let loop = getLoopParent(declarator, scopeParent); loop; loop = getLoopParent(loop, scopeParent)) { 75 | if (loop.node.end === undefined || loop.node.end > violationStart) { 76 | return true; 77 | } 78 | } 79 | }); 80 | 81 | return violation; 82 | } 83 | 84 | module.exports = function() { 85 | return { 86 | name: "transform-remove-undefined", 87 | visitor: { 88 | SequenceExpression(path) { 89 | const expressions = path.get("expressions"); 90 | 91 | for (let i = 0; i < expressions.length; i++) { 92 | const expr = expressions[i]; 93 | if (!isPureAndUndefined(expr, path.scope)) continue; 94 | 95 | // last value 96 | if (i === expressions.length - 1) { 97 | if (path.parentPath.isExpressionStatement()) { 98 | expr.remove(); 99 | } 100 | } else { 101 | expr.remove(); 102 | } 103 | } 104 | }, 105 | 106 | ReturnStatement(path) { 107 | if (path.node.argument !== null) { 108 | if (isPureAndUndefined(path.get("argument"), path.scope)) { 109 | path.node.argument = null; 110 | } 111 | } 112 | }, 113 | 114 | VariableDeclaration(path) { 115 | switch (path.node.kind) { 116 | case "const": 117 | break; 118 | case "let": 119 | for (const declarator of path.get("declarations")) { 120 | if (isPureAndUndefined(declarator.get("init"))) { 121 | declarator.node.init = null; 122 | } 123 | } 124 | break; 125 | case "var": 126 | const start = path.node.start; 127 | if (start === undefined) { 128 | // This is common for plugin-generated nodes 129 | break; 130 | } 131 | const scope = path.scope; 132 | for (const declarator of path.get("declarations")) { 133 | if (isPureAndUndefined(declarator.get("init")) && 134 | !hasViolation(declarator, scope, start)) { 135 | declarator.node.init = null; 136 | } 137 | } 138 | break; 139 | } 140 | }, 141 | }, 142 | }; 143 | }; 144 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | ### Setup 4 | ```sh 5 | $ git clone https://github.com/babel/babili 6 | $ cd babili 7 | $ npm install 8 | $ npm run bootstrap 9 | ``` 10 | 11 | Then you can either run: 12 | 13 | ```sh 14 | $ npm run build 15 | ``` 16 | 17 | to build Babel **once** or: 18 | 19 | ```sh 20 | $ npm run watch 21 | ``` 22 | 23 | to have Babel build itself then incrementally build files on change. 24 | 25 | To run tests: 26 | 27 | ```sh 28 | $ npm test 29 | ``` 30 | 31 | To run lint: 32 | 33 | ```sh 34 | $ npm run lint 35 | ``` 36 | 37 | To run lint autofixes: 38 | 39 | ```sh 40 | $ npm run fix 41 | ``` 42 | 43 | To run current benchmarks on a file: 44 | 45 | ```sh 46 | $ ./scripts/benchmark.js package [file.js] 47 | # do not remove package after installing to node_modules 48 | $ ./scripts/benchmark.js package [file.js] --offline 49 | ``` 50 | 51 | To run current plugin timing on a file: 52 | 53 | ```sh 54 | $ ./scripts/plugin-timing.js file.js 55 | ``` 56 | 57 | ### Debugging 58 | 59 | In your project, if you find that there is a bug that appears ONLY when you use Babili, it's most likely that there is a bug in Babili and you should definitely report it. Here are some guidelines that might help you drill down the issue. If it doesn't help you, you can of course create a minimal repro project with the bug and report it. 60 | 61 | #### Compile time Errors 62 | 63 | If you get a syntax error at compile time, then it could be a few things: 64 | 65 | 1. The parser itself doesn't handle the syntax being used (a [babylon](https://github.com/babel/babylon) bug). 66 | 2. The code is actually invalid syntax. 67 | 3. You didn't turn on the relevant Babel plugin for that syntax (if experimental). 68 | 69 | If the syntax error occurs at runtime, it likely means the code generator ([babel-generator](https://github.com/babel/babel/tree/master/packages/babel-generator)) has a bug and has output invalid code. 70 | 71 | #### Runtime errors 72 | 73 | When you run your minified code in the browser, 74 | 75 | 1. If there is an error in the console, as a first step, look around the code block where the error happens, and the code block of a few steps up in the stack. 76 | 2. Try to predict what caused the error and try relating it to some of the plugin names in the [packages/](packages) directory. The major ones (that do a lot of transformations) are - mangle, deadcode-elimination and simplify. 77 | 3. Every plugin that Babili uses has an option in preset to toggle it on/off - [preset-options](packages/babel-preset-babili#options) 78 | 4. Disable any transformation(s) that you suspect are causing problems. Turning OFF mangling (`mangle: false`) is a good practice if you don't think it's related to a mangling bug, since unmangled variable names will make debugging easier. 79 | 5. Sometimes it might NOT be a bug with one plugin but a combination of plugins. Again, `deadcode-elimination` and `simplify` maybe good candidates to start with here as they perform many transformations. 80 | 6. Sometimes it might because of the [unsafe transformations](packages/babel-preset-babili#option-groups). Some of them are grouped into a single option named `unsafe`. This option can help you identify it sooner if the bug is in one these plugins. 81 | 7. Produce a minimal repro of the same issue - the function block containing the bug should be enough to help reproduce the bug. 82 | 8. [Report it 🙂](https://github.com/babel/babili/issues/new) 83 | 9. You're awesome. Thanks! 84 | 85 | ##### Mangler bugs 86 | 87 | This should be the easy one. If there is an error thrown in the console, 88 | 89 | 1. In the devtools find the variable that's mismatched (Usually it is the one that's in the Error message. If you have try..catch, add breakpoints in the try block and get the variable name that's faulty). 90 | 2. In current Babili, there is no variable reuse (Fix in [#284](https://github.com/babel/babili/pull/284)). So, every variable that you see is declared ONLY ONCE (except `var`s which can be declared mutiple times, but all those will still be in one function block). So it should be pretty easy to find that one declaration in your code. 91 | 3. Usually, the containing function should help you reproduce the same error. 92 | 4. [Report it 🙂](https://github.com/babel/babili/issues/new) 93 | 5. You're awesome. Thanks! 94 | 95 | ### Releasing 96 | 97 | > If you are releasing a new package, you'll want to run `./scripts/npm-owner-update.sh` to add all owners to the new npm package after releasing. Or do it manually via `https://www.npmjs.com/package/package-name-here/access`. 98 | 99 | If you need to update deps run `npm run clean` and then `npm run bootstrap`. 100 | 101 | To get the changelog, run `npm run changelog` to print to the terminal. 102 | 103 | Use `npm run publish`. It will run `lerna publish` (we use `--independent`) so it will prompt the version number for every package. 104 | -------------------------------------------------------------------------------- /packages/babel-preset-babili/src/index.js: -------------------------------------------------------------------------------- 1 | const isPlainObject = require("lodash.isplainobject"); 2 | const {group, option, proxy, generate} = require("./options-manager"); 3 | 4 | // the flat plugin map 5 | // This is to prevent dynamic requires - require('babel-plugin-' + name); 6 | // as it suffers during bundling of this code with webpack/browserify 7 | const PLUGINS = [ 8 | ["booleans", require("babel-plugin-transform-minify-booleans"), true], 9 | ["consecutiveAdds", require("babel-plugin-transform-inline-consecutive-adds"), true], 10 | ["deadcode", require("babel-plugin-minify-dead-code-elimination"), true], 11 | ["evaluate", require("babel-plugin-minify-constant-folding"), true], 12 | ["flipComparisons", require("babel-plugin-minify-flip-comparisons"), true], 13 | ["guards", require("babel-plugin-minify-guarded-expressions"), true], 14 | ["infinity", require("babel-plugin-minify-infinity"), true], 15 | ["mangle", require("babel-plugin-minify-mangle-names"), true], 16 | ["memberExpressions", require("babel-plugin-transform-member-expression-literals"), true], 17 | ["mergeVars", require("babel-plugin-transform-merge-sibling-variables"), true], 18 | ["numericLiterals", require("babel-plugin-minify-numeric-literals"), true], 19 | ["propertyLiterals", require("babel-plugin-transform-property-literals"), true], 20 | ["regexpConstructors", require("babel-plugin-transform-regexp-constructors"), true], 21 | ["removeConsole", require("babel-plugin-transform-remove-console"), false], 22 | ["removeDebugger", require("babel-plugin-transform-remove-debugger"), false], 23 | ["removeUndefined", require("babel-plugin-transform-remove-undefined"), true], 24 | ["replace", require("babel-plugin-minify-replace"), true], 25 | ["simplify", require("babel-plugin-minify-simplify"), true], 26 | ["simplifyComparisons", require("babel-plugin-transform-simplify-comparison-operators"), true], 27 | ["typeConstructors", require("babel-plugin-minify-type-constructors"), true], 28 | ["undefinedToVoid", require("babel-plugin-transform-undefined-to-void"), true], 29 | ["builtIns", require("babel-plugin-minify-builtins"), true], 30 | ]; 31 | 32 | module.exports = preset; 33 | 34 | function preset(context, _opts = {}) { 35 | const opts = isPlainObject(_opts) ? _opts : {}; 36 | 37 | // to track every plugin is used 38 | const usedPlugins = new Set; 39 | 40 | const optionsMap = PLUGINS 41 | .map((plugin) => option(plugin[0], plugin[1], plugin[2])) 42 | .reduce((acc, cur) => { 43 | Object.defineProperty(acc, cur.name, { 44 | get() { 45 | usedPlugins.add(cur.name); 46 | return cur; 47 | } 48 | }); 49 | return acc; 50 | }, {}); 51 | 52 | const optionsTree = group( 53 | "options", 54 | [ 55 | optionsMap.evaluate, 56 | optionsMap.deadcode, 57 | 58 | group("unsafe", [ 59 | optionsMap.flipComparisons, 60 | optionsMap.simplifyComparisons, 61 | optionsMap.guards, 62 | optionsMap.typeConstructors, 63 | ]), 64 | 65 | optionsMap.infinity, 66 | optionsMap.mangle, 67 | optionsMap.numericLiterals, 68 | optionsMap.replace, 69 | optionsMap.simplify, 70 | optionsMap.builtIns, 71 | 72 | group("properties", [ 73 | optionsMap.consecutiveAdds, 74 | optionsMap.memberExpressions, 75 | optionsMap.propertyLiterals, 76 | ]), 77 | 78 | optionsMap.mergeVars, 79 | optionsMap.booleans, 80 | optionsMap.undefinedToVoid, 81 | optionsMap.regexpConstructors, 82 | 83 | optionsMap.removeConsole, 84 | optionsMap.removeDebugger, 85 | optionsMap.removeUndefined, 86 | 87 | proxy("keepFnName", [ 88 | optionsMap.mangle, 89 | optionsMap.deadcode 90 | ]), 91 | 92 | proxy("keepClassName", [ 93 | optionsMap.mangle, 94 | optionsMap.deadcode 95 | ]) 96 | ], 97 | "some" 98 | ); 99 | 100 | // verify all plugins are used 101 | if (usedPlugins.size !== PLUGINS.length) { 102 | const unusedPlugins = PLUGINS 103 | .filter((plugin) => !usedPlugins.has(plugin[0])) 104 | .map((plugin) => plugin[0]); 105 | throw new Error("Some imported plugins unused\n" + unusedPlugins); 106 | } 107 | 108 | const plugins = generate(optionsTree, opts); 109 | 110 | return { 111 | minified: true, 112 | comments: false, 113 | presets: [ 114 | { plugins } 115 | ], 116 | passPerPreset: true, 117 | }; 118 | } 119 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-simplify/__tests__/pattern-match.js: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | 3 | const PatternMatch = require("../src/pattern-match"); 4 | 5 | describe("simplify-plugin - pattern-match", () => { 6 | it("should match simple patterns", () => { 7 | const patterns = [ 8 | ["a", "b", "c"], 9 | ["foo", "bar"], 10 | ["bar", "bar", true], 11 | [1, true, "foo"], 12 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 0], 13 | ["foo", 1, (a) => a] 14 | ]; 15 | const matcher = new PatternMatch(patterns); 16 | 17 | patterns.forEach((pattern) => { 18 | const input = pattern.slice(0, pattern.length - 1); 19 | const result = matcher.match(input); 20 | expect(result.match).toBe(true); 21 | expect(result.value).toBe(pattern[pattern.length - 1]); 22 | }); 23 | }); 24 | 25 | it("should match simple patterns 2", () => { 26 | const patterns = [ 27 | [true, false], 28 | [true, true], 29 | ["foo", "bar"], 30 | [1, 2, 3], 31 | ["a", 1, true] 32 | ]; 33 | const matcher = new PatternMatch(patterns.map((pattern) => { 34 | return [...pattern, (pattern1) => { 35 | expect(pattern1).toEqual(pattern); 36 | }]; 37 | })); 38 | patterns.forEach((pattern) => { 39 | const result = matcher.match(pattern); 40 | expect(result.match).toBe(true); 41 | result.value(pattern); 42 | }); 43 | }); 44 | 45 | it("should throw when a pattern contains less than 2 entries", () => { 46 | expect(() => { 47 | new PatternMatch([ 48 | ["foo", "bar"], 49 | ["baz"] 50 | ]); 51 | }).toThrowError("at least 2 elements required in a pattern"); 52 | }); 53 | 54 | it("should accept a custom matcher", () => { 55 | const BOOL = (a) => typeof a === "boolean"; 56 | const NUMBER = (a) => typeof a === "number"; 57 | const STRING = (a) => typeof a === "string"; 58 | const MATCHER = (a) => a instanceof PatternMatch; 59 | 60 | const matcher = new PatternMatch([ 61 | [ BOOL, NUMBER, "foo" ], 62 | [ NUMBER, ["foo", "bar", BOOL], "foobarbaz" ], 63 | [ BOOL, STRING, NUMBER, "baz" ], 64 | [ STRING, MATCHER, "foobar" ] 65 | ]); 66 | 67 | const inputs = [ 68 | [true, 1], 69 | [false, 10.4], 70 | [100, "foo"], 71 | [0.5, "bar"], 72 | [1, false], 73 | [false, "foo", 10], 74 | ["bar", matcher] 75 | ]; 76 | 77 | const expected = [ 78 | "foo", 79 | "foo", 80 | "foobarbaz", 81 | "foobarbaz", 82 | "foobarbaz", 83 | "baz", 84 | "foobar" 85 | ]; 86 | 87 | inputs.forEach((input, index) => { 88 | const result = matcher.match(input, customMatchFunction); 89 | expect(result.match).toBe(true); 90 | expect(result.value).toBe(expected[index]); 91 | }); 92 | 93 | function customMatchFunction(pattern, input) { 94 | if (typeof pattern === "function") { 95 | return pattern(input); 96 | } 97 | if (Array.isArray(pattern)) { 98 | for (let i = 0; i < pattern.length; i++) { 99 | if (customMatchFunction(pattern[i], input)) { 100 | return true; 101 | } 102 | } 103 | return false; 104 | } 105 | return pattern === input; 106 | } 107 | }); 108 | 109 | it("should match in order - first match should win", () => { 110 | const matcher = new PatternMatch([ 111 | [1, true, "foo"], 112 | [1, true, "bar"] 113 | ]); 114 | const result = matcher.match([1, true]); 115 | expect(result.match).toBe(true); 116 | expect(result.value).toBe("foo"); 117 | }); 118 | 119 | it("should handle case no match found", () => { 120 | const matcher = new PatternMatch([ 121 | [1, 2, 3], 122 | [2, 2, 4, 5], 123 | [3, 2, 1, 6], 124 | [1, 2, 4, 3], 125 | [4, 3, 2, 1] 126 | ]); 127 | const result = matcher.match([1, 2, 5]); 128 | expect(result.match).toBe(false); 129 | expect(result.value).toBe(void 0); 130 | }); 131 | 132 | it("should match the first found pattern even if it's less specific", () => { 133 | const matcher = new PatternMatch([ 134 | ["foo", "bar", "baz"], 135 | ["foo", "bar", "baz", true] 136 | ]); 137 | const result = matcher.match(["foo", "bar"]); 138 | expect(result.match).toBe(true); 139 | expect(result.value).toBe("baz"); 140 | }); 141 | 142 | it("should match the first found pattern even if it's less specific 2", () => { 143 | const matcher = new PatternMatch([ 144 | [1, 2, 3], 145 | [1, 2, 3, 4], 146 | [1, 3], 147 | [1, 3, 5] 148 | ]); 149 | 150 | expect(matcher.match([1])).toEqual({ 151 | match: true, 152 | value: 3, 153 | keys: [1] 154 | }); 155 | 156 | expect(matcher.match([1, 2])).toEqual({ 157 | match: true, 158 | value: 3, 159 | keys: [1, 2] 160 | }); 161 | 162 | expect(matcher.match([1, 3])).toEqual({ 163 | match: true, 164 | value: 5, 165 | keys: [1, 3] 166 | }); 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /packages/babel-preset-babili/README.md: -------------------------------------------------------------------------------- 1 | # babel-preset-babili 2 | 3 | Babel preset for all minify plugins. 4 | 5 | + [Install](#install) 6 | + [Usage](#usage) 7 | + [Options](#options) 8 | 9 | ## Install 10 | 11 | ```sh 12 | npm install --save-dev babel-preset-babili 13 | ``` 14 | 15 | ## Usage 16 | 17 | ### Via `.babelrc` (Recommended) 18 | 19 | **.babelrc** 20 | 21 | ```json 22 | { 23 | "presets": ["babili"] 24 | } 25 | ``` 26 | 27 | or pass in options - 28 | 29 | ```json 30 | { 31 | "presets": [["babili", { 32 | "mangle": { 33 | "blacklist": ["MyCustomError"] 34 | }, 35 | "unsafe": { 36 | "typeConstructors": false 37 | }, 38 | "keepFnName": true 39 | }]] 40 | } 41 | ``` 42 | 43 | ### Via CLI 44 | 45 | ```sh 46 | babel script.js --presets babili 47 | ``` 48 | 49 | ### Via Node API 50 | 51 | ```javascript 52 | require("babel-core").transform("code", { 53 | presets: ["babili"] 54 | }); 55 | ``` 56 | 57 | ## Options 58 | 59 | All options are **enabled** by default **except** the ones with an explicit mention - `(Default: false)` 60 | 61 | Three types of options: 62 | 63 | ### 1-1 mapping with plugin 64 | 65 | + `false` to disable the plugin 66 | + `true` to enable the plugin with default plugin specific options 67 | + `{ ...pluginOpts }` to enable the plugin with custom plugin options 68 | 69 | The following options have 1-1 mapping with a plugin, 70 | + `evaluate` - [babel-plugin-minify-constant-folding](../../packages/babel-plugin-minify-constant-folding) 71 | + `deadcode` - [babel-plugin-minify-dead-code-elimination](../../packages/babel-plugin-minify-dead-code-elimination) 72 | + `infinity` - [babel-plugin-minify-infinity](../../packages/babel-plugin-minify-infinity) 73 | + `mangle` - [babel-plugin-minify-mangle-names](../../packages/babel-plugin-minify-mangle-names) 74 | + `numericLiterals` - [babel-plugin-minify-numeric-literals](../../packages/babel-plugin-minify-numeric-literals) 75 | + `replace` - [babel-plugin-minify-replace](../../packages/babel-plugin-minify-replace) 76 | + `simplify` - [babel-plugin-minify-simplify](../../packages/babel-plugin-minify-simplify) 77 | + `mergeVars` - [babel-plugin-transform-merge-sibling-variables](../../packages/babel-plugin-transform-merge-sibling-variables) 78 | + `booleans` - [babel-plugin-transform-minify-booleans](../../packages/babel-plugin-transform-minify-booleans) 79 | + `regexpConstructors` - [babel-plugin-transform-regexp-constructors](../../packages/babel-plugin-transform-regexp-constructors) 80 | + `removeConsole` - `(Default: false)` - [babel-plugin-transform-remove-console](../../packages/babel-plugin-transform-remove-console) 81 | + `removeDebugger` - `(Default: false)` - [babel-plugin-transform-remove-debugger](../../packages/babel-plugin-transform-remove-debugger) 82 | + `removeUndefined` - [babel-plugin-transform-remove-undefined](../../packages/babel-plugin-transform-remove-undefined) 83 | + `undefinedToVoid` - [babel-plugin-transform-undefined-to-void](../../packages/babel-plugin-transform-undefined-to-void) 84 | 85 | **Examples** 86 | 87 | ```json 88 | { 89 | "presets": [["babili", { 90 | "evaluate": false, 91 | "mangle": true 92 | }]] 93 | } 94 | ``` 95 | 96 | ```json 97 | { 98 | "presets": [["babili", { 99 | "mangle": { 100 | "blacklist": { 101 | "ParserError": true, 102 | "NetworkError": false 103 | } 104 | } 105 | }]] 106 | } 107 | ``` 108 | 109 | ### Option groups 110 | 111 | + `false` to disable the entire group 112 | + `true` to enable every plugin in the group 113 | + `{ pluginKey: <1-1 mapping> }` - enable/disable a particular plugin in a group (or) pass options to that plugin 114 | 115 | The following are groups of plugins - 116 | 117 | + `unsafe` 118 | + `flipComparisons` - [babel-plugin-minify-flip-comparisons](../../packages/babel-plugin-minify-flip-comparisons) 119 | + `simplifyComparisons` - [babel-plugin-transform-simplify-comparison-operators](../../babel-plugin-transform-simplify-comparison-operators) 120 | + `guards` - [babel-plugin-minify-guarded-expressions](../../packages/babel-plugin-minify-guarded-expressions) 121 | + `typeConstructors` - [babel-plugin-minify-type-constructors](../../packages/babel-plugin-minify-type-constructors) 122 | + `properties` 123 | + `memberExpressions` - [babel-plugin-transform-member-expression-literals](../../packages/babel-plugin-transform-member-expression-literals) 124 | + `propertyLiterals` - [babel-plugin-transform-property-literals](../../packages/babel-plugin-transform-property-literals) 125 | 126 | **Examples** 127 | 128 | Disables all unsafe plugins: 129 | 130 | ```json 131 | { 132 | "presets": [["babili", { 133 | "unsafe": false 134 | }]] 135 | } 136 | ``` 137 | 138 | Disables only minify-guarded-expressions, and enable all other unsafe plugins: 139 | 140 | ```json 141 | { 142 | "presets": [["babili", { 143 | "unsafe": { 144 | "guards": false 145 | } 146 | }]] 147 | } 148 | ``` 149 | 150 | ### Passing same plugin options to multiple plugins 151 | 152 | In babili, multiple plugins require the same set of options and it is easier to mention it in one place instead of two. 153 | 154 | + `keepFnName` - This will be passed to `mangle` and `deadcode` and will NOT be overriden if the same option exists under either mangle or deadcode. 155 | 156 | **Examples** 157 | 158 | ```json 159 | { 160 | "presets": [["babili", { 161 | "keepFnName": true 162 | }]] 163 | } 164 | ``` 165 | 166 | is the same as, 167 | 168 | Plugins applied: 169 | 170 | ```json 171 | { 172 | "presets": [["babili", { 173 | "mangle": { 174 | "keepFnName": true 175 | }, 176 | "deadcode": { 177 | "keepFnName": true 178 | } 179 | }]] 180 | } 181 | ``` 182 | -------------------------------------------------------------------------------- /packages/babel-plugin-minify-type-constructors/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function replaceArray(t, path) { 4 | const { node } = path; 5 | // arguments is taken :( 6 | const constructorArgs = path.get("arguments"); 7 | if (t.isIdentifier(node.callee, { name: "Array" }) && 8 | !path.scope.getBinding("Array")) { 9 | 10 | if (constructorArgs.length === 0) { 11 | // Array() -> [] 12 | path.replaceWith(t.arrayExpression([])); 13 | } else if (constructorArgs.length === 1) { 14 | const arg = constructorArgs[0]; 15 | const result = arg.evaluate(); 16 | 17 | if (result.confident) { 18 | if (typeof result.value === "number") { 19 | if (result.value >= 0 && result.value <= 6 && result.value % 1 === 0) { 20 | // "Array(7)" is shorter than "[,,,,,,,]" 21 | path.replaceWith(t.arrayExpression(Array(result.value).fill(null))); 22 | } else { 23 | dropNewIfPresent(); 24 | } 25 | } else { 26 | // Array("Asdf"), Array(true), Array(false) 27 | path.replaceWith(t.arrayExpression([t.valueToNode(result.value)])); 28 | } 29 | } else { 30 | const transformables = [ 31 | "ArrayExpression", 32 | "ObjectExpression", 33 | "FunctionExpression", 34 | "ArrowFunctionExpression", 35 | "ClassExpression" 36 | ]; 37 | if (transformables.indexOf(arg.node.type) !== -1) { 38 | // Array([]), Array({}) 39 | // Array(()=>{}), Array(class{}), Array(function(){}) 40 | path.replaceWith(t.arrayExpression([arg.node])); 41 | } else { 42 | // Array(x); Array(a.b); 43 | dropNewIfPresent(); 44 | } 45 | } 46 | } else { 47 | // Array(2,3), Array(a,b) => [2,3], [a,b] 48 | path.replaceWith(t.arrayExpression(node.arguments)); 49 | } 50 | return true; 51 | } 52 | 53 | function dropNewIfPresent() { 54 | if (path.isNewExpression()) { 55 | path.replaceWith(t.callExpression(node.callee, node.arguments)); 56 | } 57 | } 58 | } 59 | 60 | function replaceObject(t, path) { 61 | const { node } = path; 62 | if (t.isIdentifier(node.callee, { name: "Object" }) && 63 | !path.scope.getBinding("Object")) { 64 | 65 | const isVoid0 = require("babel-helper-is-void-0")(t); 66 | const arg = node.arguments[0]; 67 | const binding = arg && t.isIdentifier(arg) && path.scope.getBinding(arg.name); 68 | 69 | // Object() -> {} 70 | if (node.arguments.length === 0) { 71 | path.replaceWith(t.objectExpression([])); 72 | 73 | // Object([]) -> [] 74 | } else if (arg.type === "ArrayExpression" || 75 | t.isFunctionExpression(arg)) { 76 | path.replaceWith(arg); 77 | 78 | // Object(null) -> {} 79 | } else if (isVoid0(arg) || 80 | arg.name === "undefined" || 81 | arg.type === "NullLiteral" || 82 | arg.type === "ObjectExpression" && arg.properties.length === 0) { 83 | path.replaceWith(t.objectExpression([])); 84 | 85 | // Object(localFn) -> localFn 86 | } else if (binding && binding.path.isFunction()) { 87 | path.replaceWith(arg); 88 | 89 | // Object({a:b}) -> {a:b} 90 | } else if (arg.type === "ObjectExpression") { 91 | path.replaceWith(arg); 92 | 93 | // new Object(a) -> Object(a) 94 | } else if (node.type === "NewExpression") { 95 | path.replaceWith(t.callExpression(node.callee, node.arguments)); 96 | } 97 | return true; 98 | } 99 | } 100 | 101 | function defaults({ 102 | boolean = true, 103 | number = true, 104 | string = true, 105 | array = true, 106 | object = true 107 | } = {}) { 108 | return { 109 | boolean, number, string, array, object 110 | }; 111 | } 112 | 113 | module.exports = function({ types: t }) { 114 | return { 115 | name: "minify-type-constructors", 116 | visitor: { 117 | CallExpression(path) { 118 | const { node } = path; 119 | const opts = defaults(this.opts); 120 | 121 | // Boolean(foo) -> !!foo 122 | if ( 123 | opts.boolean && 124 | t.isIdentifier(node.callee, { name: "Boolean" }) && 125 | node.arguments.length === 1 && 126 | !path.scope.getBinding("Boolean")) { 127 | path.replaceWith(t.unaryExpression("!", t.unaryExpression("!", node.arguments[0], true), true)); 128 | return; 129 | } 130 | 131 | // Number(foo) -> +foo 132 | if ( 133 | opts.number && 134 | t.isIdentifier(node.callee, { name: "Number" }) && 135 | node.arguments.length === 1 && 136 | !path.scope.getBinding("Number")) { 137 | path.replaceWith(t.unaryExpression("+", node.arguments[0], true)); 138 | return; 139 | } 140 | 141 | // String(foo) -> foo + '' 142 | if ( 143 | opts.string && 144 | t.isIdentifier(node.callee, { name: "String" }) && 145 | node.arguments.length === 1 && 146 | !path.scope.getBinding("String")) { 147 | path.replaceWith(t.binaryExpression("+", node.arguments[0], t.stringLiteral(""))); 148 | return; 149 | } 150 | 151 | // Array() -> [] 152 | if (opts.array && replaceArray(t, path)) { 153 | return; 154 | } 155 | 156 | // Object() -> {} 157 | if (opts.object && replaceObject(t, path)) { 158 | return; 159 | } 160 | }, 161 | NewExpression(path) { 162 | const opts = defaults(this.opts); 163 | 164 | // new Array() -> [] 165 | if (opts.array && replaceArray(t, path)) { 166 | return; 167 | } 168 | 169 | // new Object() -> {} 170 | if (opts.object && replaceObject(t, path)) { 171 | return; 172 | } 173 | }, 174 | }, 175 | }; 176 | }; 177 | --------------------------------------------------------------------------------