├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── README.md ├── generators └── app │ ├── index.js │ ├── json-fp.js │ └── map-babel.js ├── package.json └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/legacy" 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - v5 4 | - v4 5 | - '0.12' 6 | - '0.10' 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # generator-babel 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![Build Status][travis-image]][travis-url] 5 | [![Dependency Status][depstat-image]][depstat-url] 6 | 7 | > [Yeoman][yo] generator to setup [Babel][babel] effortlessly (with plugins, if you want). 8 | > Works great as [cli](#usage) and [with other generators too](#composability). 9 | 10 | By default, Babel doesn’t do anything! You need to configure it. So this package will create Babel’s configuration file `.babelrc` with default `es2015` preset and install required `babel-cli`, `babel-core` to devDependencies in your project. 11 | 12 | After this package’s work is finished, you can access `babel-cli` and `babel-register` from your npm scripts. It’s useful for: 13 | * **[transpilation][babel-cli]:** `babel index.js --out-file index.es5.js` 14 | * **testing** via [hook][babel-register]: `mocha --require babel-register`, `tape test.js --require babel-register`, etc. 15 | 16 | [yo]: http://yeoman.io/ 17 | [babel]: https://babeljs.io/ 18 | [babel-cli]: https://babeljs.io/docs/usage/cli/#babel 19 | [babel-register]: https://babeljs.io/docs/setup/#babel_register 20 | [babel-node]: https://babeljs.io/docs/usage/cli/#babel-node 21 | 22 | ## Install 23 | 24 | npm install --global yo generator-babel 25 | 26 | ## Usage 27 | 28 | # default es2015 preset 29 | yo babel 30 | 31 | # your favorite presets 32 | yo babel es2015 stage-0 33 | 34 | # with plugins with --plugins/-p 35 | yo babel -p add-module-exports 36 | yo babel -p transform-strict-mode,transform-object-assign 37 | 38 | The entire range of [Babel presets][babel-presets] are allowed. 39 | 40 | [babel-presets]: http://babeljs.io/docs/plugins/#presets 41 | 42 | ## Composability 43 | 44 | > Composability is a way to combine smaller parts to make one large thing. Sort of [like Voltron®][voltron] 45 | > — [Yeoman docs](http://yeoman.io/authoring/composability.html) 46 | 47 | Just plug in _babel_ into your generator and let it setup your `.babelrc` and install required `devDependencies` for you. Everybody wins. 48 | 49 | ### Install 50 | 51 | npm install --save generator-babel 52 | 53 | #### Compose 54 | 55 | `skip-install` is used because `babel` install babel deps for you 56 | and you don’t need to test it in your own generator tests. 57 | 58 | ```js 59 | this.composeWith('babel', { options: { 60 | 'skip-install': this.options['skip-install'] 61 | }}, { 62 | local: require.resolve('generator-babel/generators/app') 63 | }); 64 | ``` 65 | 66 | Add any extra fields you need to `options.config` to extend the [default][defaults] configuration. The entire range of [Babel options][babel-options] are allowed. 67 | 68 | ```js 69 | this.composeWith('babel', { options: { 70 | 'skip-install': this.options['skip-install'], 71 | config: { 72 | presets: ['es2015', 'stage-0'], 73 | plugins: ['transform-strict-mode', 'transform-object-assign'], 74 | sourceMaps: true 75 | } 76 | }}, { 77 | local: require.resolve('generator-babel') 78 | }); 79 | ``` 80 | 81 | Required list of `presets` and `plugins` will be installed to `devDependencies` into your project with proper names: `es2015` will be `babel-preset-es2015` and `transform-strict-mode` will be `babel-plugin-transform-strict-mode`. 82 | 83 | [babel-options]: http://babeljs.io/docs/usage/options/ 84 | [defaults]: https://github.com/iamstarkov/generator-babel/blob/master/generators/app/templates/_babelrc 85 | [voltron]: http://25.media.tumblr.com/tumblr_m1zllfCJV21r8gq9go11_250.gif 86 | 87 | ## License 88 | 89 | MIT © [Vladimir Starkov](https://iamstarkov.com) 90 | 91 | [npm-url]: https://npmjs.org/package/generator-babel 92 | [npm-image]: https://img.shields.io/npm/v/generator-babel.svg?style=flat 93 | 94 | [travis-url]: https://travis-ci.org/iamstarkov/generator-babel 95 | [travis-image]: https://img.shields.io/travis/iamstarkov/generator-babel.svg?style=flat 96 | 97 | [depstat-url]: https://david-dm.org/iamstarkov/generator-babel 98 | [depstat-image]: https://david-dm.org/iamstarkov/generator-babel.svg?style=flat 99 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable func-names,vars-on-top */ 2 | 3 | var yeoman = require('yeoman-generator'); 4 | var R = require('ramda'); 5 | var splitKeywords = require('split-keywords'); 6 | var sortedObject = require('sorted-object'); 7 | var depsObject = require('deps-object'); 8 | var mapPrefixPreset = require('./map-babel').mapPrefixPreset; 9 | var mapPrefixPlugin = require('./map-babel').mapPrefixPlugin; 10 | var stringify = require('./json-fp').stringify; 11 | var parse = require('./json-fp').parse; 12 | 13 | // concatAll :: [Array] -> Array 14 | var concatAll = R.reduce(R.concat, []); 15 | 16 | module.exports = yeoman.Base.extend({ 17 | constructor: function () { 18 | yeoman.Base.apply(this, arguments); 19 | this.argument('presets', { type: Array, required: false, 20 | desc: 'Presets’ list: "yo babel es2015 es2016"\n' 21 | }); 22 | this.option('plugins', { type: String, required: false, alias: 'p', 23 | desc: 'Plugins list: "yo babel -p add-module-exports"' 24 | }); 25 | 26 | // helpers 27 | this.saveDepsToPkg = function (deps) { 28 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}); 29 | var currentDeps = pkg.devDependencies || {}; 30 | var mergedDeps = R.merge(currentDeps, deps); 31 | var sortedDeps = sortedObject(mergedDeps); 32 | pkg.devDependencies = sortedDeps; 33 | this.fs.writeJSON(this.destinationPath('package.json'), pkg); 34 | }; 35 | }, 36 | writing: function () { 37 | var cli = {}; 38 | 39 | if (this.presets) { 40 | cli.presets = this.presets; 41 | } 42 | 43 | var plugins = this.options.plugins; 44 | if (typeof plugins === 'boolean') { 45 | this.log('Maybe you forgot double dash: `-plugins` instead of `--plugins`'); 46 | } 47 | 48 | if (plugins) { 49 | cli.plugins = (typeof plugins === 'string') ? splitKeywords(plugins) : plugins; 50 | } 51 | 52 | var existing = this.fs.exists(this.destinationPath('.babelrc')) 53 | ? parse(this.fs.read(this.destinationPath('.babelrc'))) 54 | : {}; 55 | var defaults = { presets: ['es2015'] }; 56 | 57 | var result = R.mergeAll([existing, defaults, cli, (this.options.config || {})]); 58 | this.fs.write(this.destinationPath('.babelrc'), (stringify(result) + '\n')); 59 | var deps = concatAll([ 60 | 'babel-cli@6.6.5', 'babel-register@6.7.2', 61 | mapPrefixPreset(result.presets || []), 62 | mapPrefixPlugin(result.plugins || []) 63 | ]); 64 | 65 | return depsObject(deps) 66 | .then(function (devDeps) { 67 | this.saveDepsToPkg(devDeps); 68 | }.bind(this)) 69 | .catch(function (err) { 70 | throw err; 71 | }); 72 | }, 73 | install: function () { 74 | if (!this.options['skip-install']) { 75 | this.npmInstall(); 76 | } 77 | } 78 | }); 79 | -------------------------------------------------------------------------------- /generators/app/json-fp.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stringify: function stringify(obj) { return JSON.stringify(obj, null, 2); }, 3 | parse: JSON.parse.bind(JSON) 4 | }; 5 | -------------------------------------------------------------------------------- /generators/app/map-babel.js: -------------------------------------------------------------------------------- 1 | var R = require('ramda'); 2 | 3 | module.exports = { 4 | mapPrefixPreset: R.map(R.concat('babel-preset-')), 5 | mapPrefixPlugin: R.map(R.concat('babel-plugin-')) 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-babel", 3 | "version": "2.0.2", 4 | "description": "Yeoman generator to setup Babel effortlessly (with plugins, if you want)", 5 | "license": "MIT", 6 | "main": "generators/app/index.js", 7 | "repository": "iamstarkov/generator-babel", 8 | "author": { 9 | "name": "Vladimir Starkov", 10 | "email": "iamstarkov@gmail.com", 11 | "url": "https://github.com/iamstarkov" 12 | }, 13 | "scripts": { 14 | "test": "mocha -t 10000", 15 | "tdd": "npm test -- --watch", 16 | "postpublish": "git push origin master --tags" 17 | }, 18 | "files": [ 19 | "generators" 20 | ], 21 | "keywords": [ 22 | "yeoman-generator", 23 | "babel", 24 | "babeljs", 25 | "compiler", 26 | "compilation", 27 | "transpiler", 28 | "transpilation", 29 | "es6", 30 | "es2015", 31 | "boilerplate", 32 | "node", 33 | "starter", 34 | "kit", 35 | "yeoman", 36 | "plugin", 37 | "boilerplate", 38 | "template", 39 | "scaffold", 40 | "module", 41 | "node_module", 42 | "node-module", 43 | "travis", 44 | "javascript", 45 | "npm" 46 | ], 47 | "dependencies": { 48 | "deps-object": "^2.0.0", 49 | "ramda": "^0.21.0", 50 | "sorted-object": "^2.0.0", 51 | "split-keywords": "^2.0.0", 52 | "yeoman-generator": "^0.22.5" 53 | }, 54 | "devDependencies": { 55 | "eslint": "^2.4.0", 56 | "eslint-config-airbnb": "^6.1.0", 57 | "mocha": "*", 58 | "babel-eslint": "^6.0.0", 59 | "yeoman-assert": "^2.1.1", 60 | "yeoman-test": "^1.0.0" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | /* eslint-disable func-names, no-extra-bind */ 3 | 4 | var R = require('ramda'); 5 | var path = require('path'); 6 | var assert = require('yeoman-assert'); 7 | var helpers = require('yeoman-test'); 8 | var depsObject = require('deps-object'); 9 | var mapPrefixPreset = require('./generators/app/map-babel').mapPrefixPreset; 10 | var mapPrefixPlugin = require('./generators/app/map-babel').mapPrefixPlugin; 11 | 12 | var generator = function() { 13 | return helpers.run(path.join(__dirname, './generators/app')); 14 | }; 15 | 16 | it('creates files', function(done) { 17 | generator().on('end', function() { 18 | assert.file('.babelrc'); 19 | done(); 20 | }); 21 | }); 22 | 23 | it('uses presets from options.config', function(done) { 24 | var config = { presets: ['es2015', 'stage-0'] }; 25 | generator().withOptions({ config: config }).on('end', function() { 26 | assert.jsonFileContent('.babelrc', config); 27 | done(); 28 | }); 29 | }); 30 | 31 | it('uses presets from arguments', function(done) { 32 | var presets = ['es2015', 'stage-0']; 33 | generator().withArguments(presets).on('end', function() { 34 | assert.jsonFileContent('.babelrc', { presets: presets }); 35 | done(); 36 | }); 37 | }); 38 | 39 | it('uses plugins from options.config', function(done) { 40 | var plugins = ['transform-strict-mode', 'transform-object-assign']; 41 | generator().withOptions({ config: { plugins: plugins }}).on('end', function() { 42 | assert.jsonFileContent('.babelrc', { plugins: plugins }); 43 | done(); 44 | }); 45 | }); 46 | 47 | it('uses plugins from options.plugins', function(done) { 48 | var plugins = ['transform-strict-mode', 'transform-object-assign']; 49 | generator().withOptions({ plugins: ['transform-strict-mode', 'transform-object-assign'] }).on('end', function() { 50 | assert.jsonFileContent('.babelrc', { plugins: plugins }); 51 | done(); 52 | }); 53 | }); 54 | 55 | it('uses any other option from options.config', function(done) { 56 | var config = { sourceMaps: true }; 57 | generator().withOptions({ config: config }).on('end', function() { 58 | assert.jsonFileContent('.babelrc', config); 59 | done(); 60 | }); 61 | }); 62 | 63 | it('add presets and plugins with proper prefixes', function(done) { 64 | var presets = ['es2015', 'stage-0']; 65 | var plugins = ['transform-strict-mode', 'transform-object-assign']; 66 | var deps = R.concat(mapPrefixPreset(presets), mapPrefixPlugin(plugins)); 67 | depsObject(deps).then(function(devDeps) { 68 | generator() 69 | .withOptions({ config: { 70 | presets: presets, 71 | plugins: plugins, 72 | sourceMaps: true, 73 | }}) 74 | .on('end', function() { 75 | assert.jsonFileContent('package.json', { devDependencies: devDeps }); 76 | done(); 77 | }); 78 | }); 79 | }); 80 | 81 | it('not adding es2015 if config.presets are specified', function(done) { 82 | var config = { presets: ['es2016'] }; 83 | generator().withOptions({ config: config }).on('end', function() { 84 | assert.noFileContent('.babelrc', /es2015/); 85 | done(); 86 | }); 87 | }); 88 | --------------------------------------------------------------------------------