├── .gitattributes ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── deploy.sh ├── generators ├── app │ └── index.js ├── base.js ├── cli │ ├── index.js │ └── templates │ │ └── cli.tpl ├── readme │ ├── index.js │ └── templates │ │ └── README.tpl ├── src │ ├── index.js │ └── templates │ │ ├── index.tpl │ │ └── rollup.config.tpl └── test │ ├── index.js │ └── templates │ └── test.tpl ├── index.js ├── package.json └── test ├── ci └── index.js ├── generators ├── app.js ├── cli.js ├── readme.js ├── src.js └── test.js └── helpers ├── answers.json └── set-up-mockery.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .tmp/ 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | env: 4 | global: 5 | - CI: true 6 | - GH_REF: github.com/maurizzzio/generator-mnm-example.git 7 | - secure: VqS4f6ybZSWQlJhKRZj6wVWhH6ywCaRo40gDQGd2xmcGUK0JRjDA6+tIQUgpGGFWlpCsm0EgtmTM18RzrfZceOr8o2NAMWMKENAo/8vu8JIojyxVD9th6dWW9JGojgoQaSVUpT7U91wena18qnGjU17vlWUyLEszln4o/RGYrGfEewG1wheYHNYoSwcQZJ8i7+wirRMFkLYB5GrYZaEWTXHg37GILdq+0oA5CH0XgYBPxLR4+u5w88Zno4kw1AdGaNvtywTJrHYAC5Wv6+lWuPTC8905FXqaEqUswYUYzYMy8+1NpttgDchGnpqKO8JdHhXhxKYdUPEg6PgIl16cYEx3BBAwdkZWt2412n2/4qZ6Oi03mR8zjpYt8T9T5t/H43UG3LO3+tDYqAoqyQkxwwrdz8duJp8lfkYWs5wo+U/mZMkNNXM1fmBoywNPyihjBDo8IUtMvNIkIzRRoG3DfKtmQKJHJCXueroOyPXGmiR1X49qd+04xAI9jIikB6SzAUARzK/4KqdsWeKSsbp2nr1iqj7Iltm9hEsJ2VMSfmeEn0RSlGE3m5XdXEhLXzK3D1J9bJyIyheDvuz42C9S1HCTuz1krGMGOaRIlsOrlHh38Zf/9x5lHKT4E6oqOPcQDo2rrox8zbvmWbYYFzmck7T1yLbP3BoU80afEptR4lg= 8 | 9 | node_js: 10 | - v5 11 | before_install: if [[ `npm -v` != 3* ]]; then npm i -g npm@3; fi 12 | script: 13 | - npm run lint 14 | - npm test 15 | - npm run test:ci 16 | after_success: 17 | - bash deploy.sh 18 | 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # [0.6.0](https://github.com/maurizzzio/generator-mnm/compare/v0.5.1...v0.6.0) (2016-09-26) 3 | 4 | 5 | ### Build 6 | 7 | * generator-travis removed in favor of a custom one ([a51f39cb2e39597ae2c188c69689f4800f48752e](https://github.com/maurizzzio/generator-mnm/commit/a51f39cb2e39597ae2c188c69689f4800f48752e)) 8 | 9 | ### Fix 10 | 11 | * added yamljs as a dependency ([4031ae436eda4d4db9cbcb15e3831d02347e4470](https://github.com/maurizzzio/generator-mnm/commit/4031ae436eda4d4db9cbcb15e3831d02347e4470)) 12 | * task test run on CI ([5a50b079264ce5caa73e03ec044b0d9d425c37ad](https://github.com/maurizzzio/generator-mnm/commit/5a50b079264ce5caa73e03ec044b0d9d425c37ad)) 13 | * travis now only tests against node v4 ([792ec4c0b0f2edf3ac57bc186b34606f81e8595c](https://github.com/maurizzzio/generator-mnm/commit/792ec4c0b0f2edf3ac57bc186b34606f81e8595c)) 14 | 15 | ### New 16 | 17 | * added a task changelog to easily generate a CHANGELOG file ([fea3d04ba2f3376771bd1ffbe3a2d8439a017156](https://github.com/maurizzzio/generator-mnm/commit/fea3d04ba2f3376771bd1ffbe3a2d8439a017156)) 18 | * common js bundle created with rollup ([e7b2148d3d9c6bda60b973374ff8701160902b93](https://github.com/maurizzzio/generator-mnm/commit/e7b2148d3d9c6bda60b973374ff8701160902b93)), closes [#2](https://github.com/maurizzzio/generator-mnm/issues/2) 19 | 20 | 21 | 22 | 23 | ## [0.5.1](https://github.com/maurizzzio/generator-mnm/compare/v0.5.0...v0.5.1) (2016-05-10) 24 | 25 | 26 | 27 | 28 | 29 | # [0.5.0](https://github.com/maurizzzio/generator-mnm/compare/v0.4.0...v0.5.0) (2016-05-09) 30 | 31 | 32 | 33 | 34 | 35 | # [0.4.0](https://github.com/maurizzzio/generator-mnm/compare/v0.3.0...v0.4.0) (2016-05-06) 36 | 37 | 38 | 39 | 40 | 41 | # [0.3.0](https://github.com/maurizzzio/generator-mnm/compare/v0.2.3...v0.3.0) (2015-12-08) 42 | 43 | 44 | ### Docs 45 | 46 | * docs related with ES6 bundlers ([9193d03d22dae63c2121b1ac09c891ae1d69e4e6](https://github.com/maurizzzio/generator-mnm/commit/9193d03d22dae63c2121b1ac09c891ae1d69e4e6)) 47 | 48 | ### Fix 49 | 50 | * license field is not present in package.json ([8ccf13ae133c790f9fd6963073800e5af02b56dc](https://github.com/maurizzzio/generator-mnm/commit/8ccf13ae133c790f9fd6963073800e5af02b56dc)), closes [#3](https://github.com/maurizzzio/generator-mnm/issues/3) 51 | 52 | 53 | 54 | 55 | ## [0.2.3](https://github.com/maurizzzio/generator-mnm/compare/v0.2.2...v0.2.3) (2015-12-06) 56 | 57 | 58 | 59 | 60 | 61 | ## [0.2.2](https://github.com/maurizzzio/generator-mnm/compare/v0.2.1...v0.2.2) (2015-12-06) 62 | 63 | 64 | 65 | 66 | 67 | ## [0.2.1](https://github.com/maurizzzio/generator-mnm/compare/v0.2.0...v0.2.1) (2015-12-06) 68 | 69 | 70 | 71 | 72 | 73 | # [0.2.0](https://github.com/maurizzzio/generator-mnm/compare/v0.1.1...v0.2.0) (2015-11-27) 74 | 75 | 76 | 77 | 78 | 79 | ## [0.1.1](https://github.com/maurizzzio/generator-mnm/compare/v0.1.0...v0.1.1) (2015-11-26) 80 | 81 | 82 | 83 | 84 | 85 | # 0.1.0 (2015-11-25) 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

5 | Create node modules writing ES6/ES7 today compiled with Babel, tested with ava, bundled with rollup and linted with standard on top of npm scripts 6 |

7 | 8 |

9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

20 | 21 |
22 | 23 | ## Install 24 | 25 | ```sh 26 | $ npm install -g yo generator-mnm 27 | ``` 28 | 29 | ## Usage 30 | 31 | ```sh 32 | Usage: 33 | yo mnm:app [options] [] 34 | 35 | Options: 36 | -h, --help # Print the generator's options and usage 37 | --skip-cache # Do not remember prompt answers Default: false 38 | --skip-install # Do not automatically install dependencies Default: false 39 | -a, --all # Ask all questions Default: false 40 | -y, --yes # Skip some questions, like $ npm init -y Default: false 41 | 42 | Arguments: 43 | name # module name 44 | If provided the module will be created inside .// 45 | otherwise it will be created in the current directory 46 | 47 | Examples: 48 | 49 | $ yo mnm 50 | $ yo mnm myAwesomeModule 51 | 52 | Type: String Required: false 53 | ``` 54 | 55 | Example 56 | 57 | ```sh 58 | $ yo mnm -y 59 | create package.json 60 | create README.md 61 | create .gitignore 62 | create src/index.js 63 | create test/index.js 64 | create .travis.yml 65 | create .babelrc 66 | create rollup.config.js 67 | ``` 68 | 69 | ## Features 70 | 71 | - Made out of many other generators, the main generator only creates a [`package.json` file](https://github.com/maurizzzio/generator-mnm/blob/master/generators/app/index.js#L225-L240) and a [minimal `.gitignore` file](https://github.com/maurizzzio/generator-mnm/blob/master/generators/app/index.js#L246-L248) 72 | - Composable, since the logic to create the README, cli and other files is on their own subgenerator 73 | - [Babel](https://babeljs.io) transpiles the code/tests 74 | - [standard](http://standardjs.com/) to lint the code 75 | - [ava](https://github.com/sindresorhus/ava) for testing 76 | - [yargs](https://github.com/bcoe/yargs) to parse cli arguments (optional) 77 | - [rollup](https://github.com/rollup/rollup) to create a common js compatible bundle 78 | - npm scripts as the build system 79 | 80 | ## Example 81 | 82 | Check [https://github.com/maurizzzio/generator-mnm-example](https://github.com/maurizzzio/generator-mnm-example) 83 | 84 | ## List of npm scripts included 85 | 86 | Common tasks 87 | 88 | | task | description | 89 | | ----- | --- | 90 | | `npm test` | `ava` | 91 | | `npm run build` | `rollup --config`| 92 | | `npm run lint` | `standard` | 93 | | `npm run clean` | Removes all the files inside `dist/`| 94 | 95 | Watching files 96 | 97 | | task | description | 98 | | --- | --- | 99 | | `npm run test:watch` | Same as `npm test` but with ` --watch` | 100 | | `npm run build:watch` | Same as `npm run build` but with ` --watch` | 101 | 102 | Pre/Post hooks 103 | 104 | | Task | description | 105 | | --- | --- | 106 | | `npm run prebuild` | Run before `build`, `npm clean -s && npm lint -s` | 107 | | `npm run preversion` | Run before `version`, `npm run build` | 108 | 109 | ### Useful npm commands that you should know 110 | 111 | - `npm version major|minor|patch` bumps the package version 112 | - `npm run` lists all available scripts 113 | 114 | ## Why? 115 | 116 | This project is heavily inspired by [this article by Keith Cirkel][stop-using-grunt-gulp] where he describes that the existing build system tools attempt to solve the problems that exist among them "covering up the inadequacies of the other tools while also surfacing their own". 117 | 118 | [James Halliday](https://www.npmjs.com/~substack) who is the creator of many awesome packages like `browserify` and `tape` also wrote an article where he points out that the command `npm run` is "perfectly adequate for everything while maintaining a very tiny configuration footprint." 119 | 120 | ### Articles to read: 121 | 122 | - [Why we should stop using grunt][stop] 123 | - [How to use npm as a build tool][how-to] 124 | - [Task automation with run][task-automation] 125 | - [Choose grunt, gulp or npm][choose] 126 | 127 | ### Inspiration projects 128 | 129 | - https://github.com/yeoman/generator-node 130 | - https://github.com/vinniegarcia/ES6-module-starter 131 | - https://github.com/sindresorhus/generator-nm 132 | - https://github.com/bucaran/generator-rise 133 | - https://github.com/iamstarkov/generator-zen 134 | - https://github.com/keithamus/npm-scripts-example 's awesome `package.json` file 135 | 136 | I'd like to thank [iamstarkov](https://github.com/iamstarkov) for his awesome work on generators that are actually composable 137 | 138 | ## Composability 139 | 140 | Just plug in any of the subgenerators or the `app` generator itself on your generator 141 | 142 |
143 | 144 |
145 | 146 | Generators used in this project 147 | 148 | - [generator-babel](https://github.com/iamstarkov/generator-babel) 149 | - [generator-git-init](https://github.com/iamstarkov/generator-git-init) 150 | - [generator-license](https://github.com/jozefizso/generator-license) 151 | - [generator-mnm/generators/src](./generators/src) 152 | - [generator-mnm/generators/test](./generators/test) 153 | - [generator-mnm/generators/cli](./generators/cli) 154 | - [generator-mnm/generators/readme](./generators/readme) 155 | 156 | ## Workflow 157 | 158 | ```sh 159 | # equivalent to npm init -y 160 | yo mnm -y 161 | # see https://www.npmjs.com/package/ghrepo 162 | ghrepo -m "initial commit" 163 | # see https://www.npmjs.com/package/travisjs 164 | travisjs hook # or travis enable with the travis gem 165 | 166 | # if a cli is needed 167 | yo mnm:cli 168 | ``` 169 | 170 | ## Development 171 | 172 | - `npm test` 173 | - `npm test:ci` run the tests (open `./test/ci/.tmp` to see a generated) 174 | 175 | ## License 176 | 177 | 2015-2016 MIT © [Mauricio Poppe](http://maurizzzio.com) 178 | 179 | [stop-using-grunt-gulp]: http://blog.keithcirkel.co.uk/why-we-should-stop-using-grunt/ 180 | [stop]: http://blog.keithcirkel.co.uk/why-we-should-stop-using-grunt/ 181 | [how-to]: http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/ 182 | [task-automation]: http://substack.net/task_automation_with_npm_run 183 | [choose]: http://ponyfoo.com/articles/choose-grunt-gulp-or-npm 184 | 185 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit with non-zero exit code on failure 4 | set -e 5 | 6 | # Taken from https://medium.com/philosophy-logic/publishing-gh-pages-with-travis-ci-53a8270e87db 7 | 8 | cd test/ci/.tmp 9 | git config user.name "Travis CI" 10 | git add . 11 | git commit -m "[travis build #$TRAVIS_JOB_NUMBER] Automatic deploy from https://travis-ci.org/maurizzzio/generator-mnm" 12 | git push --force "https://${GH_TOKEN}@${GH_REF}" master > /dev/null 2>&1 13 | 14 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var defined = require('defined') 3 | var extend = require('extend') 4 | var toCase = require('to-case') 5 | var githubUsername = require('github-username') 6 | var normalizeUrl = require('normalize-url') 7 | var isUrl = require('is-url') 8 | var mkdirp = require('mkdirp') 9 | 10 | var Base = require('../base') 11 | 12 | module.exports = Base.extend({ 13 | constructor: function () { 14 | Base.apply(this, arguments) 15 | 16 | this.argument('name', { 17 | type: String, 18 | required: false, 19 | desc: [ 20 | 'module name', 21 | 'If provided the module will be created inside ./myAwesomeModule/', 22 | 'otherwise it will be created in the current directory', 23 | '', 24 | 'Examples:', 25 | '', 26 | ' $ yo mnm', 27 | ' $ yo mnm myAwesomeModule', 28 | '', 29 | '' 30 | ].join('\n ') 31 | }) 32 | 33 | this.option('all', { 34 | type: Boolean, 35 | required: false, 36 | alias: 'a', 37 | default: false, 38 | desc: 'Ask all questions' 39 | }) 40 | 41 | this.option('yes', { 42 | type: Boolean, 43 | required: false, 44 | alias: 'y', 45 | default: false, 46 | desc: 'Skip some questions, like $ npm init -y' 47 | }) 48 | 49 | // TODO: performant npm 50 | // this.option('performant', { 51 | // type: Boolean, 52 | // required: false, 53 | // alias: 'p', 54 | // default: false, 55 | // desc: 'Install with pnpm instead of npm, make sure you have pnpm installed' 56 | // }) 57 | }, 58 | 59 | initializing: function () { 60 | this.savedAnswers = this._globalConfig.getAll().promptValues || {} 61 | this.shouldSkipAll = this.options.yes 62 | this.shouldAskAll = this.options.all 63 | var defaults = extend({}, this.savedAnswers, { 64 | moduleName: toCase.slug(this.name || this.appname), 65 | moduleDescription: '', 66 | moduleKeywords: '', 67 | moduleLicense: 'MIT', 68 | coverage: true, 69 | // additional not configurable props 70 | src: 'src/', 71 | dist: 'dist/', 72 | test: 'test/' 73 | }) 74 | this.props = extend({}, defaults) 75 | if (this.shouldSkipAll && this.shouldAskAll) { 76 | this.log('You have chosen to ask both "all" and "minimum" questions!\n') 77 | return 78 | } 79 | }, 80 | 81 | _checkEmpty: function (message) { 82 | return function (v) { 83 | if (!v.length) { return message } 84 | return true 85 | } 86 | }, 87 | 88 | _checkUrl: function (urlMessage) { 89 | return function (v) { 90 | if (v.length && !isUrl(normalizeUrl(v))) return urlMessage 91 | return true 92 | } 93 | }, 94 | 95 | _shouldAskUserInfo: function (prop) { 96 | return this.shouldAskAll || !defined(this.savedAnswers[prop]) 97 | }, 98 | 99 | prompting: { 100 | userInfo: function () { 101 | var prompts = [{ 102 | name: 'name', 103 | message: 'Your name:', 104 | when: this._shouldAskUserInfo('name'), 105 | validate: this._checkEmpty('Your name is required'), 106 | store: true 107 | }, { 108 | name: 'email', 109 | message: 'Your email:', 110 | when: this._shouldAskUserInfo('email'), 111 | validate: this._checkEmpty('Your email is required'), 112 | store: true 113 | }, { 114 | name: 'website', 115 | message: 'Your website:', 116 | when: this._shouldAskUserInfo('website'), 117 | validate: this._checkUrl('The input is not a valid url'), 118 | filter: function (v) { 119 | if (v.indexOf('.') === -1) return v 120 | return normalizeUrl(v) 121 | }, 122 | required: false, 123 | store: true 124 | }] 125 | 126 | var done = this.async() 127 | this.prompt(prompts, function (props) { 128 | extend(this.props, props) 129 | if (this.props.website) { 130 | this.props.website = normalizeUrl(this.props.website) 131 | } 132 | done() 133 | }.bind(this)) 134 | }, 135 | 136 | askForGithubAccount: function () { 137 | var self = this 138 | var done = this.async() 139 | githubUsername(this.props.email, function (err, username) { 140 | if (err) throw (err) 141 | self.prompt({ 142 | name: 'githubUsername', 143 | message: 'Your github username:', 144 | when: self._shouldAskUserInfo('githubUsername'), 145 | store: true 146 | }, function (answers) { 147 | extend(self.props, answers) 148 | done() 149 | }) 150 | }) 151 | }, 152 | 153 | moduleInfo: function () { 154 | var self = this 155 | var done = this.async() 156 | this.prompt([{ 157 | name: 'moduleName', 158 | message: 'Module name:', 159 | default: this.props.moduleName, 160 | validate: this._checkEmpty('Module name required'), 161 | when: !this.shouldSkipAll, 162 | filter: function (v) { 163 | return toCase.slug(v || '') 164 | } 165 | }, { 166 | name: 'moduleDescription', 167 | message: 'Module description:', 168 | validate: this._checkEmpty('Module description required'), 169 | when: !this.shouldSkipAll 170 | }, { 171 | name: 'moduleKeywords', 172 | message: 'Module keywords (comma to split):', 173 | when: !this.shouldSkipAll, 174 | filter: function (value) { 175 | return (value || '').split(',') 176 | .map(function (el) { return el.trim() }) 177 | .filter(Boolean) 178 | } 179 | }, { 180 | name: 'moduleLicense', 181 | message: 'License:', 182 | default: this.props.moduleLicense, 183 | when: !this.shouldSkipAll 184 | }], function (answers) { 185 | extend(self.props, answers) 186 | done() 187 | }) 188 | }, 189 | 190 | addOns: function () { 191 | // additional stuff 192 | // - cli 193 | // - code coverage 194 | var prompts = [{ 195 | // type: 'confirm', 196 | // name: 'cli', 197 | // message: '❯ do you need a cli?', 198 | // when: this.options.cli === undefined, 199 | // default: false 200 | // }, { 201 | type: 'confirm', 202 | name: 'coverage', 203 | message: 'Do you need code coverage?', 204 | when: !this.shouldSkipAll, 205 | default: this.props.coverage 206 | }] 207 | var done = this.async() 208 | this.prompt(prompts, function (answers) { 209 | extend(this.props, answers) 210 | done() 211 | }.bind(this)) 212 | } 213 | }, 214 | 215 | writing: { 216 | pkg: function () { 217 | if (this.name) { 218 | // if the argument `name` is given create the project inside it 219 | mkdirp(this.props.moduleName) 220 | this.destinationRoot(this.destinationPath(this.props.moduleName)) 221 | } 222 | 223 | // check if there's an existing package.json 224 | var currentPkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 225 | var pkg = { 226 | name: this.props.moduleName, 227 | version: '0.0.0', 228 | description: this.props.moduleDescription, 229 | license: this.props.moduleLicense, 230 | author: { 231 | name: this.props.name, 232 | email: this.props.email, 233 | url: this.props.website 234 | }, 235 | main: this.props.dist + this.props.moduleName + '.js', 236 | module: this.props.dist + this.props.moduleName + '.mjs', 237 | 'jsnext:main': this.props.dist + this.props.moduleName + '.mjs', 238 | keywords: this.props.moduleKeywords, 239 | repository: this.props.githubUsername + '/' + this.props.moduleName, 240 | scripts: {}, 241 | dependencies: {} 242 | } 243 | 244 | // Let's extend package.json so we're not overwriting user previous fields 245 | this.fs.writeJSON('package.json', extend(true, pkg, currentPkg)) 246 | }, 247 | 248 | gitignore: function () { 249 | this._gitignore(['.DS_Store', 'node_modules']) 250 | } 251 | }, 252 | 253 | default: function () { 254 | // git init 255 | this.composeWith('git-init', {}, { 256 | local: require.resolve('generator-git-init/generators/app') 257 | }) 258 | 259 | // src/index.js and test/index.js 260 | this.composeWith('mnm:src', { 261 | options: { 262 | src: this.props.src, 263 | dist: this.props.dist, 264 | 'skip-install': this.options['skip-install'] 265 | } 266 | }, { local: require.resolve('../src') }) 267 | 268 | this.composeWith('mnm:test', { 269 | options: { 270 | src: this.props.src, 271 | test: this.props.test, 272 | coverage: this.props.coverage, 273 | 'skip-install': this.options['skip-install'] 274 | } 275 | }, { local: require.resolve('../test') }) 276 | 277 | // TODO: make the generator receive a license field 278 | // if (!this.shouldSkipAll) { 279 | // this.composeWith('license', { 280 | // options: { 281 | // name: this.props.name, 282 | // email: this.props.email, 283 | // website: this.props.website 284 | // }, 285 | // prompts: {license: 'MIT'} 286 | // }, { local: require.resolve('generator-license/app') }) 287 | // } 288 | 289 | if (!this.fs.exists(this.destinationPath('README.md'))) { 290 | this.composeWith('mnm:readme', { 291 | options: { 292 | githubUsername: this.props.githubUsername, 293 | codecov: this.props.coverage, 294 | yes: this.shouldSkipAll 295 | } 296 | }, { local: require.resolve('../readme') }) 297 | } 298 | } 299 | 300 | }) 301 | -------------------------------------------------------------------------------- /generators/base.js: -------------------------------------------------------------------------------- 1 | var yeoman = require('yeoman-generator') 2 | var extend = require('extend') 3 | var sortedObject = require('sorted-object') 4 | var depsObject = require('deps-object') 5 | var yaml = require('yamljs') 6 | 7 | module.exports = yeoman.Base.extend({ 8 | _saveDepsToPkg: function (deps) { 9 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 10 | var currentDeps = pkg.devDependencies || {} 11 | var mergedDeps = extend({}, currentDeps, deps) 12 | var sortedDeps = sortedObject(mergedDeps) 13 | pkg.devDependencies = sortedDeps 14 | this.fs.writeJSON(this.destinationPath('package.json'), pkg) 15 | }, 16 | 17 | _saveDeps: function (deps) { 18 | return depsObject(deps) 19 | .then(function (devDependencies) { 20 | this._saveDepsToPkg(devDependencies) 21 | }.bind(this)) 22 | .catch(function (err) { throw err }) 23 | }, 24 | 25 | _travis: function (additional) { 26 | var travisPath = this.destinationPath('.travis.yml') 27 | var existing = this.fs.exists(travisPath) 28 | ? yaml.parse(this.fs.read(travisPath)) 29 | : {} 30 | var result = Object.assign({ 31 | language: 'node_js', 32 | node_js: ['stable'] 33 | }, existing, additional) 34 | 35 | this.fs.write( 36 | this.destinationPath('.travis.yml'), 37 | yaml.stringify(result, 3, 2) 38 | ) 39 | }, 40 | 41 | _gitignore: function (ignores) { 42 | var giPath = this.destinationPath('.gitignore') 43 | var file = this.fs.read(giPath, { defaults: '' }) 44 | ignores.forEach(function (v) { 45 | if (file.indexOf(v) === -1) { 46 | file += v + '\n' 47 | } 48 | }) 49 | this.fs.write(giPath, file) 50 | } 51 | }) 52 | -------------------------------------------------------------------------------- /generators/cli/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var toCase = require('to-case') 3 | var relative = require('relative') 4 | var defined = require('defined') 5 | 6 | var Base = require('../base') 7 | 8 | module.exports = Base.extend({ 9 | constructor: function () { 10 | Base.apply(this, arguments) 11 | 12 | this.option('in', { 13 | type: String, 14 | required: false, 15 | defaults: 'bin/index.js', 16 | desc: 'The location of cli source code' 17 | }) 18 | 19 | this.option('out', { 20 | type: String, 21 | required: false, 22 | defaults: 'bin/index.es5.js', 23 | desc: 'The path to your cli written in the bin property of package.json' 24 | }) 25 | 26 | this.option('src', { 27 | type: String, 28 | required: false, 29 | defaults: 'dist/index.js', 30 | desc: "The location of the project's source file" 31 | }) 32 | }, 33 | 34 | writing: { 35 | pkg: function () { 36 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 37 | pkg.scripts = pkg.scripts || {} 38 | pkg.scripts['build:cli'] = pkg.scripts['build:cli'] || 'babel ' + this.options.in + ' -o ' + this.options.out 39 | 40 | // pkg.bin value 41 | // - pkg.bin if pkb.bin was already in package.json 42 | // - options.bin (an override to options.cli, useful when the cli file 43 | // is transpiled) 44 | pkg.bin = defined(pkg.bin, this.options.out, this.options.in) 45 | this.fs.writeJSON(this.destinationPath('package.json'), pkg) 46 | }, 47 | 48 | pkgDeps: function () { 49 | return this._saveDeps(['yargs']) 50 | }, 51 | 52 | cli: function () { 53 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 54 | var cliPath = this.options.in 55 | var srcPath = this.options.src 56 | var relativePath = relative(cliPath, srcPath) 57 | if (relativePath[0] !== '.') { 58 | relativePath = './' + relativePath 59 | } 60 | 61 | this.fs.copyTpl( 62 | this.templatePath('cli.tpl'), 63 | this.destinationPath(cliPath), { 64 | camelName: toCase.camel(pkg.name || this.appname), 65 | indexPath: relativePath 66 | } 67 | ) 68 | } 69 | }, 70 | 71 | install: function () { 72 | if (!this.options['skip-install']) { 73 | this.npmInstall() 74 | } 75 | } 76 | }) 77 | -------------------------------------------------------------------------------- /generators/cli/templates/cli.tpl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict' 3 | 4 | import yargs from 'yargs' 5 | 6 | import <%= camelName %> from '<%= indexPath %>' 7 | 8 | yargs 9 | .usage('Usage: $0 [an argument]') 10 | .demand(1) 11 | 12 | <%= camelName %>(yargs.argv) 13 | 14 | -------------------------------------------------------------------------------- /generators/readme/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var toCase = require('to-case') 3 | var extend = require('extend') 4 | var parseAuthor = require('parse-author') 5 | 6 | var Base = require('../base') 7 | 8 | module.exports = Base.extend({ 9 | constructor: function () { 10 | Base.apply(this, arguments) 11 | 12 | this.option('codecov', { 13 | type: Boolean, 14 | required: false, 15 | default: false, 16 | desc: 'Include the codecov badge' 17 | }) 18 | }, 19 | 20 | initializing: function () { 21 | this.shouldSkipAll = this.options.yes 22 | this.props = { 23 | badges: ['npm', 'travis', this.options.codecov && 'codecov'].filter(Boolean) 24 | } 25 | }, 26 | 27 | prompting: { 28 | badges: function () { 29 | var done = this.async() 30 | this.prompt({ 31 | type: 'checkbox', 32 | name: 'badges', 33 | message: 'Select the badges that you want in your README', 34 | choices: [ 35 | { name: 'npm' }, 36 | { name: 'travis' }, 37 | { name: 'codecov' }, 38 | { name: 'david' }, 39 | { name: 'downloads' } 40 | ], 41 | default: this.props.badges, 42 | when: !this.shouldSkipAll 43 | }, function (answers) { 44 | extend(this.props, answers) 45 | done() 46 | }.bind(this)) 47 | } 48 | }, 49 | 50 | writing: function () { 51 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 52 | var authorInfo 53 | if (pkg.author && typeof pkg.author === 'object') { 54 | authorInfo = pkg.author 55 | } else if (typeof pkg.author === 'string') { 56 | authorInfo = parseAuthor(pkg.author) 57 | } else { 58 | authorInfo = {} 59 | } 60 | 61 | // get githubUsername from repository field 62 | // assume for simplicity that the field has the form 63 | // 64 | // githubUsername/moduleName 65 | // 66 | var githubUsername = (pkg.repository || '').split('/')[0] 67 | 68 | extend(this.props, { 69 | name: authorInfo.name || '', 70 | email: authorInfo.email || '', 71 | website: authorInfo.url || '', 72 | githubUsername: githubUsername, 73 | moduleName: (pkg.name || this.appname), 74 | moduleDescription: pkg.description || '', 75 | moduleLicense: pkg.license || '' 76 | }) 77 | this.props.camelModuleName = toCase.camel(this.props.moduleName) 78 | this.fs.copyTpl( 79 | this.templatePath('README.tpl'), 80 | this.destinationPath('README.md'), 81 | this.props 82 | ) 83 | } 84 | }) 85 | 86 | -------------------------------------------------------------------------------- /generators/readme/templates/README.tpl: -------------------------------------------------------------------------------- 1 | <% 2 | var b = [] 3 | if (~badges.indexOf('npm')) b.push('[![NPM version][npm-image]][npm-url]') 4 | if (~badges.indexOf('travis')) b.push('[![Build Status][travis-image]][travis-url]') 5 | if (~badges.indexOf('codecov')) b.push('[![Codecov Status][codecov-image]][codecov-url]') 6 | if (~badges.indexOf('david')) b.push('[![Dependency Status][depstat-image]][depstat-url]') 7 | if (~badges.indexOf('downloads')) b.push('[![Downloads][download-image]][npm-url]') 8 | b.push('[![Standard][standard-image]][standard-url]') 9 | %> 10 | 11 | # <%= moduleName %> 12 | <%= b.join('\n') %> 13 | 14 | > <%= moduleDescription %> 15 | 16 | ## Install 17 | 18 | ```sh 19 | npm install --save <%= moduleName %> 20 | ``` 21 | 22 | ## Usage 23 | 24 | ```js 25 | import <%= camelModuleName %> from '<%= moduleName %>' 26 | 27 | <%= camelModuleName %>() 28 | ``` 29 | 30 | ## License 31 | 32 | <% if (moduleLicense) { %> <%= moduleLicense + " © " %> <% } %><%= "[" + name + "](" + website + ")" %> 33 | 34 | [npm-url]: https://npmjs.org/package/<%= moduleName %> 35 | [npm-image]: https://img.shields.io/npm/v/<%= moduleName %>.svg?style=flat 36 | 37 | [travis-url]: https://travis-ci.org/<%= githubUsername %>/<%= moduleName %> 38 | [travis-image]: https://img.shields.io/travis/<%= githubUsername %>/<%= moduleName %>.svg?style=flat 39 | 40 | [codecov-url]: https://codecov.io/github/<%= githubUsername %>/<%= moduleName %> 41 | [codecov-image]: https://img.shields.io/codecov/c/github/<%= githubUsername %>/<%= moduleName %>.svg?style=flat 42 | 43 | [depstat-url]: https://david-dm.org/<%= githubUsername %>/<%= moduleName %> 44 | [depstat-image]: https://david-dm.org/<%= githubUsername %>/<%= moduleName %>.svg?style=flat 45 | 46 | [download-image]: http://img.shields.io/npm/dm/<%= moduleName %>.svg?style=flat 47 | 48 | [standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat 49 | [standard-url]: http://standardjs.com/ 50 | 51 | -------------------------------------------------------------------------------- /generators/src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var path = require('path') 3 | var toCase = require('to-case') 4 | 5 | var Base = require('../base') 6 | 7 | module.exports = Base.extend({ 8 | constructor: function () { 9 | Base.apply(this, arguments) 10 | 11 | this.option('src', { 12 | type: String, 13 | required: false, 14 | defaults: 'src/', 15 | desc: 'Source folder' 16 | }) 17 | 18 | this.option('dist', { 19 | type: String, 20 | required: false, 21 | defaults: 'dist/', 22 | desc: 'Dist folder (after compilation with Babel)' 23 | }) 24 | }, 25 | 26 | writing: { 27 | pkgScripts: function () { 28 | function setTask (name, task) { 29 | scripts[name] = scripts[name] || task 30 | } 31 | 32 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 33 | 34 | var scripts = pkg.scripts || {} 35 | setTask('clean', 'rimraf ' + this.options.dist + ' && mkdirp ' + this.options.dist) 36 | setTask('lint', 'standard') 37 | setTask('changelog', 'conventional-changelog -p eslint -i CHANGELOG.md -s -r 0') 38 | setTask('prebuild', 'npm run clean -s && npm run lint -s') 39 | setTask('build', 'rollup --config') 40 | setTask('build:watch', 'npm run build -- --watch') 41 | // instead of runnning this on prepublish which doesn't work as expecte on 42 | // npm@3 run it on preversion, this is because it's highly unlikely to do 43 | // something after `npm version` 44 | setTask('preversion', 'npm run build') 45 | pkg.scripts = scripts 46 | 47 | // standard ignores 48 | // no need to ignore this.options.dist since it honors .gitignore 49 | 50 | // `files` is like !.npmignore, i.e. the strategy is to ignore everything 51 | // but what's included on this field 52 | // 53 | // include dist/ (ignored in .gitignore but added through `files`) 54 | // include src/ (jsnext:main compatibility) 55 | pkg.files = pkg.files || [] 56 | 57 | var files = [this.options.src, this.options.dist] 58 | files.forEach(function (path) { 59 | if (pkg.files.indexOf(path) === -1) { 60 | pkg.files.push(path) 61 | } 62 | }) 63 | this.fs.writeJSON(this.destinationPath('package.json'), pkg) 64 | }, 65 | 66 | pkgDeps: function () { 67 | return this._saveDeps([ 68 | 'rimraf', 'mkdirp', 'standard', 'conventional-changelog', 69 | 'rollup', 'rollup-plugin-babel', 'rollup-watch', 'babelrc-rollup' 70 | ]) 71 | }, 72 | 73 | templates: function () { 74 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 75 | var srcPath = path.join(this.options.src, 'index.js') 76 | 77 | // copy index.tpl as srcPath 78 | // e.g. src/index.js 79 | this.fs.copyTpl( 80 | this.templatePath('index.tpl'), 81 | this.destinationPath(srcPath), {} 82 | ) 83 | 84 | // copy rollup.config.tpl to rollup.config.js 85 | this.fs.copyTpl( 86 | this.templatePath('rollup.config.tpl'), 87 | this.destinationPath('rollup.config.js'), { 88 | srcPath: srcPath, 89 | moduleName: toCase.camel(pkg.name || this.appname) 90 | } 91 | ) 92 | }, 93 | 94 | gitignore: function () { 95 | this._gitignore([this.options.dist]) 96 | } 97 | }, 98 | 99 | default: function () { 100 | // using my own .travis generator because the other one force defaults 101 | this._travis({ 102 | script: 'npm run build' 103 | }) 104 | 105 | this.composeWith('babel', { 106 | options: { 107 | 'skip-install': this.options['skip-install'], 108 | config: { 109 | plugins: ['external-helpers'] 110 | } 111 | } 112 | }, { local: require.resolve('generator-babel/generators/app') }) 113 | }, 114 | 115 | install: function () { 116 | if (!this.options['skip-install']) { 117 | this.npmInstall() 118 | } 119 | } 120 | }) 121 | -------------------------------------------------------------------------------- /generators/src/templates/index.tpl: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | export default awesome => { 4 | return `everything is <%= "${awesome}" %>` 5 | } 6 | 7 | -------------------------------------------------------------------------------- /generators/src/templates/rollup.config.tpl: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import babelrc from 'babelrc-rollup' 3 | 4 | let pkg = require('./package.json') 5 | let external = Object.keys(pkg.dependencies) 6 | 7 | export default { 8 | entry: '<%= srcPath %>', 9 | plugins: [ babel(babelrc()) ], 10 | external: external, 11 | targets: [{ 12 | dest: pkg['main'], 13 | format: 'cjs' 14 | }, { 15 | dest: pkg['jsnext:main'], 16 | format: 'es' 17 | }] 18 | } 19 | 20 | -------------------------------------------------------------------------------- /generators/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var path = require('path') 3 | var toCase = require('to-case') 4 | var relative = require('relative') 5 | 6 | var Base = require('../base') 7 | 8 | module.exports = Base.extend({ 9 | constructor: function () { 10 | Base.apply(this, arguments) 11 | 12 | this.option('src', { 13 | type: String, 14 | required: false, 15 | defaults: 'src/', 16 | desc: 'Source code folder (relative to the project root)' 17 | }) 18 | 19 | this.option('test', { 20 | type: String, 21 | required: false, 22 | defaults: 'test/', 23 | desc: 'Source code folder for the tests (relative to the project root)' 24 | }) 25 | 26 | this.option('coverage', { 27 | type: Boolean, 28 | required: false, 29 | defaults: false, 30 | desc: 'Include code coverage script?' 31 | }) 32 | }, 33 | 34 | writing: { 35 | pkg: function () { 36 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 37 | pkg.scripts = pkg.scripts || {} 38 | 39 | // force the inclusion of these scripts 40 | // this is because initially "test": "echo no tests" 41 | pkg.scripts.test = 'ava' 42 | pkg.scripts['test:watch'] = 'npm test -- --watch' 43 | if (this.options.coverage) { 44 | // note that this will only be run on a CI server 45 | pkg.scripts.coverage = pkg.scripts.coverage || 'nyc npm test && nyc report --reporter=text-lcov > coverage.lcov && codecov' 46 | } 47 | 48 | // ava configuration 49 | pkg.ava = pkg.ava || {} 50 | pkg.ava.require = ['babel-register'] 51 | 52 | this.fs.writeJSON('package.json', pkg) 53 | }, 54 | 55 | pkgDeps: function () { 56 | return this._saveDeps(['ava']) 57 | }, 58 | 59 | gitignore: function () { 60 | if (this.options.coverage) { 61 | return this._gitignore(['coverage', '.nyc_output']) 62 | } 63 | }, 64 | 65 | templates: function () { 66 | var pkg = this.fs.readJSON(this.destinationPath('package.json'), {}) 67 | var testPath = path.join(this.options.test, 'index.js') 68 | var srcPath = path.join(this.options.src, 'index.js') 69 | var relativePath = relative(testPath, srcPath) 70 | if (relativePath[0] !== '.') { 71 | relativePath = './' + relativePath 72 | } 73 | 74 | this.fs.copyTpl( 75 | this.templatePath('test.tpl'), 76 | this.destinationPath(testPath), { 77 | camelName: toCase.camel(pkg.name || this.appname), 78 | // computes the relative from `test` to `index` 79 | // e.g. from test/ to src/index.js = ../src/index.js 80 | indexPath: relativePath 81 | } 82 | ) 83 | } 84 | }, 85 | 86 | default: function () { 87 | if (this.options.coverage) { 88 | this._travis({ 89 | before_install: 'npm install codecov && npm install nyc', 90 | after_success: 'npm run coverage' 91 | }) 92 | } 93 | }, 94 | 95 | install: function () { 96 | if (!this.options['skip-install']) { 97 | this.npmInstall() 98 | } 99 | } 100 | }) 101 | -------------------------------------------------------------------------------- /generators/test/templates/test.tpl: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import <%= camelName %> from '<%= indexPath %>' 4 | import test from 'ava' 5 | 6 | test('awesome:test', t => { 7 | const message = 'everything is awesome' 8 | t.is(<%= camelName %>('awesome'), message, message) 9 | }) 10 | 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | app: require.resolve('./generators/app'), 3 | boilerplate: require.resolve('./generators/boilerplate'), 4 | readme: require.resolve('./generators/readme'), 5 | rollup: require.resolve('./generators/rollup'), 6 | git: require.resolve('./generators/git'), 7 | cli: require.resolve('./generators/cli') 8 | } 9 | 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-mnm", 3 | "version": "0.6.0", 4 | "description": "Create node modules writing ES6 today compiled with Babel, tested with ava and linted with standard on top of npm scripts Create node modules with es6, test with tape on top of npm scripts", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "repository": "maurizzzio/generator-mnm", 8 | "author": { 9 | "name": "Mauricio Poppe", 10 | "url": "https://github.com/maurizzzio" 11 | }, 12 | "engines": { 13 | "node": ">=4" 14 | }, 15 | "scripts": { 16 | "lint": "standard", 17 | "test": "mocha test/generators/*.js", 18 | "test:ci": "mocha test/ci/*.js" 19 | }, 20 | "files": [ 21 | "generators", 22 | "index.js" 23 | ], 24 | "keywords": [ 25 | "mnm", 26 | "yeoman-generator", 27 | "boilerplate", 28 | "es6", 29 | "node", 30 | "module", 31 | "starter", 32 | "yeoman", 33 | "scaffold", 34 | "node-module", 35 | "npm scripts", 36 | "generator", 37 | "yo" 38 | ], 39 | "dependencies": { 40 | "defined": "^1.0.0", 41 | "deps-object": "^2.0.2", 42 | "extend": "^3.0.0", 43 | "generator-babel": "^2.0.2", 44 | "generator-git-init": "^1.0.4", 45 | "generator-license": "^3.1.1", 46 | "github-username": "^2.1.0", 47 | "is-url": "^1.2.1", 48 | "mkdirp": "^0.5.1", 49 | "normalize-url": "^1.5.2", 50 | "parse-author": "^1.0.0", 51 | "relative": "^3.0.2", 52 | "sorted-object": "^2.0.0", 53 | "to-case": "^2.0.0", 54 | "yamljs": "^0.2.8", 55 | "yeoman-generator": "^0.22.6" 56 | }, 57 | "devDependencies": { 58 | "async-series": "0.0.1", 59 | "mocha": "^2.4.5", 60 | "mockery": "^1.4.0", 61 | "pinkie-promise": "^2.0.1", 62 | "standard": "^7.0.1", 63 | "yeoman-assert": "^2.2.1", 64 | "yeoman-test": "^1.4.0" 65 | }, 66 | "standard": { 67 | "env": [ 68 | "mocha" 69 | ] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/ci/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var path = require('path') 4 | var assert = require('yeoman-assert') 5 | var helpers = require('yeoman-test') 6 | var exec = require('child_process').exec 7 | var series = require('async-series') 8 | 9 | describe('generator-mnm on CI', function () { 10 | this.timeout(600000) 11 | 12 | function handleProcess (command, done) { 13 | exec(command, function (err) { 14 | if (err) { return done(err) } 15 | done(null) 16 | }) 17 | } 18 | 19 | before(function (done) { 20 | helpers.run(path.join(__dirname, '../../generators/app')) 21 | .inDir(path.join(__dirname, '.tmp')) 22 | .withOptions({ skipInstall: false }) 23 | .withPrompts({ 24 | name: 'Mauricio Poppe', 25 | email: 'foo@bar.com', 26 | url: 'http://maurizzzio.com', 27 | githubUsername: 'maurizzzio', 28 | moduleName: 'generator-mnm-example', 29 | moduleDescription: 'An example of the generator https://github.com/maurizzzio/generator-mnm', 30 | moduleLicense: 'MIT', 31 | moduleKeywords: ['generator', 'example', 'mnm'], 32 | // addons 33 | coverage: true, 34 | // generator-license/app 35 | // license: 'MIT', 36 | // ./generators/readme 37 | badges: ['npm', 'travis', 'codecov', 'david', 'downloads'] 38 | }) 39 | .on('end', done) 40 | }) 41 | 42 | describe('with default options', function () { 43 | it('should have the required files in package.json', function () { 44 | assert.file('package.json') 45 | assert.JSONFileContent('package.json', { 46 | name: 'generator-mnm-example', 47 | version: '0.0.0', 48 | main: 'dist/generator-mnm-example.js', 49 | module: 'dist/generator-mnm-example.mjs', 50 | 'jsnext:main': 'dist/generator-mnm-example.mjs', 51 | license: 'MIT' 52 | }) 53 | }) 54 | 55 | it('should have the required contents in .babelrc', function () { 56 | assert.file('.babelrc') 57 | assert.JSONFileContent('.babelrc', { 58 | presets: ['es2015'] 59 | }) 60 | }) 61 | 62 | it('should have the required contents in .travis.yml', function () { 63 | assert.file('.travis.yml') 64 | assert.fileContent('.travis.yml', 'npm run build') 65 | assert.fileContent('.travis.yml', 'npm run coverage') 66 | }) 67 | 68 | it('should execute package.json scripts', function (done) { 69 | series([ 70 | function (cb) { handleProcess('npm run build', cb) }, 71 | function (cb) { handleProcess('npm test', cb) } 72 | ], done) 73 | }) 74 | 75 | it('should be compatible with commonjs\' require', function (done) { 76 | handleProcess('node -e "require(\'./dist/generator-mnm-example.js\')(\'awesome\')"', done) 77 | }) 78 | }) 79 | }) 80 | 81 | -------------------------------------------------------------------------------- /test/generators/app.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var path = require('path') 4 | var extend = require('extend') 5 | var assert = require('yeoman-assert') 6 | var helpers = require('yeoman-test') 7 | var answers = require('../helpers/answers.json') 8 | 9 | describe('node-mnm:app', function () { 10 | this.timeout(20000) 11 | 12 | require('../helpers/set-up-mockery')(before, after) 13 | 14 | describe('running on new project', function () { 15 | before(function () { 16 | return helpers.run(path.join(__dirname, '../../generators/app')) 17 | .inDir(path.join(__dirname, '.tmp')) 18 | .withPrompts(extend(answers, {})) 19 | .toPromise() 20 | }) 21 | 22 | it('creates files', function () { 23 | assert.file([ 24 | '.travis.yml', 25 | '.gitignore', 26 | 'README.md', 27 | 'src/index.js', 28 | 'test/index.js' 29 | ]) 30 | }) 31 | 32 | it('creates package.json', function () { 33 | assert.file('package.json') 34 | assert.JSONFileContent('package.json', { 35 | name: answers.moduleName, 36 | version: '0.0.0', 37 | description: answers.moduleDescription, 38 | license: answers.moduleLicense, 39 | author: { 40 | name: answers.name, 41 | email: answers.email, 42 | url: 'http://' + answers.website 43 | }, 44 | main: 'dist/' + answers.moduleName + '.js', 45 | module: 'dist/' + answers.moduleName + '.mjs', 46 | 'jsnext:main': 'dist/' + answers.moduleName + '.mjs', 47 | keywords: answers.moduleKeywords, 48 | repository: answers.githubUsername + '/' + answers.moduleName 49 | }) 50 | }) 51 | 52 | it('creates and fill contents in README.md', function () { 53 | assert.file('README.md') 54 | assert.fileContent('README.md', 'import generatorMnm from \'generator-mnm\'') 55 | assert.fileContent('README.md', '> A node module generator') 56 | assert.fileContent('README.md', 'npm install --save generator-mnm') 57 | assert.fileContent('README.md', 'MIT') 58 | assert.fileContent('README.md', '[Mauricio Poppe](http://maurizzzio.com)') 59 | assert.fileContent('README.md', '[travis-image]: https://img.shields.io/travis/maurizzzio/generator-mnm.svg') 60 | assert.fileContent('README.md', '[![Codecov Status][codecov-image]][codecov-url]') 61 | }) 62 | 63 | it('creates a valid .npmignore file', function () { 64 | assert.file('.gitignore') 65 | assert.fileContent('.gitignore', '.DS_Store') 66 | assert.fileContent('.gitignore', 'node_modules') 67 | assert.fileContent('.gitignore', 'dist/') 68 | assert.fileContent('.gitignore', '.nyc_output') 69 | assert.fileContent('.gitignore', 'coverage') 70 | }) 71 | }) 72 | }) 73 | -------------------------------------------------------------------------------- /test/generators/cli.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var assert = require('yeoman-assert') 3 | var helpers = require('yeoman-test') 4 | 5 | require('../helpers/set-up-mockery')(before, after) 6 | 7 | describe('mnm::cli', function () { 8 | this.timeout(10000) 9 | 10 | describe('cli with default options', function () { 11 | before(function () { 12 | return helpers.run(path.join(__dirname, '../../generators/cli')) 13 | .inDir(path.join(__dirname, '.tmp')) 14 | .toPromise() 15 | }) 16 | 17 | it('has a cli file', function () { 18 | assert.file('bin/index.js') 19 | }) 20 | 21 | it('has a valid bin path in package.json', function () { 22 | assert.file('package.json') 23 | assert.JSONFileContent('package.json', { 24 | bin: 'bin/index.es5.js' 25 | }) 26 | }) 27 | 28 | it('has a script to build the cli', function () { 29 | assert.fileContent('package.json', 'build:cli') 30 | assert.fileContent('package.json', 'babel bin/index.js -o bin/index.es5.js') 31 | }) 32 | 33 | it('has the correct file contents', function () { 34 | assert.file('bin/index.js') 35 | assert.fileContent('bin/index.js', '\'../dist/index.js\'') 36 | assert.fileContent('bin/index.js', '\'yargs\'') 37 | }) 38 | }) 39 | }) 40 | 41 | -------------------------------------------------------------------------------- /test/generators/readme.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var assert = require('yeoman-assert') 3 | var helpers = require('yeoman-test') 4 | 5 | require('../helpers/set-up-mockery')(before, after) 6 | 7 | describe('mnm::readme', function () { 8 | this.timeout(10000) 9 | describe('readme', function () { 10 | before(function () { 11 | return helpers.run(path.join(__dirname, '../../generators/readme')) 12 | .inDir(path.join(__dirname, '.tmp')) 13 | .toPromise() 14 | }) 15 | 16 | it('creates a readme file', function () { 17 | assert.file('README.md') 18 | }) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /test/generators/src.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var assert = require('yeoman-assert') 3 | var helpers = require('yeoman-test') 4 | 5 | require('../helpers/set-up-mockery')(before, after) 6 | 7 | describe('mnm::src', function () { 8 | this.timeout(10000) 9 | 10 | describe('with default options', function () { 11 | before(function () { 12 | return helpers.run(path.join(__dirname, '../../generators/src')) 13 | .inDir(path.join(__dirname, '.tmp')) 14 | .toPromise() 15 | }) 16 | 17 | it('creates a source file', function () { 18 | assert.file('src/index.js') 19 | assert.file('rollup.config.js') 20 | }) 21 | 22 | it('modifies package.json scripts field', function () { 23 | assert.fileContent('package.json', '"lint": "standard"') 24 | assert.fileContent('package.json', '"clean": "rimraf dist/ && mkdirp dist/"') 25 | assert.fileContent('package.json', '"prebuild": "npm run clean -s && npm run lint -s"') 26 | assert.fileContent('package.json', '"build": "rollup --config"') 27 | assert.fileContent('package.json', '"build:watch": "npm run build -- --watch"') 28 | }) 29 | 30 | it('modifies package.json files field', function () { 31 | assert.JSONFileContent('package.json', { 32 | files: ['src/', 'dist/'] 33 | }) 34 | }) 35 | 36 | it('modifies package.json devDependencies field', function () { 37 | assert.JSONFileContent('package.json', { 38 | // NOTE: this should be updated when mnm dependencies are updated 39 | devDependencies: { 40 | 'babel-cli': '6.6.5', 41 | 'babel-register': '6.7.2', 42 | 'babel-preset-es2015': '*', 43 | rimraf: '*', 44 | mkdirp: '*', 45 | standard: '*' 46 | } 47 | }) 48 | }) 49 | 50 | it('creates/modifies .gitignore', function () { 51 | assert.file('.gitignore') 52 | assert.fileContent('.gitignore', 'dist/') 53 | }) 54 | 55 | it('creates/modifies .travis.yml', function () { 56 | assert.file('.travis.yml') 57 | assert.fileContent('.travis.yml', 'script: \'npm run build\'') 58 | }) 59 | }) 60 | 61 | describe('with options', function () { 62 | before(function () { 63 | return helpers.run(path.join(__dirname, '../../generators/src')) 64 | .inDir(path.join(__dirname, '.tmp')) 65 | .withOptions({ 66 | src: 'lib/', 67 | dist: 'build/' 68 | }) 69 | .toPromise() 70 | }) 71 | 72 | it('creates a source file', function () { 73 | assert.file('lib/index.js') 74 | }) 75 | 76 | it('modifies package.json files field', function () { 77 | assert.JSONFileContent('package.json', { 78 | files: ['lib/', 'build/'] 79 | }) 80 | }) 81 | 82 | it('creates/modifies .gitignore', function () { 83 | assert.file('.gitignore') 84 | assert.fileContent('.gitignore', 'build/') 85 | }) 86 | 87 | it('modifies package.json scripts field', function () { 88 | assert.fileContent('package.json', '"build": "rollup --config"') 89 | }) 90 | }) 91 | }) 92 | -------------------------------------------------------------------------------- /test/generators/test.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var assert = require('yeoman-assert') 3 | var helpers = require('yeoman-test') 4 | 5 | describe('mnm::test', function () { 6 | this.timeout(10000) 7 | 8 | require('../helpers/set-up-mockery')(before, after) 9 | 10 | describe('test with default options', function () { 11 | before(function () { 12 | return helpers.run(path.join(__dirname, '../../generators/test')) 13 | .inDir(path.join(__dirname, '.tmp')) 14 | .toPromise() 15 | }) 16 | 17 | it('creates test/index.js', function () { 18 | assert.file('test/index.js') 19 | assert.fileContent('test/index.js', 'import test from \'ava\'') 20 | }) 21 | 22 | it('modifies package.json devDependencies field', function () { 23 | assert.JSONFileContent('package.json', { 24 | devDependencies: { 25 | ava: '*' 26 | } 27 | }) 28 | }) 29 | 30 | it('modifies package.json scripts field', function () { 31 | assert.fileContent('package.json', '"test": "ava"') 32 | assert.fileContent('package.json', '"test:watch": "npm test -- --watch"') 33 | assert.JSONFileContent('package.json', { 34 | ava: { require: ['babel-register'] } 35 | }) 36 | }) 37 | }) 38 | 39 | describe('with coverage on', function () { 40 | before(function () { 41 | return helpers.run(path.join(__dirname, '../../generators/test')) 42 | .inDir(path.join(__dirname, '.tmp')) 43 | .withOptions({ coverage: true }) 44 | .toPromise() 45 | }) 46 | 47 | it('modifies package.json scripts field', function () { 48 | assert.fileContent('package.json', '"coverage": "nyc npm test && nyc report --reporter=text-lcov > coverage.lcov && codecov"') 49 | }) 50 | 51 | it('creates/modifies .gitignore', function () { 52 | assert.file('.gitignore') 53 | assert.fileContent('.gitignore', '.nyc_output') 54 | assert.fileContent('.gitignore', 'coverage') 55 | }) 56 | 57 | it('creates/modifies .travis.yml', function () { 58 | assert.file('.travis.yml') 59 | assert.fileContent('.travis.yml', 'before_install: \'npm install codecov && npm install nyc\'') 60 | assert.fileContent('.travis.yml', 'after_success: \'npm run coverage\'') 61 | }) 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /test/helpers/answers.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Mauricio Poppe", 3 | "website": "maurizzzio.com", 4 | "githubUsername": "maurizzzio", 5 | "moduleName": "generator-mnm", 6 | "moduleDescription": "A node module generator", 7 | "moduleKeywords": ["foo", "bar"], 8 | "moduleLicense": "MIT" 9 | } 10 | -------------------------------------------------------------------------------- /test/helpers/set-up-mockery.js: -------------------------------------------------------------------------------- 1 | var mockery = require('mockery') 2 | var helpers = require('yeoman-test') 3 | var Promise = require('pinkie-promise') 4 | 5 | module.exports = function (before, after) { 6 | before(function () { 7 | mockery.enable({ 8 | warnOnUnregistered: false 9 | }) 10 | 11 | mockery.registerMock('npm-name', function (name, cb) { 12 | cb(null, true) 13 | }) 14 | 15 | mockery.registerMock('github-username', function (name, cb) { 16 | cb(null, 'unicornUser') 17 | }) 18 | 19 | mockery.registerMock( 20 | require.resolve('generator-license/app'), 21 | helpers.createDummyGenerator() 22 | ) 23 | 24 | mockery.registerMock('deps-object', function (deps) { 25 | var obj = deps.reduce(function (o, v) { 26 | var tok = v.split('@') 27 | if (tok.length === 1) tok.push('*') 28 | o[tok[0]] = tok[1] 29 | return o 30 | }, {}) 31 | return Promise.resolve(obj) 32 | }) 33 | }) 34 | 35 | after(function () { 36 | mockery.disable() 37 | }) 38 | } 39 | 40 | --------------------------------------------------------------------------------