diff --git a/packages/gulp-babili/.npmignore b/packages/gulp-babili/.npmignore new file mode 100644 index 000000000..22250660e --- /dev/null +++ b/packages/gulp-babili/.npmignore @@ -0,0 +1,4 @@ +src +__tests__ +node_modules +*.log diff --git a/packages/gulp-babili/README.md b/packages/gulp-babili/README.md new file mode 100644 index 000000000..a9df9ea17 --- /dev/null +++ b/packages/gulp-babili/README.md @@ -0,0 +1,41 @@ +# gulp-babili + +## Installation + +```sh +npm install gulp-babili --save-dev +``` + +## Usage + +```js +const gulp = require("gulp"); +const babili = require("gulp-babili"); + +gulp.task("minify", () => + gulp.src("./build/app.js") + .pipe(babili({ + mangle: { + keepClassNames: true + } + })) + .pipe(gulp.dest("./dist")); +); +``` + +## API + +```js +gulpBabili(babiliOptions, overrides); +``` + +### babiliOptions + +These are passed on to the babili preset. Refer https://github.com/babel/babili/tree/master/packages/babel-preset-babili#options. Default `{}` + +### Overrides + +Default: `{}` + ++ `babel`: Use a custom `babel-core` ++ `babili`: Use a custom `babel-preset-babili` diff --git a/packages/gulp-babili/__tests__/__snapshots__/gulp-babili-test.js.snap b/packages/gulp-babili/__tests__/__snapshots__/gulp-babili-test.js.snap new file mode 100644 index 000000000..720f65986 --- /dev/null +++ b/packages/gulp-babili/__tests__/__snapshots__/gulp-babili-test.js.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`gulp-babili comments should remove all comments when false 1`] = `"foo(),bar(),baz();"`; + +exports[`gulp-babili comments should remove comments by default except license and preserve 1`] = ` +/** + * @license + * This is a test + */"foo(),bar(),baz();"`; + +exports[`gulp-babili comments should take a custom function 1`] = `"/* YAC - yet another comment */foo(),bar(),baz();"`; diff --git a/packages/gulp-babili/__tests__/gulp-babili-test.js b/packages/gulp-babili/__tests__/gulp-babili-test.js new file mode 100644 index 000000000..5f0fed2d4 --- /dev/null +++ b/packages/gulp-babili/__tests__/gulp-babili-test.js @@ -0,0 +1,167 @@ +jest.autoMockOff(); + +const gutil = require("gulp-util"); +const babelCore = require("babel-core"); +const babiliPreset = require("babel-preset-babili"); + +const unpad = require("../../../utils/unpad"); +const gulpBabili = require("../src/index"); + +describe("gulp-babili", () => { + it("should work with a good default", () => { + return new Promise((resolve, reject) => { + const stream = gulpBabili(); + + const source = unpad(` + function foo() { + const a = 10; + return a; + } + `); + const expected = "function foo(){return 10}"; + + stream.on("data", function (file) { + expect(file.contents.toString()).toBe(expected); + resolve(); + }); + stream.on("error", reject); + + stream.write(new gutil.File({ + path: "defaults.js", + contents: new Buffer(source), + })); + }); + }); + + it("should take options and pass them to babili", () => { + return new Promise((resolve, reject) => { + const stream = gulpBabili({ + mangle: { + blacklist: { + bar: true + } + } + }); + + const source = unpad(` + function foo(bar, baz) { + return bar + baz; + } + `); + const expected = "function foo(bar,a){return bar+a}"; + + stream.on("data", function (file) { + expect(file.contents.toString()).toBe(expected); + resolve(); + }); + stream.on("error", reject); + + stream.write(new gutil.File({ + path: "options.js", + contents: new Buffer(source) + })); + }); + }); + + it("should take custom babel and babili", () => { + return new Promise((resolve, reject) => { + const babel = Object.assign({}, babelCore); + + let usedTransform = false; + Object.defineProperty(babel, "transform", { + get() { + usedTransform = true; + return babelCore.transform; + } + }); + + let usedPreset = false; + const babili = function (...args) { + usedPreset = true; + return babiliPreset(...args); + }; + + const stream = gulpBabili({}, { + babel, + babili, + }); + + stream.on("data", function () { + expect(usedTransform).toBe(true); + expect(usedPreset).toBe(true); + resolve(); + }); + stream.on("error", reject); + + stream.write(new gutil.File({ + path: "custom-transformers.js", + contents: new Buffer("foo()") + })); + }); + }); + + describe("comments", () => { + const source = unpad(` + /** + * @license + * This is a test + */ + foo(); + // this is another comment + bar(); + /* YAC - yet another comment */ + baz(); + `); + + let file; + + beforeEach(() => { + file = new gutil.File({ + path: "comments.js", + contents: new Buffer(source) + }); + }); + + xit("should remove comments by default except license and preserve", () => { + return new Promise((resolve, reject) => { + const stream = gulpBabili(); + stream.on("data", function (file) { + expect(file.contents.toString()).toMatchSnapshot(); + resolve(); + }); + stream.on("error", reject); + stream.write(file); + }); + }); + + it("should remove all comments when false", () => { + return new Promise((resolve, reject) => { + const stream = gulpBabili({ + comments: false + }); + stream.on("data", () => { + expect(file.contents.toString()).toMatchSnapshot(); + resolve(); + }); + stream.on("error", reject); + stream.write(file); + }); + }); + + xit("should take a custom function", () => { + return new Promise((resolve, reject) => { + const stream = gulpBabili({ + comments(contents) { + return contents.indexOf("YAC") !== -1; + } + }); + stream.on("data", () => { + expect(file.contents.toString()).toMatchSnapshot(); + resolve(); + }); + stream.on("error", reject); + stream.write(file); + }); + }); + }); +}); diff --git a/packages/gulp-babili/package.json b/packages/gulp-babili/package.json new file mode 100644 index 000000000..7f8f83b0c --- /dev/null +++ b/packages/gulp-babili/package.json @@ -0,0 +1,21 @@ +{ + "name": "gulp-babili", + "version": "0.0.1", + "description": "Gulp Babili", + "homepage": "https://github.com/babel/babili#readme", + "repository": "https://github.com/babel/babili/tree/master/packages/gulp-babili", + "bugs": "https://github.com/babel/babili/issues", + "author": "boopathi", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-preset", + "babili" + ], + "dependencies": { + "babel-core": "^6.22.1", + "babel-preset-babili": "^0.0.10", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "devDependencies": {} +} diff --git a/packages/gulp-babili/src/index.js b/packages/gulp-babili/src/index.js new file mode 100644 index 000000000..80a14bc55 --- /dev/null +++ b/packages/gulp-babili/src/index.js @@ -0,0 +1,91 @@ +const babelCore = require("babel-core"); +const through2 = require("through2"); +const gutil = require("gulp-util"); +const applySourceMap = require("vinyl-sourcemaps-apply"); +const babiliPreset = require("babel-preset-babili"); + +const { PluginError } = gutil; + +const NAME = "gulp-babili"; + +module.exports = gulpBabili; + +function gulpBabili(babiliOpts = {}, { + babel = babelCore, + babili = babiliPreset, + comments = /preserve|licen(s|c)e/ +} = {}) { + return through2.obj(function (file, enc, callback) { + if (file.isNull()) { + return callback(null, file); + } + + if (file.isStream()) { + return callback(new PluginError(NAME, "Streaming not supported")); + } + + let inputSourceMap; + if (file.sourceMap && file.sourceMap.mappings) { + inputSourceMap = file.sourceMap; + } + + const babelOpts = { + minified: true, + babelrc: false, + ast: false, + + /* preset */ + presets: [ [ babili, babiliOpts ] ], + + /* sourcemaps */ + sourceMaps: !!file.sourceMap, + inputSourceMap, + + shouldPrintComment(contents) { + return shouldPrintComment(contents, comments); + }, + + /* file */ + filename: file.path, + filenameRelative: file.relative, + }; + + const { result, success, error } = transform({ + babel, + input: file.contents.toString(), + babelOpts + }); + + if (success) { + file.contents = new Buffer(result.code); + if (file.sourceMap) { + applySourceMap(file, result.map); + } + return callback(null, file); + } + + callback(error); + }); +} + +function transform({ babel, input, babelOpts }) { + try { + return { + success: true, + result: babel.transform(input, babelOpts) + }; + } catch (e) { + return { + success: false, + error: e + }; + } +} + +function shouldPrintComment(contents, predicate) { + switch (typeof predicate) { + case "function": return predicate(contents); + case "object": return predicate.test(contents); + default: return !!predicate; + } +}