├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .travis.yml ├── .verb.md ├── LICENSE ├── basefile.js ├── docs └── example.js ├── examples ├── cli.js ├── generator-plugins.js ├── generators │ ├── a │ │ ├── .gitignore │ │ ├── generator.js │ │ ├── index.js │ │ ├── package.json │ │ └── templates │ │ │ └── post.hbs │ ├── b │ │ ├── .gitignore │ │ ├── generator.js │ │ └── package.json │ ├── c │ │ ├── .gitignore │ │ ├── generator.js │ │ └── package.json │ ├── d │ │ └── .gitkeep │ ├── e │ │ ├── .gitignore │ │ ├── generator.js │ │ ├── package.json │ │ └── templates │ │ │ └── post.hbs │ ├── f │ │ ├── .gitignore │ │ ├── generator.js │ │ └── package.json │ ├── g │ │ ├── .gitignore │ │ ├── index.js │ │ └── package.json │ ├── h │ │ ├── .gitignore │ │ ├── index.js │ │ └── package.json │ ├── i │ │ ├── .gitignore │ │ ├── index.js │ │ └── package.json │ ├── instance │ │ ├── generator.js │ │ └── package.json │ ├── j │ │ ├── .gitignore │ │ ├── index.js │ │ └── package.json │ └── package.json └── resolve.js ├── fixtures ├── fn.js ├── generate-xyz │ └── index.js ├── instance.js └── verb-readme-generator │ └── index.js ├── gulpfile.js ├── index.js ├── lib ├── compose.js ├── generate.js ├── generator.js ├── plugins.js ├── tasks.js └── utils.js ├── package.json ├── readme.md └── test ├── app.extendWith.js ├── app.generate.js ├── app.generateEach.js ├── app.generator.js ├── app.getGenerator.js ├── app.lookupGenerator.js ├── app.matchGenerator.js ├── app.register.js ├── app.task.js ├── app.toAlias.js ├── fixtures ├── generator.js ├── generators │ ├── a │ │ ├── .gitignore │ │ ├── generator.js │ │ ├── package.json │ │ └── post.hbs │ ├── b │ │ ├── .gitignore │ │ ├── index.js │ │ └── package.json │ ├── c │ │ ├── .gitignore │ │ ├── generator.js │ │ └── package.json │ ├── e │ │ ├── .gitignore │ │ ├── generator.js │ │ ├── package.json │ │ └── templates │ │ │ └── post.hbs │ └── qux │ │ ├── .gitignore │ │ ├── generator.js │ │ └── package.json ├── generators2.js ├── not-exposed.js ├── one │ ├── generator.js │ ├── package.json │ └── templates │ │ ├── a.txt │ │ ├── x.txt │ │ ├── y.txt │ │ └── z.txt ├── three │ ├── four │ │ ├── five │ │ │ ├── generator.js │ │ │ ├── package.json │ │ │ └── templates │ │ │ │ ├── a.txt │ │ │ │ ├── b.txt │ │ │ │ └── c.txt │ │ ├── generator.js │ │ ├── package.json │ │ └── templates │ │ │ ├── a.txt │ │ │ ├── b.txt │ │ │ └── c.txt │ ├── generator.js │ ├── package.json │ └── templates │ │ ├── a.txt │ │ ├── b.txt │ │ └── c.txt └── two │ ├── generator.js │ ├── package.json │ └── templates │ ├── a.txt │ ├── b.txt │ └── c.txt ├── generators.env.js ├── generators.events.js ├── generators.plugin.js ├── support ├── app.js └── is-app.js └── tasks.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | charset = utf-8 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{**/{actual,fixtures,expected,templates}/**,*.md}] 12 | trim_trailing_whitespace = false 13 | insert_final_newline = false -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "modules": true, 4 | "experimentalObjectRestSpread": true 5 | }, 6 | 7 | "env": { 8 | "browser": false, 9 | "es6": true, 10 | "node": true, 11 | "mocha": true 12 | }, 13 | 14 | "globals": { 15 | "document": false, 16 | "navigator": false, 17 | "window": false 18 | }, 19 | 20 | "rules": { 21 | "accessor-pairs": 2, 22 | "arrow-spacing": [2, { "before": true, "after": true }], 23 | "block-spacing": [2, "always"], 24 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 25 | "comma-dangle": [2, "never"], 26 | "comma-spacing": [2, { "before": false, "after": true }], 27 | "comma-style": [2, "last"], 28 | "constructor-super": 2, 29 | "curly": [2, "multi-line"], 30 | "dot-location": [2, "property"], 31 | "eol-last": 2, 32 | "eqeqeq": [2, "allow-null"], 33 | "generator-star-spacing": [2, { "before": true, "after": true }], 34 | "handle-callback-err": [2, "^(err|error)$" ], 35 | "indent": [2, 2, { "SwitchCase": 1 }], 36 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 37 | "keyword-spacing": [2, { "before": true, "after": true }], 38 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 39 | "new-parens": 2, 40 | "no-array-constructor": 2, 41 | "no-caller": 2, 42 | "no-class-assign": 2, 43 | "no-cond-assign": 2, 44 | "no-const-assign": 2, 45 | "no-control-regex": 2, 46 | "no-debugger": 2, 47 | "no-delete-var": 2, 48 | "no-dupe-args": 2, 49 | "no-dupe-class-members": 2, 50 | "no-dupe-keys": 2, 51 | "no-duplicate-case": 2, 52 | "no-empty-character-class": 2, 53 | "no-eval": 2, 54 | "no-ex-assign": 2, 55 | "no-extend-native": 2, 56 | "no-extra-bind": 2, 57 | "no-extra-boolean-cast": 2, 58 | "no-extra-parens": [2, "functions"], 59 | "no-fallthrough": 2, 60 | "no-floating-decimal": 2, 61 | "no-func-assign": 2, 62 | "no-implied-eval": 2, 63 | "no-inner-declarations": [2, "functions"], 64 | "no-invalid-regexp": 2, 65 | "no-irregular-whitespace": 2, 66 | "no-iterator": 2, 67 | "no-label-var": 2, 68 | "no-labels": 2, 69 | "no-lone-blocks": 2, 70 | "no-mixed-spaces-and-tabs": 2, 71 | "no-multi-spaces": 2, 72 | "no-multi-str": 2, 73 | "no-multiple-empty-lines": [2, { "max": 1 }], 74 | "no-native-reassign": 0, 75 | "no-negated-in-lhs": 2, 76 | "no-new": 2, 77 | "no-new-func": 2, 78 | "no-new-object": 2, 79 | "no-new-require": 2, 80 | "no-new-wrappers": 2, 81 | "no-obj-calls": 2, 82 | "no-octal": 2, 83 | "no-octal-escape": 2, 84 | "no-proto": 0, 85 | "no-redeclare": 2, 86 | "no-regex-spaces": 2, 87 | "no-return-assign": 2, 88 | "no-self-compare": 2, 89 | "no-sequences": 2, 90 | "no-shadow-restricted-names": 2, 91 | "no-spaced-func": 2, 92 | "no-sparse-arrays": 2, 93 | "no-this-before-super": 2, 94 | "no-throw-literal": 2, 95 | "no-trailing-spaces": 0, 96 | "no-undef": 2, 97 | "no-undef-init": 2, 98 | "no-unexpected-multiline": 2, 99 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 100 | "no-unreachable": 2, 101 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 102 | "no-useless-call": 0, 103 | "no-with": 2, 104 | "one-var": [0, { "initialized": "never" }], 105 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 106 | "padded-blocks": [0, "never"], 107 | "quotes": [2, "single", "avoid-escape"], 108 | "radix": 2, 109 | "semi": [2, "always"], 110 | "semi-spacing": [2, { "before": false, "after": true }], 111 | "space-before-blocks": [2, "always"], 112 | "space-before-function-paren": [2, "never"], 113 | "space-in-parens": [2, "never"], 114 | "space-infix-ops": 2, 115 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 116 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 117 | "use-isnan": 2, 118 | "valid-typeof": 2, 119 | "wrap-iife": [2, "any"], 120 | "yoda": [2, "never"] 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text eol=lf 3 | 4 | # binaries 5 | *.ai binary 6 | *.psd binary 7 | *.jpg binary 8 | *.gif binary 9 | *.png binary 10 | *.jpeg binary 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | *.sublime-* 4 | 5 | # test related, or directories generated by tests 6 | test/actual 7 | actual 8 | coverage 9 | 10 | # npm 11 | node_modules 12 | npm-debug.log 13 | 14 | # misc 15 | _gh_pages 16 | benchmark 17 | bower_components 18 | vendor 19 | temp 20 | tmp 21 | TODO.md 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '5' 5 | - '4' 6 | - '0.12' 7 | - '0.10' 8 | matrix: 9 | fast_finish: true 10 | allow_failures: 11 | - node_js: '4' 12 | - node_js: '0.10' 13 | - node_js: '0.12' 14 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | **HEADS UP!** 2 | 3 | The `.generateEach` method has been deprecated. Use `.generate` instead. 4 | 5 | ## Usage 6 | 7 | ```js 8 | var generators = require('{%= name %}'); 9 | var Base = require('base'); 10 | 11 | // register the plugin before instantiating, to make 12 | // sure the plugin is called on all Generator instances 13 | Base.use(generators()); 14 | var base = new Base(); 15 | ``` 16 | 17 | ## Examples 18 | 19 | All examples assume the following code is defined: 20 | 21 | ```js 22 | var Base = require('base'); 23 | var generators = require('base-generators'); 24 | 25 | Base.use(generators()); 26 | var base = new Base(); 27 | ``` 28 | 29 | ### Tasks 30 | 31 | Tasks are exactly the same as [gulp][] tasks, and are powered by [bach][] and [composer][]. 32 | 33 | **Register a task:** 34 | 35 | ```js 36 | base.task('default', function(cb) { 37 | // do stuff 38 | cb(); 39 | }); 40 | ``` 41 | 42 | **Run a task:** 43 | 44 | ```js 45 | base.build('default', function(err) { 46 | if (err) throw err; 47 | }); 48 | ``` 49 | 50 | ### Generators 51 | 52 | > I heard you liked tasks, so I put some tasks in your tasks. 53 | 54 | **What's a generator?** 55 | 56 | Generators are functions that are registered by name, and are used to encapsulate and organize code, [tasks](#tasks), other generators, or [sub-generators](#sub-generators), in a sharable, publishable and easily re-usable way. 57 | 58 | In case it helps, here are some [live examples](#in-the-wild). 59 | 60 | **Register a generator:** 61 | 62 | ```js 63 | base.register('foo', function(app, base) { 64 | // `app` is the generator's "private" instance 65 | // `base` is a "shared" instance, accessible by all generators 66 | }); 67 | ``` 68 | 69 | **Get a generator:** 70 | 71 | ```js 72 | var foo = base.generator('foo'); 73 | ``` 74 | 75 | **Register tasks in a generator:** 76 | 77 | ```js 78 | base.register('foo', function(app, base) { 79 | app.task('default', function() {}); 80 | app.task('one', function() {}); 81 | app.task('two', function() {}); 82 | }); 83 | ``` 84 | 85 | **Run a generator's tasks:** 86 | 87 | The `.generate` method simply calls the `.build` method on a specific generator. 88 | 89 | To run a generator's tasks, pass the generator name as the first argument, and optionally define one or more tasks as the second argument. _(If no tasks are defined, the `default` task is run.)_ 90 | 91 | ```js 92 | // run the "default" task on generator "foo" 93 | base.generate('foo', function(err) { 94 | if (err) throw err; 95 | console.log('done!'); 96 | }); 97 | 98 | // or specify tasks 99 | base.generate('foo', ['default'], function() {}); 100 | base.generate('foo', ['one', 'two'], function() {}); 101 | ``` 102 | 103 | Alternatively, you can call `.build` on the generator directly: 104 | 105 | ```js 106 | // run the "default" task on generator "foo" 107 | base.generator('foo') 108 | .build('default', function(err) { 109 | if (err) throw err; 110 | }); 111 | ``` 112 | 113 | ### Sub-generators 114 | 115 | Sub-generators are just generators that are registered on (or invoked within) another generator instance. 116 | 117 | **Register sub-generators:** 118 | 119 | Register generators `one`, `two`, and `three` on generator `foo`: 120 | 121 | ```js 122 | base.register('foo', function(app, base) { 123 | app.register('one', function() {}); 124 | app.register('two', function() {}); 125 | app.register('three', function() {}); 126 | }); 127 | ``` 128 | 129 | **Get a sub-generator:** 130 | 131 | Use dot-notation to get a sub-generator: 132 | 133 | ```js 134 | var one = base.generator('foo.one'); 135 | ``` 136 | 137 | Sub-generators may be nested to any level. In reality, you probably won't write code like the following example, but this only illustrates the point that generators are extremely composable, and can be built on top of or with other generators. 138 | 139 | ```js 140 | base.register('a', function(a, base) { 141 | // do stuff 142 | a.register('b', function(b) { 143 | // do stuff 144 | b.register('c', function(c) { 145 | // do stuff 146 | c.register('d', function(d) { 147 | // do stuff 148 | d.register('e', function(e) { 149 | // arbitrary task 150 | e.task('default', function(cb) { 151 | console.log('e > default!'); 152 | cb(); 153 | }); 154 | }); 155 | }); 156 | }); 157 | }); 158 | }); 159 | 160 | base.getGenerator('a.b.c.d.e') 161 | .build(function(err) { 162 | if (err) throw err; 163 | // 'e > default!' 164 | }); 165 | ``` 166 | 167 | **Register tasks on sub-generators:** 168 | 169 | ```js 170 | base.register('foo', function(app, base) { 171 | app.register('one', function(one) { 172 | one.task('default', function() {}); 173 | one.task('a', function() {}); 174 | one.task('b', function() {}); 175 | one.task('c', function() {}); 176 | }); 177 | 178 | app.register('two', function(two) { 179 | two.task('default', function() {}); 180 | }); 181 | 182 | app.register('three', function(three) { 183 | three.task('default', function() {}); 184 | }); 185 | }); 186 | ``` 187 | 188 | **Run a sub-generator's tasks** 189 | 190 | ```js 191 | // run the `default` task from sub-generator `foo.one` 192 | base.generate('foo.one', function(err) { 193 | if (err) throw err; 194 | console.log('done!'); 195 | }); 196 | ``` 197 | 198 | **Run multiple tasks on a sub-generator:** 199 | 200 | ```js 201 | // run tasks `a`, `b` and `c` on sub-generator `foo.one` 202 | base.generate('foo.one', ['a', 'b', 'c'], function(err) { 203 | if (err) throw err; 204 | console.log('done!'); 205 | }); 206 | ``` 207 | 208 | ## In the wild 209 | 210 | The following applications use this library: 211 | 212 | - [generate][]: adds a CLI, template rendering, fs methods and generator convenience-methods to base-generators 213 | - [assemble][]: site generation 214 | - [verb][]: documentation generation 215 | - [update][]: renames generators to "updaters", which are used to keep your project up-to-date 216 | 217 | ## API 218 | {%= apidocs("index.js") %} 219 | {%= apidocs("lib/*.js") %} 220 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016, Jon Schlinkert. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /basefile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app, base, env, options) { 4 | app.task('default', function(cb) { 5 | console.log('generator', app.name, '> task', this.name); 6 | cb(); 7 | }); 8 | 9 | app.task('git', function(cb) { 10 | console.log('generator', app.name, '> task', this.name); 11 | cb(); 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /docs/example.js: -------------------------------------------------------------------------------- 1 | 2 | var generators = require('..'); 3 | var Base = require('base'); 4 | Base.use(function fn() { 5 | this.isApp = true; 6 | return fn; 7 | }); 8 | 9 | // all of the `base` variables below refer 10 | // to this initial instance 11 | var base = new Base(); 12 | base.use(generators()); 13 | 14 | base.register('foo', function(foo, base) { 15 | // `foo` is "app" 16 | // `foo.parent` is (also) `base` 17 | // `foo.base` is `base` 18 | // 19 | // namespace => `foo` 20 | 21 | foo.register('bar', function(bar, base) { 22 | // `bar` is "app" 23 | // `bar.parent` is `foo` 24 | // `bar.base` is `base` 25 | // 26 | // namespace => `foo.bar` 27 | 28 | bar.register('baz', function(baz, base) { 29 | // `baz` is "app" 30 | // `baz.parent` is `bar` 31 | // `baz.base` is `base` 32 | // 33 | // namespace => `foo.bar.baz` 34 | 35 | baz.register('qux', function(qux, base) { 36 | // `qux` is "app" 37 | // `quz.parent` is `baz` 38 | // `qux.base`is `base` 39 | // 40 | // namespace => `foo.bar.baz.qux` 41 | 42 | }); 43 | }); 44 | }); 45 | }); 46 | 47 | /** 48 | * Get a generator 49 | */ 50 | 51 | console.log(base) 52 | console.log(base.generator('foo')) 53 | console.log(base.generator('foo.bar')) 54 | console.log(base.generator('foo.bar.baz')) 55 | console.log(base.generator('foo.bar.baz.qux')) 56 | 57 | /** 58 | * See the sub-generators cached on a generator 59 | */ 60 | 61 | console.log(base.generators) 62 | //=> { foo: [Getter] } 63 | console.log(base.generator('foo').generators) 64 | //=> { bar: [Getter] } 65 | console.log(base.generator('foo.bar').generators) 66 | //=> { baz: [Getter] } 67 | console.log(base.generator('foo.bar.baz').generators) 68 | //=> { qux: [Getter] } 69 | console.log(base.generator('foo.bar.baz.qux').generators) 70 | //=> {} 71 | -------------------------------------------------------------------------------- /examples/cli.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var generators = require('..'); 4 | var runtimes = require('base-runtimes'); 5 | var Base = require('base'); 6 | Base.use(function fn() { 7 | this.isApp = true; 8 | return fn; 9 | }); 10 | 11 | var argv = require('minimist')(process.argv.slice(2)); 12 | var file = argv.file ? require(argv.file) : require('./generators/a'); 13 | var tasks = argv._.length ? argv._ : ['default']; 14 | 15 | var base = new Base(); 16 | base.use(generators()); 17 | base.use(runtimes()); 18 | base.register('default', file); 19 | 20 | base.getGenerator('default') 21 | .generateEach(tasks, function(err) { 22 | if (err) throw err; 23 | console.log('done!'); 24 | }); 25 | -------------------------------------------------------------------------------- /examples/generator-plugins.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * This example shows how generators pass options 5 | * and plugins to child generators 6 | */ 7 | 8 | var generators = require('..'); 9 | var option = require('base-option'); 10 | var Base = require('base'); 11 | Base.use(function fn() { 12 | this.is('app'); 13 | return fn; 14 | }); 15 | 16 | var base = new Base(); 17 | base.use(generators()); 18 | base.use(option()); 19 | base.option('cwd', 'examples'); 20 | 21 | base.register('foo', function(foo) { 22 | this.use(function fn() { 23 | this.aaa = 'aaa'; 24 | return fn; 25 | }); 26 | 27 | this.option('one', 'one'); 28 | console.log(this.aaa); 29 | console.log(this.options); 30 | 31 | this.register('bar', function(bar) { 32 | this.bbb = 'bbb'; 33 | this.option('two', 'two'); 34 | 35 | console.log(this.aaa); 36 | console.log(this.options); 37 | 38 | this.register('baz', function(baz) { 39 | this.ccc = 'ccc'; 40 | this.option('three', 'three'); 41 | 42 | console.log(this.aaa); 43 | console.log(this.options); 44 | 45 | this.register('qux', function(qux) { 46 | this.ddd = 'ddd'; 47 | this.option('four', 'four'); 48 | 49 | console.log(this.aaa); 50 | console.log(this.options); 51 | 52 | this.register('fez', function(fez) { 53 | this.eee = 'eee'; 54 | this.option('five', 'five'); 55 | 56 | console.log(this.aaa); 57 | console.log(this.options); 58 | }); 59 | }); 60 | }); 61 | }); 62 | }); 63 | 64 | base.getGenerator('foo.bar.baz.qux.fez'); 65 | -------------------------------------------------------------------------------- /examples/generators/a/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/a/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var config = require('base-config'); 4 | 5 | module.exports = function(app) { 6 | app.use(config()); 7 | 8 | app.config.map('bar', function() { 9 | console.log('config BAR') 10 | }); 11 | 12 | app.task('default', function(cb) { 13 | console.log('fixtures/a > default'); 14 | cb(); 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /examples/generators/a/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | module.exports = require('./generator') 11 | -------------------------------------------------------------------------------- /examples/generators/a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-a", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "main": "generator.js", 9 | "dependencies": { 10 | "base-config": "^0.3.6" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/generators/a/templates/post.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Post 3 | --- 4 | 5 | This is SOME POST 6 | -------------------------------------------------------------------------------- /examples/generators/b/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/b/generator.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var data = require('base-data'); 11 | 12 | module.exports = function(app) { 13 | app.use(data()); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/generators/b/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bbb", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "main": "generator.js", 9 | "dependencies": { 10 | "base-data": "^0.3.6" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/generators/c/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/c/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | 5 | module.exports = function(app, opts) { 6 | app.extendWith(path.resolve(__dirname, '../b')); 7 | 8 | app.data({site: {title: 'Foo'}}); 9 | 10 | app.task('default', function(cb) { 11 | console.log('c > default'); 12 | cb(); 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/generators/c/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "a", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /examples/generators/d/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/examples/generators/d/.gitkeep -------------------------------------------------------------------------------- /examples/generators/e/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/e/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * testing... 5 | */ 6 | 7 | module.exports = function(app, base, env) { 8 | app.task('default', function(cb) { 9 | console.log('e > default'); 10 | cb(); 11 | }); 12 | 13 | app.generator('c', require('../c')); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/generators/e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-e", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /examples/generators/e/templates/post.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Post 3 | --- 4 | 5 | This is three 6 | -------------------------------------------------------------------------------- /examples/generators/f/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/f/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('base-fs'); 4 | 5 | module.exports = function(app, base) { 6 | // app.use(fs); 7 | 8 | // app.task('default', function() { 9 | // console.log('f > default'); 10 | // return app.src('*.js') 11 | // .pipe(app.dest('test/actual')); 12 | // }); 13 | 14 | // app.task('f', function() { 15 | // console.log('generator.js > task f'); 16 | // return app.src('LICENSE') 17 | // .pipe(app.dest('test/actual/f')); 18 | // }); 19 | }; 20 | -------------------------------------------------------------------------------- /examples/generators/f/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-f", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "main": "generator.js", 9 | "dependencies": { 10 | "base-fs": "^0.2.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/generators/g/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/g/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | module.exports = function(app) { 11 | //app.partial('g', {content: '...'}); 12 | }; 13 | -------------------------------------------------------------------------------- /examples/generators/g/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bbb", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /examples/generators/h/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/h/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var data = require('base-data'); 11 | 12 | module.exports = function(app, base) { 13 | // base.partial('h', {content: '...'}); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/generators/h/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bbb", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /examples/generators/i/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/i/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var cli = require('base-cli'); 11 | 12 | module.exports = function(app) { 13 | app.use(cli()); 14 | 15 | app.cli.map('abc', function(val) { 16 | console.log(val); 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/generators/i/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bbb", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "main": "generator.js", 9 | "dependencies": { 10 | "base-cli": "^0.4.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/generators/instance/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var argv = require('minimist')(process.argv.slice(2)); 5 | var generators = require('../../..'); 6 | 7 | /** 8 | * Register the `generators` plugin before instantiating `Base` 9 | */ 10 | 11 | var Base = require('base'); 12 | Base.use(generators()); 13 | 14 | /** 15 | * Instantiate 16 | */ 17 | 18 | var app = new Base(); 19 | var cwd = path.resolve.bind(path, __dirname, '../../generators'); 20 | 21 | /** 22 | * Register a generator 23 | */ 24 | 25 | app.register('example', function(app) { 26 | app.extendWith(cwd('f')); 27 | app.extendWith(cwd('e')); 28 | 29 | app.generator(cwd('a')) 30 | .config.map('foo', function() { 31 | console.log('config FOO') 32 | }); 33 | 34 | app.generator(cwd('a')) 35 | .config.map('zzz', function() { 36 | console.log('config ZZZ') 37 | }); 38 | 39 | app.task('process', function(cb) { 40 | app.generator(cwd('i')) 41 | .cli.process(argv, function(err) { 42 | if (err) return cb(err); 43 | 44 | console.log('example > process'); 45 | app.generator(cwd('a')) 46 | .config.process({zzz: 'zzz', bar: 'bar'}, cb); 47 | }); 48 | }); 49 | 50 | app.task('default', function(cb) { 51 | console.log('example > default'); 52 | cb(); 53 | }); 54 | }); 55 | 56 | /** 57 | * Generate 58 | */ 59 | 60 | app.task('default', function(cb) { 61 | console.log(this.app.name + ' > ' + this.name); 62 | app.generate('example', ['process'], function(err) { 63 | if (err) return cb(err); 64 | console.log('example > process'); 65 | cb(); 66 | }); 67 | }); 68 | 69 | module.exports = app; 70 | -------------------------------------------------------------------------------- /examples/generators/instance/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-instance-example", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /examples/generators/j/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/generators/j/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var data = require('base-data'); 11 | 12 | module.exports = function(app) { 13 | app.use(data()); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/generators/j/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bbb", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /examples/generators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-generators", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /examples/resolve.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // require('time-require'); 4 | var task = require('base-task'); 5 | var assemble = require('assemble-core'); 6 | var resolve = require('../lib/resolve'); 7 | var register = require('..'); 8 | var env = require('base-env'); 9 | 10 | var app = assemble(); 11 | app.use(env()); 12 | app.use(resolve()); 13 | app.use(register()); 14 | 15 | app.on('resolve', function(file) { 16 | console.log(file); 17 | }); 18 | 19 | app.on('search', function(type, fp) { 20 | console.log(type, fp); 21 | }); 22 | 23 | // var files = app.resolve(); 24 | 25 | app.search('generator', 'verb-*-generator', { 26 | alias: function(name) { 27 | return name.replace(/^verb-([^-]+)-generator/g, '$1'); 28 | } 29 | }); 30 | 31 | app.search('verb', 'verb-*-generator', { 32 | alias: function(name) { 33 | return name.replace(/^verb-([^-]+)-generator/g, '$1'); 34 | } 35 | }); 36 | 37 | // console.log(files); 38 | -------------------------------------------------------------------------------- /fixtures/fn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function fn(app, base, env) { 4 | console.log(app); 5 | console.log('path:', __filename); 6 | } 7 | -------------------------------------------------------------------------------- /fixtures/generate-xyz/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function fn(app, base, env) { 4 | console.log(app); 5 | console.log('path:', __filename); 6 | } 7 | -------------------------------------------------------------------------------- /fixtures/instance.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Base = require('base'); 4 | module.exports = new Base(); 5 | -------------------------------------------------------------------------------- /fixtures/verb-readme-generator/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function fn(app, base, env) { 4 | console.log(app); 5 | console.log('path:', __filename); 6 | } 7 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var mocha = require('gulp-mocha'); 5 | var istanbul = require('gulp-istanbul'); 6 | var unused = require('gulp-unused'); 7 | var eslint = require('gulp-eslint'); 8 | 9 | gulp.task('coverage', function() { 10 | return gulp.src(['index.js', 'lib/*.js']) 11 | .pipe(istanbul()) 12 | .pipe(istanbul.hookRequire()); 13 | }); 14 | 15 | gulp.task('test', ['coverage'], function() { 16 | return gulp.src('test/*.js') 17 | .pipe(mocha({reporter: 'spec'})) 18 | .pipe(istanbul.writeReports()); 19 | }); 20 | 21 | gulp.task('lint', function() { 22 | return gulp.src(['*.js', 'test/*.js', 'lib/*.js']) 23 | .pipe(eslint()) 24 | .pipe(eslint.format()); 25 | }); 26 | 27 | gulp.task('unused', function() { 28 | var keys = Object.keys(require('./lib/utils.js')); 29 | return gulp.src(['index.js', 'lib/*.js']) 30 | .pipe(unused({keys: keys})); 31 | }); 32 | 33 | gulp.task('default', ['test', 'lint']); 34 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * base-generators 3 | * 4 | * Copyright (c) 2016, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var path = require('path'); 11 | var debug = require('debug')('base:generators'); 12 | var generator = require('./lib/generator'); 13 | var generate = require('./lib/generate'); 14 | var plugins = require('./lib/plugins'); 15 | var tasks = require('./lib/tasks'); 16 | var utils = require('./lib/utils'); 17 | var parseTasks = tasks.parse; 18 | 19 | /** 20 | * Expose `generators` 21 | */ 22 | 23 | module.exports = function(config) { 24 | config = config || {}; 25 | 26 | return function plugin(app) { 27 | if (!utils.isValid(app, 'base-generators')) return; 28 | 29 | this.isGenerator = true; 30 | this.generators = {}; 31 | var cache = {}; 32 | 33 | this.define('constructor', this.constructor); 34 | this.use(plugins()); 35 | this.fns.push(plugin); 36 | 37 | /** 38 | * Add methods to `app` (instance of Base) 39 | */ 40 | 41 | this.define({ 42 | 43 | /** 44 | * Alias to `.setGenerator`. 45 | * 46 | * ```js 47 | * app.register('foo', function(app, base) { 48 | * // "app" is a private instance created for the generator 49 | * // "base" is a shared instance 50 | * }); 51 | * ``` 52 | * @name .register 53 | * @param {String} `name` The generator's name 54 | * @param {Object|Function|String} `options` or generator 55 | * @param {Object|Function|String} `generator` Generator function, instance or filepath. 56 | * @return {Object} Returns the generator instance. 57 | * @api public 58 | */ 59 | 60 | register: function(name, options, generator) { 61 | return this.setGenerator.apply(this, arguments); 62 | }, 63 | 64 | /** 65 | * Get and invoke generator `name`, or register generator `name` with 66 | * the given `val` and `options`, then invoke and return the generator 67 | * instance. This method differs from `.register`, which lazily invokes 68 | * generator functions when `.generate` is called. 69 | * 70 | * ```js 71 | * app.generator('foo', function(app, base, env, options) { 72 | * // "app" - private instance created for generator "foo" 73 | * // "base" - instance shared by all generators 74 | * // "env" - environment object for the generator 75 | * // "options" - options passed to the generator 76 | * }); 77 | * ``` 78 | * @name .generator 79 | * @param {String} `name` 80 | * @param {Function|Object} `fn` Generator function, instance or filepath. 81 | * @return {Object} Returns the generator instance or undefined if not resolved. 82 | * @api public 83 | */ 84 | 85 | generator: function(name, val, options) { 86 | debug('.generator', name, val); 87 | 88 | if (this.hasGenerator(name)) { 89 | return this.getGenerator(name); 90 | } 91 | 92 | this.setGenerator.apply(this, arguments); 93 | return this.getGenerator(name); 94 | }, 95 | 96 | /** 97 | * Store a generator by file path or instance with the given 98 | * `name` and `options`. 99 | * 100 | * ```js 101 | * app.setGenerator('foo', function(app, base) { 102 | * // "app" - private instance created for generator "foo" 103 | * // "base" - instance shared by all generators 104 | * // "env" - environment object for the generator 105 | * // "options" - options passed to the generator 106 | * }); 107 | * ``` 108 | * @name .setGenerator 109 | * @param {String} `name` The generator's name 110 | * @param {Object|Function|String} `options` or generator 111 | * @param {Object|Function|String} `generator` Generator function, instance or filepath. 112 | * @return {Object} Returns the generator instance. 113 | * @api public 114 | */ 115 | 116 | setGenerator: function(name, val, options) { 117 | debug('.setGenerator', name); 118 | 119 | if (this.hasGenerator(name)) { 120 | return this.findGenerator(name); 121 | } 122 | 123 | // ensure local sub-generator paths are resolved 124 | if (typeof val === 'string' && val.charAt(0) === '.' && this.env) { 125 | val = path.resolve(this.env.dirname, val); 126 | } 127 | 128 | return generator(name, val, options, this); 129 | }, 130 | 131 | /** 132 | * Get generator `name` from `app.generators`, same as [findGenerator], but also invokes 133 | * the returned generator with the current instance. Dot-notation may be used for getting 134 | * sub-generators. 135 | * 136 | * ```js 137 | * var foo = app.getGenerator('foo'); 138 | * 139 | * // get a sub-generator 140 | * var baz = app.getGenerator('foo.bar.baz'); 141 | * ``` 142 | * @name .getGenerator 143 | * @param {String} `name` Generator name. 144 | * @return {Object|undefined} Returns the generator instance or undefined. 145 | * @api public 146 | */ 147 | 148 | getGenerator: function(name, options) { 149 | debug('.getGenerator', name); 150 | 151 | if (name === 'this') { 152 | return this; 153 | } 154 | 155 | var gen = this.findGenerator(name, options); 156 | if (utils.isValidInstance(gen)) { 157 | return gen.invoke(gen, options); 158 | } 159 | }, 160 | 161 | /** 162 | * Find generator `name`, by first searching the cache, then searching the 163 | * cache of the `base` generator. Use this to get a generator without invoking it. 164 | * 165 | * ```js 166 | * // search by "alias" 167 | * var foo = app.findGenerator('foo'); 168 | * 169 | * // search by "full name" 170 | * var foo = app.findGenerator('generate-foo'); 171 | * ``` 172 | * @name .findGenerator 173 | * @param {String} `name` 174 | * @param {Function} `options` Optionally supply a rename function on `options.toAlias` 175 | * @return {Object|undefined} Returns the generator instance if found, or undefined. 176 | * @api public 177 | */ 178 | 179 | findGenerator: function fn(name, options) { 180 | debug('.findGenerator', name); 181 | if (utils.isObject(name)) { 182 | return name; 183 | } 184 | 185 | if (Array.isArray(name)) { 186 | name = name.join('.'); 187 | } 188 | 189 | if (typeof name !== 'string') { 190 | throw new TypeError('expected name to be a string'); 191 | } 192 | 193 | if (cache.hasOwnProperty(name)) { 194 | return cache[name]; 195 | } 196 | 197 | var app = this.generators[name] 198 | || this.base.generators[name] 199 | || this._findGenerator(name, options); 200 | 201 | // if no app, check the `base` instance 202 | if (typeof app === 'undefined' && this.hasOwnProperty('parent')) { 203 | app = this.base._findGenerator(name, options); 204 | } 205 | 206 | if (app) { 207 | cache[app.name] = app; 208 | cache[app.alias] = app; 209 | cache[name] = app; 210 | return app; 211 | } 212 | 213 | var search = {name, options}; 214 | this.base.emit('unresolved', search, this); 215 | if (search.app) { 216 | cache[search.app.name] = search.app; 217 | cache[search.app.alias] = search.app; 218 | return search.app; 219 | } 220 | 221 | cache[name] = null; 222 | }, 223 | 224 | /** 225 | * Private method used by `.findGenerator`. 226 | */ 227 | 228 | _findGenerator: function(name, options) { 229 | if (this.generators.hasOwnProperty(name)) { 230 | return this.generators[name]; 231 | } 232 | 233 | if (~name.indexOf('.')) { 234 | return this.getSubGenerator.apply(this, arguments); 235 | } 236 | 237 | var opts = utils.extend({}, this.options, options); 238 | if (typeof opts.lookup === 'function') { 239 | var app = this.lookupGenerator(name, opts, opts.lookup); 240 | if (app) { 241 | return app; 242 | } 243 | } 244 | return this.matchGenerator(name); 245 | }, 246 | 247 | /** 248 | * Get sub-generator `name`, optionally using dot-notation for nested generators. 249 | * 250 | * ```js 251 | * app.getSubGenerator('foo.bar.baz'); 252 | * ``` 253 | * @name .getSubGenerator 254 | * @param {String} `name` The property-path of the generator to get 255 | * @param {Object} `options` 256 | * @api public 257 | */ 258 | 259 | getSubGenerator: function(name, options) { 260 | debug('.getSubGenerator', name); 261 | var segs = name.split('.'); 262 | var len = segs.length; 263 | var idx = -1; 264 | var app = this; 265 | 266 | while (++idx < len) { 267 | var key = segs[idx]; 268 | app = app.getGenerator(key, options); 269 | if (!app) { 270 | break; 271 | } 272 | } 273 | return app; 274 | }, 275 | 276 | /** 277 | * Iterate over `app.generators` and call `generator.isMatch(name)` 278 | * on `name` until a match is found. 279 | * 280 | * @param {String} `name` 281 | * @return {Object|undefined} Returns a generator object if a match is found. 282 | * @api public 283 | */ 284 | 285 | matchGenerator: function(name) { 286 | debug('.matchGenerator', name); 287 | for (var key in this.generators) { 288 | var generator = this.generators[key]; 289 | if (generator.isMatch(name)) { 290 | return generator; 291 | } 292 | } 293 | }, 294 | 295 | /** 296 | * Returns true if the given generator `name` or `val` is already registered. 297 | * 298 | * ```js 299 | * console.log(app.hasGenerator('foo')); 300 | * ``` 301 | * @param {String} `name` 302 | * @param {Object|Function} `val` 303 | * @return {Boolean} 304 | * @api public 305 | */ 306 | 307 | hasGenerator: function(name, val) { 308 | return this.generators.hasOwnProperty(name) || this.base.generators[name]; 309 | }, 310 | 311 | /** 312 | * Tries to find a registered generator that matches `name` 313 | * by iterating over the `generators` object, and doing a strict 314 | * comparison of each name returned by the given lookup `fn`. 315 | * The lookup function receives `name` and must return an array 316 | * of names to use for the lookup. 317 | * 318 | * For example, if the lookup `name` is `foo`, the function might 319 | * return `["generator-foo", "foo"]`, to ensure that the lookup happens 320 | * in that order. 321 | * 322 | * @param {String} `name` Generator name to search for 323 | * @param {Object} `options` 324 | * @param {Function} `fn` Lookup function that must return an array of names. 325 | * @return {Object} 326 | * @api public 327 | */ 328 | 329 | lookupGenerator: function(name, options, fn) { 330 | debug('.lookupGenerator', name); 331 | if (typeof options === 'function') { 332 | fn = options; 333 | options = {}; 334 | } 335 | 336 | if (typeof fn !== 'function') { 337 | throw new TypeError('expected `fn` to be a lookup function'); 338 | } 339 | 340 | options = options || {}; 341 | 342 | // remove `lookup` fn from options to prevent self-recursion 343 | delete this.options.lookup; 344 | delete options.lookup; 345 | 346 | var names = fn(name); 347 | debug('looking up generator "%s" with "%j"', name, names); 348 | 349 | var len = names.length; 350 | var idx = -1; 351 | 352 | while (++idx < len) { 353 | var gen = this.findGenerator(names[idx], options); 354 | if (gen) { 355 | this.options.lookup = fn; 356 | return gen; 357 | } 358 | } 359 | 360 | this.options.lookup = fn; 361 | }, 362 | 363 | /** 364 | * Extend the generator instance with settings and features 365 | * of another generator. 366 | * 367 | * ```js 368 | * var foo = base.generator('foo'); 369 | * app.extendWith(foo); 370 | * // or 371 | * app.extendWith('foo'); 372 | * // or 373 | * app.extendWith(['foo', 'bar', 'baz']); 374 | * 375 | * app.extendWith(require('generate-defaults')); 376 | * ``` 377 | * 378 | * @name .extendWith 379 | * @param {String|Object} `app` 380 | * @return {Object} Returns the instance for chaining. 381 | * @api public 382 | */ 383 | 384 | extendWith: function(name, options) { 385 | if (typeof name === 'function') { 386 | this.use(name, options); 387 | return this; 388 | } 389 | 390 | if (Array.isArray(name)) { 391 | var len = name.length; 392 | var idx = -1; 393 | while (++idx < len) { 394 | this.extendWith(name[idx], options); 395 | } 396 | return this; 397 | } 398 | 399 | var app = name; 400 | if (typeof name === 'string') { 401 | app = this.generators[name] || this.findGenerator(name, options); 402 | if (!app && utils.exists(name)) { 403 | var fn = utils.tryRequire(name, this.cwd); 404 | if (typeof fn === 'function') { 405 | app = this.register(name, fn); 406 | } 407 | } 408 | } 409 | 410 | if (!utils.isValidInstance(app)) { 411 | throw new Error('cannot find generator: "' + name + '"'); 412 | } 413 | 414 | var alias = app.env ? app.env.alias : 'default'; 415 | debug('extending "%s" with "%s"', alias, name); 416 | app.run(this); 417 | app.invoke(options, this); 418 | return this; 419 | }, 420 | 421 | /** 422 | * Run a `generator` and `tasks`, calling the given `callback` function 423 | * upon completion. 424 | * 425 | * ```js 426 | * // run tasks `bar` and `baz` on generator `foo` 427 | * app.generate('foo', ['bar', 'baz'], function(err) { 428 | * if (err) throw err; 429 | * }); 430 | * 431 | * // or use shorthand 432 | * app.generate('foo:bar,baz', function(err) { 433 | * if (err) throw err; 434 | * }); 435 | * 436 | * // run the `default` task on generator `foo` 437 | * app.generate('foo', function(err) { 438 | * if (err) throw err; 439 | * }); 440 | * 441 | * // run the `default` task on the `default` generator, if defined 442 | * app.generate(function(err) { 443 | * if (err) throw err; 444 | * }); 445 | * ``` 446 | * @name .generate 447 | * @emits `generate` with the generator `name` and the array of `tasks` that are queued to run. 448 | * @param {String} `name` 449 | * @param {String|Array} `tasks` 450 | * @param {Function} `cb` Callback function that exposes `err` as the only parameter. 451 | */ 452 | 453 | generate: function(name, tasks, options, cb) { 454 | var self = this; 455 | 456 | if (typeof name === 'function') { 457 | return this.generate('default', [], {}, name); 458 | } 459 | if (utils.isObject(name)) { 460 | return this.generate('default', ['default'], name, tasks); 461 | } 462 | if (typeof tasks === 'function') { 463 | return this.generate(name, [], {}, tasks); 464 | } 465 | if (utils.isObject(tasks)) { 466 | return this.generate(name, [], tasks, options); 467 | } 468 | if (typeof options === 'function') { 469 | return this.generate(name, tasks, {}, options); 470 | } 471 | 472 | var results = []; 473 | if (Array.isArray(name)) { 474 | return utils.eachSeries(name, function(val, next) { 475 | self.generate(val, tasks, options, function(err, result) { 476 | if (err) return next(err); 477 | results = results.concat(result); 478 | next(null, result); 479 | }); 480 | }, function(err) { 481 | if (err) return cb(err); 482 | cb(null, results); 483 | }); 484 | } 485 | 486 | if (typeof cb !== 'function') { 487 | throw new TypeError('expected a callback function'); 488 | } 489 | 490 | var queue = parseTasks(app, name, tasks); 491 | 492 | utils.eachSeries(queue, function(queued, next) { 493 | if (queued._ && queued._.length) { 494 | if (queued._[0] === 'default') { 495 | next(); 496 | return; 497 | } 498 | var msg = utils.formatError('generator', app, queued._); 499 | next(new Error(msg)); 500 | return; 501 | } 502 | 503 | if (cb.name === 'finishRun' && typeof name === 'string' && queued.tasks.indexOf(name) !== -1) { 504 | queued.name = name; 505 | queued.tasks = ['default']; 506 | } 507 | 508 | queued.generator = queued.app || this.getGenerator(queued.name, options); 509 | 510 | if (!utils.isGenerator(queued.generator)) { 511 | if (queued.name === 'default') { 512 | next(); 513 | return; 514 | } 515 | next(new Error(utils.formatError('generator', app, queued.name))); 516 | return; 517 | } 518 | 519 | generate(this, queued, options, function(err, result) { 520 | if (err) return next(err); 521 | results = results.concat(result); 522 | next(null, result); 523 | }); 524 | }.bind(this), function(err) { 525 | if (err) return cb(err); 526 | cb(null, results); 527 | }); 528 | return; 529 | }, 530 | 531 | /** 532 | * Create a generator alias from the given `name`. By default the alias 533 | * is the string after the last dash. Or the whole string if no dash exists. 534 | * 535 | * ```js 536 | * var camelcase = require('camel-case'); 537 | * var alias = app.toAlias('foo-bar-baz'); 538 | * //=> 'baz' 539 | * 540 | * // custom `toAlias` function 541 | * app.option('toAlias', function(name) { 542 | * return camelcase(name); 543 | * }); 544 | * var alias = app.toAlias('foo-bar-baz'); 545 | * //=> 'fooBarBaz' 546 | * ``` 547 | * @name .toAlias 548 | * @param {String} `name` 549 | * @param {Object} `options` 550 | * @return {String} Returns the alias. 551 | * @api public 552 | */ 553 | 554 | toAlias: function(name, options) { 555 | if (typeof options === 'function') { 556 | return options(name); 557 | } 558 | if (options && typeof options.toAlias === 'function') { 559 | return options.toAlias(name); 560 | } 561 | if (typeof app.options.toAlias === 'function') { 562 | return app.options.toAlias(name); 563 | } 564 | return name; 565 | } 566 | }); 567 | 568 | /** 569 | * Getter that returns `true` if the current instance is the `default` generator 570 | */ 571 | 572 | Object.defineProperty(this, 'isDefault', { 573 | configurable: true, 574 | get: function() { 575 | return this.env && this.env.isDefault; 576 | } 577 | }); 578 | 579 | return plugin; 580 | }; 581 | }; 582 | 583 | -------------------------------------------------------------------------------- /lib/compose.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./utils'); 4 | 5 | /** 6 | * Extend the generator being invoked with settings from the instance, 7 | * but only if the generator is not the `default` generator. 8 | * 9 | * Also, note that this **does not add tasks** from the `default` generator 10 | * onto the instance. 11 | */ 12 | 13 | module.exports = function(app, generator, ctx) { 14 | var env = generator.env || {}; 15 | var alias = env.alias; 16 | 17 | // update `cache.config` 18 | var config = utils.merge({}, ctx || app.cache.config || app.pkg.get(app._name)); 19 | generator.set('cache.config', config); 20 | 21 | // set options 22 | utils.merge(generator.options, app.options); 23 | utils.merge(generator.options, config); 24 | 25 | // extend generator with settings from default 26 | if (app.generators.hasOwnProperty('default') && alias !== 'default') { 27 | var compose = generator 28 | .compose(['default']) 29 | .options(); 30 | 31 | if (typeof app.data === 'function') { 32 | compose.data(); 33 | } 34 | 35 | if (typeof app.pipeline === 'function') { 36 | compose.pipeline(); 37 | } 38 | 39 | if (typeof app.helper === 'function') { 40 | compose.helpers(); 41 | compose.engines(); 42 | compose.views(); 43 | } 44 | 45 | if (typeof app.question === 'function') { 46 | compose.questions(); 47 | } 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /lib/generate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var compose = require('./compose'); 4 | var utils = require('./utils'); 5 | 6 | /** 7 | * Run generators, calling `.config.process` first if it exists. 8 | * 9 | * @param {String|Array} `name` generator to run 10 | * @param {Array|String} `tasks` tasks to run 11 | * @param {Object} `app` Application instance 12 | * @param {Object} `generator` generator instance 13 | * @param {Function} next 14 | */ 15 | 16 | module.exports = function(app, queued, options, next) { 17 | var generator = queued.generator; 18 | var tasks = queued.tasks; 19 | 20 | compose(app, generator); 21 | 22 | if (tasks.length === 1 && !generator.tasks.hasOwnProperty(tasks[0])) { 23 | if (tasks[0] === 'default') { 24 | next(); 25 | return; 26 | } 27 | var suffix = queued.name !== 'this' ? ('" in generator: "' + queued.name + '"') : ''; 28 | console.error('Cannot find task: "' + tasks[0] + suffix); 29 | next(); 30 | return; 31 | } 32 | 33 | utils.merge(generator.options, options); 34 | 35 | var alias = generator.env ? generator.env.alias : generator._name; 36 | app.emit('generate', alias, queued.tasks, generator); 37 | if (app._lookup) { 38 | app.options.lookup = app._lookup; 39 | } 40 | 41 | // if `base-config` is registered call `.process` first, then run tasks 42 | if (typeof generator.config !== 'undefined') { 43 | var config = app.get('cache.config') || {}; 44 | generator.config.process(config, build); 45 | } else { 46 | build(); 47 | } 48 | 49 | function build(err) { 50 | if (err) return done(err); 51 | generator.build(tasks, done); 52 | } 53 | 54 | function done(err, result) { 55 | if (err) { 56 | err.queue = queued; 57 | utils.handleError(app, queued.name, next)(err); 58 | } else { 59 | next(null, result); 60 | } 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /lib/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./utils'); 4 | 5 | function toGenerator(name, val, options, parent) { 6 | var Generator = parent.constructor; 7 | var generator = val; 8 | 9 | if (utils.isValidInstance(val)) { 10 | generator.constructor = Generator; 11 | } else { 12 | generator = new Generator(); 13 | } 14 | 15 | var fn = decorate(name, val, options, parent); 16 | generator.use(fn); 17 | 18 | // cache the generator 19 | parent.generators[generator.alias] = generator; 20 | parent.generators[generator.name] = generator; 21 | parent.generators[name] = generator; 22 | parent.emit('generator', generator); 23 | return generator; 24 | } 25 | 26 | function decorate(name, val, options, parent) { 27 | return function(app) { 28 | utils.merge(this.options, parent.options); 29 | this.is('generator'); 30 | this.isApp = true; 31 | this.define('parent', parent); 32 | parent.run(this); 33 | 34 | this.on('error', parent.emit.bind(parent, 'error')); 35 | 36 | Object.defineProperty(this, 'env', { 37 | configurable: true, 38 | get: function() { 39 | return parent.createEnv(name, val, this.options); 40 | } 41 | }); 42 | 43 | Object.defineProperty(this, 'alias', { 44 | configurable: true, 45 | get: function() { 46 | return this.env.alias; 47 | } 48 | }); 49 | 50 | Object.defineProperty(this, 'name', { 51 | configurable: true, 52 | get: function() { 53 | return this.env.name; 54 | } 55 | }); 56 | 57 | this.define('isMatch', function() { 58 | return this.env.isMatch.apply(this.env, arguments); 59 | }); 60 | 61 | this.define('invoke', function(context, options) { 62 | return this.env.invoke.apply(this.env, arguments); 63 | }); 64 | }; 65 | } 66 | 67 | module.exports = toGenerator; 68 | -------------------------------------------------------------------------------- /lib/plugins.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./utils'); 4 | 5 | module.exports = function() { 6 | return function fn(app) { 7 | if (utils.isValid(app, 'base-generators-plugins')) { 8 | this.define('isValid', utils.isValid); 9 | this.use(utils.plugins()); 10 | this.use(utils.cwd()); 11 | this.use(utils.pkg()); 12 | this.use(utils.env()); 13 | this.use(utils.option()); 14 | this.use(utils.data()); 15 | this.use(utils.compose()); 16 | this.use(utils.task()); 17 | } 18 | return fn; 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /lib/tasks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * ```sh 5 | * $ gen 6 | * $ gen default 7 | * $ gen foo 8 | * $ gen foo:default 9 | * $ gen foo,bar 10 | * $ gen foo bar 11 | * $ gen foo bar:baz 12 | * $ gen foo:bar,baz 13 | * $ gen foo.bar 14 | * $ gen foo.bar:baz 15 | * $ gen foo.bar baz 16 | * $ gen foo.bar baz.qux 17 | * $ gen foo.bar:baz qux.fez:default 18 | * ``` 19 | */ 20 | 21 | // foo:bar,baz 22 | exports.parse = function(app, name, tasks) { 23 | if (tasks && !tasks.length) { 24 | tasks = undefined; 25 | } 26 | 27 | if (Array.isArray(name)) { 28 | var arr = name.reduce(function(acc, val) { 29 | return acc.concat(exports.parse(app, val)); 30 | }, []); 31 | 32 | return arr.reduce(function(acc, obj) { 33 | var prev = acc[acc.length - 1]; 34 | if (prev && prev.name === obj.name) { 35 | prev.tasks = prev.tasks.concat(obj.tasks); 36 | return acc; 37 | } 38 | return acc.concat(obj); 39 | }, []); 40 | } 41 | 42 | if (!tasks && /:/.test(name)) { 43 | return exports.parse.apply(null, [app].concat(name.split(':'))); 44 | } 45 | 46 | if (typeof tasks === 'string') { 47 | tasks = tasks.split(','); 48 | } 49 | 50 | /** 51 | * If `name` and `tasks` was passed, call process, e.g: 52 | * 53 | * ```sh 54 | * $ gen foo:default 55 | * $ gen foo bar:baz 56 | * $ gen foo:bar,baz 57 | * $ gen foo.bar:baz 58 | * $ gen foo.bar:baz qux.fez:default 59 | * ``` 60 | */ 61 | 62 | if (tasks) { 63 | return [{name: name, tasks: tasks}]; 64 | } 65 | 66 | /** 67 | * Otherwise, we have one of the following: 68 | * 69 | * ```sh 70 | * $ gen 71 | * $ gen default 72 | * $ gen foo 73 | * $ gen foo,bar,baz 74 | * $ gen foo bar 75 | * $ gen foo.bar 76 | * $ gen foo.bar baz 77 | * $ gen foo.bar baz.qux 78 | * ``` 79 | */ 80 | 81 | if (typeof name === 'string') { 82 | name = name.split(','); 83 | } 84 | 85 | return name.reduce(function(acc, str) { 86 | var obj = exports.process(app, str); 87 | var prev = acc[acc.length - 1]; 88 | if (prev && prev.name === obj.name) { 89 | prev.tasks = prev.tasks.concat(obj.tasks); 90 | return acc; 91 | } 92 | return acc.concat(obj); 93 | }, []); 94 | }; 95 | 96 | /** 97 | * All we have left at this point is ambiguous args 98 | * that could represent tasks or generators: 99 | * 100 | * ```sh 101 | * $ gen 102 | * $ gen default 103 | * $ gen foo 104 | * $ gen foo bar 105 | * ``` 106 | */ 107 | 108 | exports.process = function(app, str) { 109 | var generator; 110 | if (app.tasks.hasOwnProperty(str)) { 111 | return {name: app.isDefault ? 'default' : 'this', tasks: [str]}; 112 | } 113 | 114 | if (/\./.test(str) || app.generators.hasOwnProperty(str)) { 115 | return {name: app.isDefault ? ('default.' + str) : str, tasks: ['default']}; 116 | } 117 | 118 | // `app` is **not** the default generator 119 | if (!app.isDefault) { 120 | generator = app.base.getGenerator('default'); 121 | if (generator) { 122 | return exports.process(generator, str); 123 | } 124 | } 125 | 126 | // `app` is the default generator 127 | generator = app.base.getGenerator(str); 128 | if (generator) { 129 | return {name: generator.name, tasks: ['default'], app: generator}; 130 | } 131 | 132 | // unresolved argument 133 | return {_: [str]}; 134 | }; 135 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var utils = require('lazy-cache')(require); 6 | var fn = require; 7 | require = utils; // eslint-disable-line 8 | 9 | /** 10 | * Utils 11 | */ 12 | 13 | require('async-each-series', 'eachSeries'); 14 | require('base-compose', 'compose'); 15 | require('base-cwd', 'cwd'); 16 | require('base-data', 'data'); 17 | require('base-env', 'env'); 18 | require('base-option', 'option'); 19 | require('base-pkg', 'pkg'); 20 | require('base-plugins', 'plugins'); 21 | require('base-task', 'task'); 22 | require('define-property', 'define'); 23 | require('extend-shallow', 'extend'); 24 | require('global-modules', 'gm'); 25 | require('is-valid-app', 'isValid'); 26 | require('is-valid-instance'); 27 | require('kind-of', 'typeOf'); 28 | require('mixin-deep', 'merge'); 29 | require = fn; // eslint-disable-line 30 | 31 | /** 32 | * Cache lookups 33 | */ 34 | 35 | var lookupCache = {}; 36 | 37 | /** 38 | * Returns true if a task or array of tasks is valid 39 | */ 40 | 41 | utils.isValidTasks = function(val) { 42 | if (!val) return false; 43 | if (utils.isString(val)) { 44 | return !/\W/.test(val); 45 | } 46 | if (!Array.isArray(val)) { 47 | return false; 48 | } 49 | return val.every(function(str) { 50 | return utils.isString(str) && !/\W/.test(str); 51 | }); 52 | }; 53 | 54 | utils.isGenerator = function(val) { 55 | return utils.isApp(val, 'Generator'); 56 | }; 57 | 58 | utils.isApp = function(val, ctorName) { 59 | return utils.isObject(val) && val['is' + ctorName] === true; 60 | }; 61 | 62 | /** 63 | * Return true if `val` is a string with length greater than zero. 64 | */ 65 | 66 | utils.isString = function(val) { 67 | return val && typeof val === 'string'; 68 | }; 69 | 70 | /** 71 | * Create an array of tasks 72 | */ 73 | 74 | utils.toArray = function(val) { 75 | if (Array.isArray(val)) { 76 | return val.reduce(function(acc, str) { 77 | return acc.concat(utils.toArray(str)); 78 | }, []); 79 | } 80 | if (utils.isString(val)) { 81 | return val.split(','); 82 | } 83 | return []; 84 | }; 85 | 86 | /** 87 | * Cast `val` to an array 88 | */ 89 | 90 | utils.arrayify = function(val) { 91 | return val ? (Array.isArray(val) ? val : [val]) : []; 92 | }; 93 | 94 | /** 95 | * Returns true if `val` is an object 96 | */ 97 | 98 | utils.isObject = function(val) { 99 | return utils.typeOf(val) === 'object'; 100 | }; 101 | 102 | /** 103 | * Try to require a module `name` locally, from local node_modules, 104 | * then global npm directory 105 | */ 106 | 107 | utils.tryRequire = function(name, cwd) { 108 | cwd = cwd || process.cwd(); 109 | try { 110 | return require(name); 111 | } catch (err) {} 112 | 113 | try { 114 | return require(path.resolve(name)); 115 | } catch (err) {} 116 | 117 | try { 118 | return require(path.resolve(cwd, 'node_modules', name)); 119 | } catch (err) {} 120 | 121 | try { 122 | return require(path.resolve(utils.gm, name)); 123 | } catch (err) {} 124 | return null; 125 | }; 126 | 127 | /** 128 | * Return true if `filepath` exists on the file system 129 | */ 130 | 131 | utils.exists = function(name) { 132 | if (lookupCache.hasOwnProperty(name)) { 133 | return lookupCache[name]; 134 | } 135 | 136 | function set(name, fp) { 137 | if (name) lookupCache[name] = true; 138 | if (fp) lookupCache[fp] = true; 139 | } 140 | 141 | try { 142 | fs.lstatSync(name); 143 | set(name); 144 | return true; 145 | } catch (err) {}; 146 | 147 | try { 148 | var fp = path.resolve('node_modules', name); 149 | if (lookupCache[fp]) return true; 150 | 151 | fs.lstatSync(fp); 152 | set(name, fp); 153 | return true; 154 | } catch (err) {} 155 | 156 | try { 157 | fp = path.resolve(utils.gm, name); 158 | if (lookupCache[fp]) return true; 159 | fs.lstatSync(fp); 160 | set(name, fp); 161 | return true; 162 | } catch (err) {} 163 | 164 | lookupCache[name] = false; 165 | return false; 166 | }; 167 | 168 | /** 169 | * Handle generator errors 170 | */ 171 | 172 | utils.handleError = function(app, name, next) { 173 | return function(err) { 174 | if (!err) { 175 | next(); 176 | return; 177 | } 178 | 179 | var msg = utils.formatError(err, app, name); 180 | if (!msg) { 181 | next(); 182 | return; 183 | } 184 | 185 | if (msg instanceof Error) { 186 | next(err); 187 | return; 188 | } 189 | 190 | next(new Error(msg)); 191 | }; 192 | }; 193 | 194 | utils.formatError = function(err, app, name) { 195 | if (err instanceof Error) { 196 | var match = /task "(.*?)" is not registered/.exec(err.message); 197 | if (!match) { 198 | return err; 199 | } 200 | 201 | var taskname = match[1]; 202 | if (taskname === 'default') { 203 | return; 204 | } 205 | 206 | if (~name.indexOf(':')) { 207 | var segs = name.split(':'); 208 | taskname = segs[1]; 209 | name = segs[0]; 210 | } 211 | } 212 | 213 | var msg = 'Cannot find '; 214 | var gen = app.getGenerator(name); 215 | if (gen && name !== taskname) { 216 | msg += 'task: "' + taskname + (name !== 'this' ? '" in generator' : ''); 217 | } else { 218 | // don't error when a `default` generator is not defined 219 | if (name === 'default') { 220 | return; 221 | } 222 | msg += 'generator'; 223 | } 224 | 225 | msg += (name !== 'this' ? ': "' + name + '"' : ''); 226 | 227 | var cwd = app.get('options.cwd'); 228 | if (cwd) msg += ' in "' + cwd + '"'; 229 | return msg; 230 | }; 231 | 232 | /** 233 | * Expose `utils` 234 | */ 235 | 236 | module.exports = utils; 237 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-generators", 3 | "description": "Adds project-generator support to your `base` application.", 4 | "version": "0.4.6", 5 | "homepage": "https://github.com/node-base/base-generators", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "node-base/base-generators", 8 | "bugs": { 9 | "url": "https://github.com/node-base/base-generators/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js", 14 | "lib", 15 | "LICENSE", 16 | "README.md" 17 | ], 18 | "main": "index.js", 19 | "engines": { 20 | "node": ">=0.10.0" 21 | }, 22 | "scripts": { 23 | "test": "mocha" 24 | }, 25 | "dependencies": { 26 | "async-each-series": "^1.1.0", 27 | "base-compose": "^0.2.1", 28 | "base-cwd": "^0.3.1", 29 | "base-data": "^0.6.0", 30 | "base-env": "^0.3.0", 31 | "base-option": "^0.8.4", 32 | "base-pkg": "^0.2.4", 33 | "base-plugins": "^0.4.13", 34 | "base-task": "^0.6.1", 35 | "debug": "^2.2.0", 36 | "define-property": "^0.2.5", 37 | "extend-shallow": "^2.0.1", 38 | "global-modules": "^0.2.2", 39 | "is-valid-app": "^0.2.0", 40 | "is-valid-instance": "^0.2.0", 41 | "kind-of": "^3.0.3", 42 | "lazy-cache": "^2.0.1", 43 | "mixin-deep": "^1.1.3" 44 | }, 45 | "devDependencies": { 46 | "assemble-core": "^0.23.0", 47 | "base": "^0.11.1", 48 | "base-config-process": "^0.1.7", 49 | "base-runtimes": "^0.1.11", 50 | "cross-spawn": "^4.0.0", 51 | "fs-exists-sync": "^0.1.0", 52 | "generate-foo": "^0.1.5", 53 | "generator-util": "^0.2.9", 54 | "gulp": "^3.9.1", 55 | "gulp-eslint": "^2.0.0", 56 | "gulp-format-md": "^0.1.9", 57 | "gulp-istanbul": "^1.0.0", 58 | "gulp-mocha": "^2.2.0", 59 | "gulp-unused": "^0.1.2", 60 | "is-absolute": "^0.2.5", 61 | "minimist": "^1.2.0", 62 | "mocha": "^2.5.3", 63 | "npm-install-global": "^0.1.2", 64 | "resolve": "^1.1.7" 65 | }, 66 | "keywords": [ 67 | "api", 68 | "app", 69 | "application", 70 | "base", 71 | "baseplugin", 72 | "boilerplate", 73 | "building-blocks", 74 | "create", 75 | "framework", 76 | "generate", 77 | "generator", 78 | "generators", 79 | "init", 80 | "plugin", 81 | "plugins", 82 | "project", 83 | "scaffold", 84 | "tool", 85 | "toolkit", 86 | "tools", 87 | "yeoman", 88 | "yo" 89 | ], 90 | "lintDeps": { 91 | "ignore": [ 92 | "docs", 93 | "examples/generators" 94 | ] 95 | }, 96 | "verb": { 97 | "toc": true, 98 | "layout": "default", 99 | "tasks": [ 100 | "readme" 101 | ], 102 | "plugins": [ 103 | "gulp-format-md" 104 | ], 105 | "related": { 106 | "highlight": "base-task", 107 | "list": [ 108 | "bach", 109 | "base", 110 | "base-fs", 111 | "base-pipeline", 112 | "base-plugins", 113 | "base-task", 114 | "composer", 115 | "gulp" 116 | ] 117 | }, 118 | "reflinks": [ 119 | "bach", 120 | "composer", 121 | "gulp", 122 | "verb", 123 | "verb-readme-generator", 124 | "generate", 125 | "assemble", 126 | "update" 127 | ] 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # base-generators [![NPM version](https://img.shields.io/npm/v/base-generators.svg?style=flat)](https://www.npmjs.com/package/base-generators) [![NPM downloads](https://img.shields.io/npm/dm/base-generators.svg?style=flat)](https://npmjs.org/package/base-generators) [![Linux Build Status](https://img.shields.io/travis/node-base/base-generators.svg?style=flat&label=Travis)](https://travis-ci.org/node-base/base-generators) 2 | 3 | > Adds project-generator support to your `base` application. 4 | 5 | You might also be interested in [base-task](https://github.com/node-base/base-task). 6 | 7 | ## Table of Contents 8 | 9 | - [Install](#install) 10 | - [Usage](#usage) 11 | - [Examples](#examples) 12 | * [Tasks](#tasks) 13 | * [Generators](#generators) 14 | * [Sub-generators](#sub-generators) 15 | - [In the wild](#in-the-wild) 16 | - [API](#api) 17 | - [About](#about) 18 | * [Related projects](#related-projects) 19 | * [Contributing](#contributing) 20 | * [Contributors](#contributors) 21 | * [Release history](#release-history) 22 | * [Building docs](#building-docs) 23 | * [Running tests](#running-tests) 24 | * [Author](#author) 25 | * [License](#license) 26 | 27 | _(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_ 28 | 29 | ## Install 30 | 31 | Install with [npm](https://www.npmjs.com/): 32 | 33 | ```sh 34 | $ npm install --save base-generators 35 | ``` 36 | 37 | **HEADS UP!** 38 | 39 | The `.generateEach` method has been deprecated. Use `.generate` instead. 40 | 41 | ## Usage 42 | 43 | ```js 44 | var generators = require('base-generators'); 45 | var Base = require('base'); 46 | 47 | // register the plugin before instantiating, to make 48 | // sure the plugin is called on all Generator instances 49 | Base.use(generators()); 50 | var base = new Base(); 51 | ``` 52 | 53 | ## Examples 54 | 55 | All examples assume the following code is defined: 56 | 57 | ```js 58 | var Base = require('base'); 59 | var generators = require('base-generators'); 60 | 61 | Base.use(generators()); 62 | var base = new Base(); 63 | ``` 64 | 65 | ### Tasks 66 | 67 | Tasks are exactly the same as [gulp](http://gulpjs.com) tasks, and are powered by [bach](https://github.com/gulpjs/bach) and [composer](https://github.com/doowb/composer). 68 | 69 | **Register a task:** 70 | 71 | ```js 72 | base.task('default', function(cb) { 73 | // do stuff 74 | cb(); 75 | }); 76 | ``` 77 | 78 | **Run a task:** 79 | 80 | ```js 81 | base.build('default', function(err) { 82 | if (err) throw err; 83 | }); 84 | ``` 85 | 86 | ### Generators 87 | 88 | > I heard you liked tasks, so I put some tasks in your tasks. 89 | 90 | **What's a generator?** 91 | 92 | Generators are functions that are registered by name, and are used to encapsulate and organize code, [tasks](#tasks), other generators, or [sub-generators](#sub-generators), in a sharable, publishable and easily re-usable way. 93 | 94 | In case it helps, here are some [live examples](#in-the-wild). 95 | 96 | **Register a generator:** 97 | 98 | ```js 99 | base.register('foo', function(app, base) { 100 | // `app` is the generator's "private" instance 101 | // `base` is a "shared" instance, accessible by all generators 102 | }); 103 | ``` 104 | 105 | **Get a generator:** 106 | 107 | ```js 108 | var foo = base.generator('foo'); 109 | ``` 110 | 111 | **Register tasks in a generator:** 112 | 113 | ```js 114 | base.register('foo', function(app, base) { 115 | app.task('default', function() {}); 116 | app.task('one', function() {}); 117 | app.task('two', function() {}); 118 | }); 119 | ``` 120 | 121 | **Run a generator's tasks:** 122 | 123 | The `.generate` method simply calls the `.build` method on a specific generator. 124 | 125 | To run a generator's tasks, pass the generator name as the first argument, and optionally define one or more tasks as the second argument. _(If no tasks are defined, the `default` task is run.)_ 126 | 127 | ```js 128 | // run the "default" task on generator "foo" 129 | base.generate('foo', function(err) { 130 | if (err) throw err; 131 | console.log('done!'); 132 | }); 133 | 134 | // or specify tasks 135 | base.generate('foo', ['default'], function() {}); 136 | base.generate('foo', ['one', 'two'], function() {}); 137 | ``` 138 | 139 | Alternatively, you can call `.build` on the generator directly: 140 | 141 | ```js 142 | // run the "default" task on generator "foo" 143 | base.generator('foo') 144 | .build('default', function(err) { 145 | if (err) throw err; 146 | }); 147 | ``` 148 | 149 | ### Sub-generators 150 | 151 | Sub-generators are just generators that are registered on (or invoked within) another generator instance. 152 | 153 | **Register sub-generators:** 154 | 155 | Register generators `one`, `two`, and `three` on generator `foo`: 156 | 157 | ```js 158 | base.register('foo', function(app, base) { 159 | app.register('one', function() {}); 160 | app.register('two', function() {}); 161 | app.register('three', function() {}); 162 | }); 163 | ``` 164 | 165 | **Get a sub-generator:** 166 | 167 | Use dot-notation to get a sub-generator: 168 | 169 | ```js 170 | var one = base.generator('foo.one'); 171 | ``` 172 | 173 | Sub-generators may be nested to any level. In reality, you probably won't write code like the following example, but this only illustrates the point that generators are extremely composable, and can be built on top of or with other generators. 174 | 175 | ```js 176 | base.register('a', function(a, base) { 177 | // do stuff 178 | a.register('b', function(b) { 179 | // do stuff 180 | b.register('c', function(c) { 181 | // do stuff 182 | c.register('d', function(d) { 183 | // do stuff 184 | d.register('e', function(e) { 185 | // arbitrary task 186 | e.task('default', function(cb) { 187 | console.log('e > default!'); 188 | cb(); 189 | }); 190 | }); 191 | }); 192 | }); 193 | }); 194 | }); 195 | 196 | base.getGenerator('a.b.c.d.e') 197 | .build(function(err) { 198 | if (err) throw err; 199 | // 'e > default!' 200 | }); 201 | ``` 202 | 203 | **Register tasks on sub-generators:** 204 | 205 | ```js 206 | base.register('foo', function(app, base) { 207 | app.register('one', function(one) { 208 | one.task('default', function() {}); 209 | one.task('a', function() {}); 210 | one.task('b', function() {}); 211 | one.task('c', function() {}); 212 | }); 213 | 214 | app.register('two', function(two) { 215 | two.task('default', function() {}); 216 | }); 217 | 218 | app.register('three', function(three) { 219 | three.task('default', function() {}); 220 | }); 221 | }); 222 | ``` 223 | 224 | **Run a sub-generator's tasks** 225 | 226 | ```js 227 | // run the `default` task from sub-generator `foo.one` 228 | base.generate('foo.one', function(err) { 229 | if (err) throw err; 230 | console.log('done!'); 231 | }); 232 | ``` 233 | 234 | **Run multiple tasks on a sub-generator:** 235 | 236 | ```js 237 | // run tasks `a`, `b` and `c` on sub-generator `foo.one` 238 | base.generate('foo.one', ['a', 'b', 'c'], function(err) { 239 | if (err) throw err; 240 | console.log('done!'); 241 | }); 242 | ``` 243 | 244 | ## In the wild 245 | 246 | The following applications use this library: 247 | 248 | * [generate](https://github.com/generate/generate): adds a CLI, template rendering, fs methods and generator convenience-methods to base-generators 249 | * [assemble](https://github.com/assemble/assemble): site generation 250 | * [verb](https://github.com/verbose/verb): documentation generation 251 | * [update](https://github.com/update/update): renames generators to "updaters", which are used to keep your project up-to-date 252 | 253 | ## API 254 | 255 | ### [.register](index.js#L60) 256 | 257 | Alias to `.setGenerator`. 258 | 259 | **Example** 260 | 261 | ```js 262 | app.register('foo', function(app, base) { 263 | // "app" is a private instance created for the generator 264 | // "base" is a shared instance 265 | }); 266 | ``` 267 | 268 | **Params** 269 | 270 | * `name` **{String}**: The generator's name 271 | * `options` **{Object|Function|String}**: or generator 272 | * `generator` **{Object|Function|String}**: Generator function, instance or filepath. 273 | * `returns` **{Object}**: Returns the generator instance. 274 | 275 | ### [.generator](index.js#L85) 276 | 277 | Get and invoke generator `name`, or register generator `name` with the given `val` and `options`, then invoke and return the generator instance. This method differs from `.register`, which lazily invokes generator functions when `.generate` is called. 278 | 279 | **Example** 280 | 281 | ```js 282 | app.generator('foo', function(app, base, env, options) { 283 | // "app" - private instance created for generator "foo" 284 | // "base" - instance shared by all generators 285 | // "env" - environment object for the generator 286 | // "options" - options passed to the generator 287 | }); 288 | ``` 289 | 290 | **Params** 291 | 292 | * `name` **{String}** 293 | * `fn` **{Function|Object}**: Generator function, instance or filepath. 294 | * `returns` **{Object}**: Returns the generator instance or undefined if not resolved. 295 | 296 | ### [.setGenerator](index.js#L116) 297 | 298 | Store a generator by file path or instance with the given `name` and `options`. 299 | 300 | **Example** 301 | 302 | ```js 303 | app.setGenerator('foo', function(app, base) { 304 | // "app" - private instance created for generator "foo" 305 | // "base" - instance shared by all generators 306 | // "env" - environment object for the generator 307 | // "options" - options passed to the generator 308 | }); 309 | ``` 310 | 311 | **Params** 312 | 313 | * `name` **{String}**: The generator's name 314 | * `options` **{Object|Function|String}**: or generator 315 | * `generator` **{Object|Function|String}**: Generator function, instance or filepath. 316 | * `returns` **{Object}**: Returns the generator instance. 317 | 318 | ### [.getGenerator](index.js#L148) 319 | 320 | Get generator `name` from `app.generators`, same as [findGenerator], but also invokes the returned generator with the current instance. Dot-notation may be used for getting sub-generators. 321 | 322 | **Example** 323 | 324 | ```js 325 | var foo = app.getGenerator('foo'); 326 | 327 | // get a sub-generator 328 | var baz = app.getGenerator('foo.bar.baz'); 329 | ``` 330 | 331 | **Params** 332 | 333 | * `name` **{String}**: Generator name. 334 | * `returns` **{Object|undefined}**: Returns the generator instance or undefined. 335 | 336 | ### [.findGenerator](index.js#L179) 337 | 338 | Find generator `name`, by first searching the cache, then searching the cache of the `base` generator. Use this to get a generator without invoking it. 339 | 340 | **Example** 341 | 342 | ```js 343 | // search by "alias" 344 | var foo = app.findGenerator('foo'); 345 | 346 | // search by "full name" 347 | var foo = app.findGenerator('generate-foo'); 348 | ``` 349 | 350 | **Params** 351 | 352 | * `name` **{String}** 353 | * `options` **{Function}**: Optionally supply a rename function on `options.toAlias` 354 | * `returns` **{Object|undefined}**: Returns the generator instance if found, or undefined. 355 | 356 | ### [.getSubGenerator](index.js#L259) 357 | 358 | Get sub-generator `name`, optionally using dot-notation for nested generators. 359 | 360 | **Example** 361 | 362 | ```js 363 | app.getSubGenerator('foo.bar.baz'); 364 | ``` 365 | 366 | **Params** 367 | 368 | * `name` **{String}**: The property-path of the generator to get 369 | * `options` **{Object}** 370 | 371 | Iterate over `app.generators` and call `generator.isMatch(name)` 372 | on `name` until a match is found. 373 | 374 | **Params** 375 | 376 | * `name` **{String}** 377 | * `returns` **{Object|undefined}**: Returns a generator object if a match is found. 378 | 379 | **Example** 380 | 381 | ```js 382 | console.log(app.hasGenerator('foo')); 383 | ``` 384 | 385 | **Params** 386 | 387 | * `name` **{String}** 388 | * `val` **{Object|Function}** 389 | * `returns` **{Boolean}** 390 | 391 | For example, if the lookup `name` is `foo`, the function might 392 | return `["generator-foo", "foo"]`, to ensure that the lookup happens 393 | in that order. 394 | 395 | **Params** 396 | 397 | * `name` **{String}**: Generator name to search for 398 | * `options` **{Object}** 399 | * `fn` **{Function}**: Lookup function that must return an array of names. 400 | * `returns` **{Object}** 401 | 402 | ### [.extendWith](index.js#L384) 403 | 404 | Extend the generator instance with settings and features of another generator. 405 | 406 | **Example** 407 | 408 | ```js 409 | var foo = base.generator('foo'); 410 | app.extendWith(foo); 411 | // or 412 | app.extendWith('foo'); 413 | // or 414 | app.extendWith(['foo', 'bar', 'baz']); 415 | 416 | app.extendWith(require('generate-defaults')); 417 | ``` 418 | 419 | **Params** 420 | 421 | * `app` **{String|Object}** 422 | * `returns` **{Object}**: Returns the instance for chaining. 423 | 424 | ### [.toAlias](index.js#L554) 425 | 426 | Create a generator alias from the given `name`. By default the alias is the string after the last dash. Or the whole string if no dash exists. 427 | 428 | **Example** 429 | 430 | ```js 431 | var camelcase = require('camel-case'); 432 | var alias = app.toAlias('foo-bar-baz'); 433 | //=> 'baz' 434 | 435 | // custom `toAlias` function 436 | app.option('toAlias', function(name) { 437 | return camelcase(name); 438 | }); 439 | var alias = app.toAlias('foo-bar-baz'); 440 | //=> 'fooBarBaz' 441 | ``` 442 | 443 | **Params** 444 | 445 | * `name` **{String}** 446 | * `options` **{Object}** 447 | * `returns` **{String}**: Returns the alias. 448 | 449 | ## About 450 | 451 | ### Related projects 452 | 453 | * [bach](https://www.npmjs.com/package/bach): Compose your async functions with elegance. | [homepage](https://github.com/gulpjs/bach#readme "Compose your async functions with elegance.") 454 | * [base-fs](https://www.npmjs.com/package/base-fs): base-methods plugin that adds vinyl-fs methods to your 'base' application for working with the file… [more](https://github.com/node-base/base-fs) | [homepage](https://github.com/node-base/base-fs "base-methods plugin that adds vinyl-fs methods to your 'base' application for working with the file system, like src, dest, copy and symlink.") 455 | * [base-pipeline](https://www.npmjs.com/package/base-pipeline): base-methods plugin that adds pipeline and plugin methods for dynamically composing streaming plugin pipelines. | [homepage](https://github.com/node-base/base-pipeline "base-methods plugin that adds pipeline and plugin methods for dynamically composing streaming plugin pipelines.") 456 | * [base-plugins](https://www.npmjs.com/package/base-plugins): Upgrade's plugin support in base applications to allow plugins to be called any time after… [more](https://github.com/node-base/base-plugins) | [homepage](https://github.com/node-base/base-plugins "Upgrade's plugin support in base applications to allow plugins to be called any time after init.") 457 | * [base-task](https://www.npmjs.com/package/base-task): base plugin that provides a very thin wrapper around [https://github.com/doowb/composer](https://github.com/doowb/composer) for adding task methods to… [more](https://github.com/node-base/base-task) | [homepage](https://github.com/node-base/base-task "base plugin that provides a very thin wrapper around for adding task methods to your application.") 458 | * [base](https://www.npmjs.com/package/base): base is the foundation for creating modular, unit testable and highly pluggable node.js applications, starting… [more](https://github.com/node-base/base) | [homepage](https://github.com/node-base/base "base is the foundation for creating modular, unit testable and highly pluggable node.js applications, starting with a handful of common methods, like `set`, `get`, `del` and `use`.") 459 | * [composer](https://www.npmjs.com/package/composer): API-first task runner with three methods: task, run and watch. | [homepage](https://github.com/doowb/composer "API-first task runner with three methods: task, run and watch.") 460 | * [gulp](https://www.npmjs.com/package/gulp): The streaming build system | [homepage](http://gulpjs.com "The streaming build system") 461 | 462 | ### Contributing 463 | 464 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 465 | 466 | ### Contributors 467 | 468 | | **Commits** | **Contributor** | 469 | | --- | --- | 470 | | 227 | [jonschlinkert](https://github.com/jonschlinkert) | 471 | | 6 | [doowb](https://github.com/doowb) | 472 | 473 | ### Building docs 474 | 475 | _(This document was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme) (a [verb](https://github.com/verbose/verb) generator), please don't edit the readme directly. Any changes to the readme must be made in [.verb.md](.verb.md).)_ 476 | 477 | To generate the readme and API documentation with [verb](https://github.com/verbose/verb): 478 | 479 | ```sh 480 | $ npm install -g verb verb-generate-readme && verb 481 | ``` 482 | 483 | ### Running tests 484 | 485 | Install dev dependencies: 486 | 487 | ```sh 488 | $ npm install -d && npm test 489 | ``` 490 | 491 | ### Author 492 | 493 | **Jon Schlinkert** 494 | 495 | * [github/jonschlinkert](https://github.com/jonschlinkert) 496 | * [twitter/jonschlinkert](http://twitter.com/jonschlinkert) 497 | 498 | ### License 499 | 500 | Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert). 501 | Released under the [MIT license](LICENSE). 502 | 503 | *** 504 | 505 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on November 22, 2016._ -------------------------------------------------------------------------------- /test/app.extendWith.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | require('generate-foo/generator.js'); 5 | 6 | var path = require('path'); 7 | var assert = require('assert'); 8 | var npm = require('npm-install-global'); 9 | var utils = require('generator-util'); 10 | var plugins = require('base-plugins'); 11 | var option = require('base-option'); 12 | var data = require('base-data'); 13 | var gm = require('global-modules'); 14 | var isApp = require('./support/is-app'); 15 | var isAbsolute = require('is-absolute'); 16 | var resolve = require('resolve'); 17 | var Base = require('base'); 18 | var generators = require('..'); 19 | var base; 20 | 21 | var fixture = path.resolve.bind(path, __dirname, 'fixtures/generators'); 22 | function resolver(search, app) { 23 | var name = search.name; 24 | 25 | try { 26 | if (isAbsolute(search.name)) { 27 | name = require.resolve(search.name); 28 | } else { 29 | name = resolve.sync(search.name); 30 | } 31 | search.app = app.register(name, name); 32 | return search; 33 | } catch (err) {} 34 | 35 | try { 36 | name = resolve.sync(search.name, {basedir: gm}); 37 | search.app = app.register(name, name); 38 | } catch (err) {} 39 | } 40 | 41 | describe('.extendWith', function() { 42 | before(function(cb) { 43 | if (!utils.exists(path.resolve(gm, 'generate-bar'))) { 44 | npm.install('generate-bar', cb); 45 | } else { 46 | cb(); 47 | } 48 | }); 49 | 50 | beforeEach(function() { 51 | Base.use(isApp()); 52 | 53 | base = new Base(); 54 | base.use(plugins()); 55 | base.use(option()); 56 | base.use(data()); 57 | base.use(generators()); 58 | 59 | base.option('toAlias', function(name) { 60 | return name.replace(/^generate-/, ''); 61 | }); 62 | 63 | base.on('unresolved', resolver); 64 | }); 65 | 66 | it('should throw an error when a generator is not found', function(cb) { 67 | try { 68 | base.register('foo', function(app) { 69 | app.extendWith('fofoofofofofof'); 70 | }); 71 | 72 | var foo = base.getGenerator('foo.fofoofofofofof'); 73 | cb(new Error('expected an error')); 74 | } catch (err) { 75 | assert.equal(err.message, 'cannot find generator: "fofoofofofofof"'); 76 | cb(); 77 | } 78 | }); 79 | 80 | it('should extend a generator with settings in the default generator', function(cb) { 81 | var count = 0; 82 | 83 | base.register('foo', function(app) { 84 | app.task('default', function(next) { 85 | assert.equal(app.options.foo, 'bar'); 86 | assert.equal(app.cache.data.foo, 'bar'); 87 | count++; 88 | next(); 89 | }); 90 | }); 91 | 92 | base.register('default', function(app) { 93 | app.data({foo: 'bar'}); 94 | app.option({foo: 'bar'}); 95 | }); 96 | 97 | base.generate('foo', function(err) { 98 | if (err) return cb(err); 99 | assert.equal(count, 1); 100 | cb(); 101 | }); 102 | }); 103 | 104 | it('should not extend tasks by default', function(cb) { 105 | var count = 0; 106 | 107 | base.register('foo', function(app) { 108 | app.task('default', function(next) { 109 | assert(app.tasks.hasOwnProperty('default')); 110 | assert(!app.tasks.hasOwnProperty('a')); 111 | assert(!app.tasks.hasOwnProperty('b')); 112 | assert(!app.tasks.hasOwnProperty('c')); 113 | count++; 114 | next(); 115 | }); 116 | }); 117 | 118 | base.register('default', function(app) { 119 | app.task('a', function(next) { 120 | next(); 121 | }); 122 | app.task('b', function(next) { 123 | next(); 124 | }); 125 | app.task('c', function(next) { 126 | next(); 127 | }); 128 | }); 129 | 130 | base.generate('foo', function(err) { 131 | if (err) return cb(err); 132 | assert.equal(count, 1); 133 | cb(); 134 | }); 135 | }); 136 | 137 | it('should get a named generator', function(cb) { 138 | var count = 0; 139 | 140 | base.register('foo', function(app) { 141 | app.extendWith('bar'); 142 | count++; 143 | }); 144 | 145 | base.register('bar', function(app) { 146 | app.task('a', function() {}); 147 | app.task('b', function() {}); 148 | app.task('c', function() {}); 149 | }); 150 | 151 | base.getGenerator('foo'); 152 | assert.equal(count, 1); 153 | cb(); 154 | }); 155 | 156 | it('should extend a generator with a named generator', function(cb) { 157 | base.register('foo', function(app) { 158 | assert(!app.tasks.a); 159 | assert(!app.tasks.b); 160 | assert(!app.tasks.c); 161 | 162 | app.extendWith('bar'); 163 | assert(app.tasks.a); 164 | assert(app.tasks.b); 165 | assert(app.tasks.c); 166 | cb(); 167 | }); 168 | 169 | base.register('bar', function(app) { 170 | app.task('a', function() {}); 171 | app.task('b', function() {}); 172 | app.task('c', function() {}); 173 | }); 174 | 175 | base.getGenerator('foo'); 176 | }); 177 | 178 | it('should extend a generator with an array of generators', function(cb) { 179 | base.register('foo', function(app) { 180 | assert(!app.tasks.a); 181 | assert(!app.tasks.b); 182 | assert(!app.tasks.c); 183 | 184 | app.extendWith(['bar', 'baz', 'qux']); 185 | assert(app.tasks.a); 186 | assert(app.tasks.b); 187 | assert(app.tasks.c); 188 | cb(); 189 | }); 190 | 191 | base.register('bar', function(app) { 192 | app.task('a', function() {}); 193 | }); 194 | 195 | base.register('baz', function(app) { 196 | app.task('b', function() {}); 197 | }); 198 | 199 | base.register('qux', function(app) { 200 | app.task('c', function() {}); 201 | }); 202 | 203 | base.getGenerator('foo'); 204 | }); 205 | 206 | describe('invoke generators', function(cb) { 207 | it('should extend with a generator instance', function(cb) { 208 | base.register('foo', function(app) { 209 | var bar = app.getGenerator('bar'); 210 | app.extendWith(bar); 211 | 212 | assert(app.tasks.hasOwnProperty('a')); 213 | assert(app.tasks.hasOwnProperty('b')); 214 | assert(app.tasks.hasOwnProperty('c')); 215 | cb(); 216 | }); 217 | 218 | base.register('bar', function(app) { 219 | app.isBar = true; 220 | app.task('a', function() {}); 221 | app.task('b', function() {}); 222 | app.task('c', function() {}); 223 | }); 224 | 225 | base.getGenerator('foo'); 226 | }); 227 | 228 | it('should invoke a named generator', function(cb) { 229 | base.register('foo', function(app) { 230 | app.extendWith('bar'); 231 | 232 | assert(app.tasks.hasOwnProperty('a')); 233 | assert(app.tasks.hasOwnProperty('b')); 234 | assert(app.tasks.hasOwnProperty('c')); 235 | cb(); 236 | }); 237 | 238 | base.register('bar', function(app) { 239 | app.task('a', function() {}); 240 | app.task('b', function() {}); 241 | app.task('c', function() {}); 242 | }); 243 | 244 | base.getGenerator('foo'); 245 | }); 246 | }); 247 | 248 | describe('extend generators', function(cb) { 249 | it('should extend a generator with a generator invoked by name', function(cb) { 250 | base.register('foo', function(app) { 251 | assert(!app.tasks.a); 252 | assert(!app.tasks.b); 253 | assert(!app.tasks.c); 254 | 255 | app.extendWith('bar'); 256 | assert(app.tasks.a); 257 | assert(app.tasks.b); 258 | assert(app.tasks.c); 259 | cb(); 260 | }); 261 | 262 | base.register('bar', function(app) { 263 | app.task('a', function() {}); 264 | app.task('b', function() {}); 265 | app.task('c', function() {}); 266 | }); 267 | 268 | base.getGenerator('foo'); 269 | }); 270 | 271 | it('should extend a generator with a generator invoked by alias', function(cb) { 272 | base.register('foo', function(app) { 273 | assert(!app.tasks.a); 274 | assert(!app.tasks.b); 275 | assert(!app.tasks.c); 276 | 277 | app.extendWith('qux'); 278 | assert(app.tasks.a); 279 | assert(app.tasks.b); 280 | assert(app.tasks.c); 281 | cb(); 282 | }); 283 | 284 | base.register('generate-qux', function(app) { 285 | app.task('a', function() {}); 286 | app.task('b', function() {}); 287 | app.task('c', function() {}); 288 | }); 289 | 290 | base.getGenerator('qux'); 291 | base.getGenerator('foo'); 292 | }); 293 | 294 | it('should extend with a generator invoked by filepath', function(cb) { 295 | base.register('foo', function(app) { 296 | assert(!app.tasks.a); 297 | assert(!app.tasks.b); 298 | assert(!app.tasks.c); 299 | 300 | app.extendWith(fixture('qux')); 301 | assert(app.tasks.a); 302 | assert(app.tasks.b); 303 | assert(app.tasks.c); 304 | cb(); 305 | }); 306 | 307 | base.getGenerator('foo'); 308 | }); 309 | 310 | it('should extend with a generator invoked from node_modules by name', function(cb) { 311 | base.register('generate-foo', require('generate-foo')); 312 | 313 | base.register('abc', function(app) { 314 | assert(!app.tasks.a); 315 | assert(!app.tasks.b); 316 | assert(!app.tasks.c); 317 | 318 | app.extendWith('generate-foo'); 319 | assert(app.tasks.a); 320 | assert(app.tasks.b); 321 | assert(app.tasks.c); 322 | cb(); 323 | }); 324 | 325 | base.getGenerator('abc'); 326 | }); 327 | 328 | it('should extend with a generator invoked from node_modules by name on a default instance', function() { 329 | var app = new Base(); 330 | app.use(plugins()); 331 | app.use(option()); 332 | app.use(generators()); 333 | 334 | app.on('unresolved', resolver); 335 | app.option('toAlias', function(name) { 336 | return name.replace(/^generate-/, ''); 337 | }); 338 | 339 | assert(!app.tasks.a); 340 | assert(!app.tasks.b); 341 | assert(!app.tasks.c); 342 | 343 | app.extendWith('generate-foo'); 344 | assert(app.tasks.a); 345 | assert(app.tasks.b); 346 | assert(app.tasks.c); 347 | }); 348 | 349 | it('should use a generator from node_modules as a plugin', function() { 350 | var app = new Base(); 351 | app.use(plugins()); 352 | app.use(option()); 353 | app.use(generators()); 354 | 355 | app.option('toAlias', function(name) { 356 | return name.replace(/^generate-/, ''); 357 | }); 358 | 359 | assert(!app.tasks.a); 360 | assert(!app.tasks.b); 361 | assert(!app.tasks.c); 362 | 363 | app.use(require('generate-foo')); 364 | assert(app.tasks.a); 365 | assert(app.tasks.b); 366 | assert(app.tasks.c); 367 | }); 368 | 369 | it('should extend with a generator invoked from global modules by name', function(cb) { 370 | base.register('zzz', function(app) { 371 | assert(!app.tasks.a); 372 | assert(!app.tasks.b); 373 | assert(!app.tasks.c); 374 | app.extendWith('generate-bar'); 375 | 376 | assert(app.tasks.a); 377 | assert(app.tasks.b); 378 | assert(app.tasks.c); 379 | cb(); 380 | }); 381 | 382 | base.getGenerator('zzz'); 383 | }); 384 | 385 | it('should extend with a generator invoked from global modules by alias', function(cb) { 386 | base.register('generate-bar'); 387 | 388 | base.register('zzz', function(app) { 389 | assert(!app.tasks.a); 390 | assert(!app.tasks.b); 391 | assert(!app.tasks.c); 392 | 393 | app.extendWith('bar'); 394 | assert(app.tasks.a); 395 | assert(app.tasks.b); 396 | assert(app.tasks.c); 397 | cb(); 398 | }); 399 | 400 | base.getGenerator('zzz'); 401 | }); 402 | }); 403 | 404 | describe('sub-generators', function(cb) { 405 | it('should invoke sub-generators', function(cb) { 406 | base.register('foo', function(app) { 407 | app.register('one', function(app) { 408 | app.task('a', function() {}); 409 | }); 410 | app.register('two', function(app) { 411 | app.task('b', function() {}); 412 | }); 413 | 414 | app.extendWith('one'); 415 | app.extendWith('two'); 416 | 417 | assert(app.tasks.hasOwnProperty('a')); 418 | assert(app.tasks.hasOwnProperty('b')); 419 | cb(); 420 | }); 421 | 422 | base.getGenerator('foo'); 423 | }); 424 | 425 | it('should invoke a sub-generator on the base instance', function(cb) { 426 | base.register('foo', function(app) { 427 | app.extendWith('bar.sub'); 428 | assert(app.tasks.hasOwnProperty('a')); 429 | assert(app.tasks.hasOwnProperty('b')); 430 | assert(app.tasks.hasOwnProperty('c')); 431 | cb(); 432 | }); 433 | 434 | base.register('bar', function(app) { 435 | app.register('sub', function(sub) { 436 | sub.task('a', function() {}); 437 | sub.task('b', function() {}); 438 | sub.task('c', function() {}); 439 | }); 440 | }); 441 | 442 | base.getGenerator('foo'); 443 | }); 444 | 445 | it('should invoke a sub-generator from node_modules by name', function(cb) { 446 | base.register('abc', function(app) { 447 | assert(!app.tasks.a); 448 | assert(!app.tasks.b); 449 | assert(!app.tasks.c); 450 | 451 | app.extendWith('xyz'); 452 | assert(app.tasks.a); 453 | assert(app.tasks.b); 454 | assert(app.tasks.c); 455 | cb(); 456 | }); 457 | 458 | base.register('xyz', function(app) { 459 | app.extendWith('generate-foo'); 460 | }); 461 | 462 | base.getGenerator('abc'); 463 | }); 464 | 465 | it('should invoke a sub-generator from node_modules by alias', function(cb) { 466 | base.register('generate-foo'); 467 | 468 | base.register('abc', function(app) { 469 | assert(!app.tasks.a); 470 | assert(!app.tasks.b); 471 | assert(!app.tasks.c); 472 | 473 | app.extendWith('xyz'); 474 | assert(app.tasks.a); 475 | assert(app.tasks.b); 476 | assert(app.tasks.c); 477 | cb(); 478 | }); 479 | 480 | base.register('xyz', function(app) { 481 | app.extendWith('foo'); 482 | }); 483 | 484 | base.getGenerator('abc'); 485 | }); 486 | 487 | it('should invoke an array of sub-generators', function(cb) { 488 | base.register('foo', function(app) { 489 | app.register('one', function(app) { 490 | app.task('a', function() {}); 491 | }); 492 | app.register('two', function(app) { 493 | app.task('b', function() {}); 494 | }); 495 | 496 | app.extendWith(['one', 'two']); 497 | 498 | assert(app.tasks.hasOwnProperty('a')); 499 | assert(app.tasks.hasOwnProperty('b')); 500 | cb(); 501 | }); 502 | 503 | base.getGenerator('foo'); 504 | }); 505 | 506 | it('should invoke sub-generators from sub-generators', function(cb) { 507 | base.register('foo', function(app) { 508 | app.register('one', function(sub) { 509 | sub.register('a', function(a) { 510 | a.task('a', function() {}); 511 | }); 512 | }); 513 | 514 | app.register('two', function(sub) { 515 | sub.register('a', function(a) { 516 | a.task('b', function() {}); 517 | }); 518 | }); 519 | 520 | app.extendWith('one.a'); 521 | app.extendWith('two.a'); 522 | 523 | assert(app.tasks.hasOwnProperty('a')); 524 | assert(app.tasks.hasOwnProperty('b')); 525 | cb(); 526 | }); 527 | 528 | base.getGenerator('foo'); 529 | }); 530 | 531 | it('should invoke an array of sub-generators from sub-generators', function(cb) { 532 | base.register('foo', function(app) { 533 | app.register('one', function(sub) { 534 | sub.register('a', function(a) { 535 | a.task('a', function() {}); 536 | }); 537 | }); 538 | 539 | app.register('two', function(sub) { 540 | sub.register('a', function(a) { 541 | a.task('b', function() {}); 542 | }); 543 | }); 544 | 545 | app.extendWith(['one.a', 'two.a']); 546 | 547 | assert(app.tasks.hasOwnProperty('a')); 548 | assert(app.tasks.hasOwnProperty('b')); 549 | cb(); 550 | }); 551 | 552 | base.getGenerator('foo'); 553 | }); 554 | 555 | it('should invoke sub-generator that invokes another generator', function(cb) { 556 | base.register('foo', function(app) { 557 | app.extendWith('bar'); 558 | assert(app.tasks.hasOwnProperty('a')); 559 | assert(app.tasks.hasOwnProperty('b')); 560 | assert(app.tasks.hasOwnProperty('c')); 561 | cb(); 562 | }); 563 | 564 | base.register('bar', function(app) { 565 | app.extendWith('baz'); 566 | }); 567 | 568 | base.register('baz', function(app) { 569 | app.task('a', function() {}); 570 | app.task('b', function() {}); 571 | app.task('c', function() {}); 572 | }); 573 | 574 | base.getGenerator('foo'); 575 | }); 576 | 577 | it('should invoke sub-generator that invokes another sub-generator', function(cb) { 578 | base.register('foo', function(app) { 579 | app.extendWith('bar.sub'); 580 | assert(app.tasks.hasOwnProperty('a')); 581 | assert(app.tasks.hasOwnProperty('b')); 582 | assert(app.tasks.hasOwnProperty('c')); 583 | cb(); 584 | }); 585 | 586 | base.register('bar', function(app) { 587 | app.register('sub', function(sub) { 588 | sub.extendWith('baz.sub'); 589 | }); 590 | }); 591 | 592 | base.register('baz', function(app) { 593 | app.register('sub', function(sub) { 594 | sub.task('a', function() {}); 595 | sub.task('b', function() {}); 596 | sub.task('c', function() {}); 597 | }); 598 | }); 599 | 600 | base.getGenerator('foo'); 601 | }); 602 | 603 | it('should invoke sub-generator that invokes another sub-generator', function(cb) { 604 | base.register('foo', function(app) { 605 | app.extendWith('bar.sub'); 606 | assert(app.tasks.hasOwnProperty('a')); 607 | assert(app.tasks.hasOwnProperty('b')); 608 | assert(app.tasks.hasOwnProperty('c')); 609 | cb(); 610 | }); 611 | 612 | base.register('bar', function(app) { 613 | app.register('sub', function(sub) { 614 | sub.extendWith('baz.sub'); 615 | }); 616 | }); 617 | 618 | base.register('baz', function(app) { 619 | app.register('sub', function(sub) { 620 | sub.task('a', function() {}); 621 | sub.task('b', function() {}); 622 | sub.task('c', function() {}); 623 | }); 624 | }); 625 | 626 | base.getGenerator('foo'); 627 | }); 628 | }); 629 | }); 630 | -------------------------------------------------------------------------------- /test/app.generateEach.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var isApp = require('./support/is-app'); 6 | var Base = require('base'); 7 | var config = require('base-config-process'); 8 | var option = require('base-option'); 9 | var generators = require('..'); 10 | Base.use(isApp()); 11 | var base; 12 | 13 | describe('.generate', function() { 14 | beforeEach(function() { 15 | base = new Base(); 16 | base.use(generators()); 17 | base.use(option()); 18 | }); 19 | 20 | describe('config.process', function(cb) { 21 | it('should run tasks when the base-config plugin is used', function(cb) { 22 | base.use(config()); 23 | var count = 0; 24 | base.task('default', function(next) { 25 | count++; 26 | next(); 27 | }); 28 | 29 | base.generate('default', function(err) { 30 | assert(!err); 31 | assert.equal(count, 1); 32 | cb(); 33 | }); 34 | }); 35 | 36 | it('should run handle errors when the base-config plugin is used', function(cb) { 37 | base.use(config()); 38 | var count = 0; 39 | base.task('default', function(next) { 40 | count++; 41 | next(new Error('fooo')); 42 | }); 43 | 44 | base.generate('default', function(err) { 45 | assert.equal(err.message, 'fooo'); 46 | assert.equal(count, 1); 47 | cb(); 48 | }); 49 | }); 50 | 51 | it('should handle config errors when the base-config plugin is used', function(cb) { 52 | base.use(config()); 53 | var count = 0; 54 | 55 | base.config.map('foo', function(val, key, config, next) { 56 | count++; 57 | next(new Error('fooo')); 58 | }); 59 | 60 | base.set('cache.config', {foo: true}); 61 | 62 | base.task('default', function(next) { 63 | count--; 64 | next(); 65 | }); 66 | 67 | base.generate('default', function(err) { 68 | assert(err); 69 | assert.equal(err.message, 'fooo'); 70 | assert.equal(count, 1); 71 | cb(); 72 | }); 73 | }); 74 | }); 75 | 76 | describe('generators', function(cb) { 77 | it('should throw an error when a generator is not found', function(cb) { 78 | base.generate('fdsslsllsfjssl', function(err) { 79 | assert(err); 80 | assert.equal('Cannot find generator: "fdsslsllsfjssl"', err.message); 81 | cb(); 82 | }); 83 | }); 84 | 85 | it('should *not* throw an error when the default task is not found', function(cb) { 86 | base.register('foo', function() {}); 87 | base.generate('foo:default', function(err) { 88 | assert(!err); 89 | cb(); 90 | }); 91 | }); 92 | 93 | it('should not throw an error when a default generator is not found', function(cb) { 94 | base.generate('default', function(err) { 95 | assert(!err); 96 | cb(); 97 | }); 98 | }); 99 | 100 | it('should not throw an error when a default task and default generator is not found', function(cb) { 101 | base.generate('default:default', function(err) { 102 | assert(!err); 103 | cb(); 104 | }); 105 | }); 106 | 107 | // special case 108 | it('should throw an error when a generator is not found in argv.cwd', function(cb) { 109 | base.option('cwd', 'foo/bar/baz'); 110 | base.generate('sflsjljskksl', function(err) { 111 | assert(err); 112 | assert.equal('Cannot find generator: "sflsjljskksl" in "foo/bar/baz"', err.message); 113 | cb(); 114 | }); 115 | }); 116 | 117 | it('should not reformat error messages that are not about invalid tasks', function(cb) { 118 | base.task('default', function(cb) { 119 | cb(new Error('whatever')); 120 | }); 121 | 122 | base.generate('default', function(err) { 123 | assert(err); 124 | assert.equal(err.message, 'whatever'); 125 | cb(); 126 | }); 127 | }); 128 | 129 | it('should not throw an error when the default task is not defined', function(cb) { 130 | base.register('foo', function() {}); 131 | base.register('bar', function() {}); 132 | base.generate('foo', ['default'], function(err) { 133 | if (err) return cb(err); 134 | 135 | base.generate('bar', function(err) { 136 | if (err) return cb(err); 137 | 138 | cb(); 139 | }); 140 | }); 141 | }); 142 | 143 | it('should run a task on the instance', function(cb) { 144 | base.task('abc123', function(next) { 145 | next(); 146 | }); 147 | 148 | base.generate('abc123', function(err) { 149 | assert(!err); 150 | cb(); 151 | }); 152 | }); 153 | 154 | it('should run same-named task instead of a generator', function(cb) { 155 | base.register('123xyz', function(app) { 156 | cb(new Error('expected the task to run first')); 157 | }); 158 | 159 | base.task('123xyz', function() { 160 | cb(); 161 | }); 162 | 163 | base.generate('123xyz', function(err) { 164 | assert(!err); 165 | }); 166 | }); 167 | 168 | it('should run a task instead of a generator with a default task', function(cb) { 169 | base.register('123xyz', function(app) { 170 | app.task('default', function() { 171 | cb(new Error('expected the task to run first')); 172 | }); 173 | }); 174 | base.task('123xyz', function() { 175 | cb(); 176 | }); 177 | base.generate('123xyz', function(err) { 178 | assert(!err); 179 | }); 180 | }); 181 | 182 | it('should run a task on a same-named generator when the task is specified', function(cb) { 183 | var count = 0; 184 | base.register('foo', function(app) { 185 | app.task('default', function(next) { 186 | count++; 187 | next(); 188 | }); 189 | }); 190 | 191 | base.task('foo', function() { 192 | cb(new Error('expected the generator to run')); 193 | }); 194 | 195 | base.generate('foo:default', function(err) { 196 | assert(!err); 197 | assert.equal(count, 1); 198 | cb(); 199 | }); 200 | }); 201 | 202 | it('should run an array of tasks that includes a same-named generator', function(cb) { 203 | var count = 0; 204 | base.register('foo', function(app) { 205 | app.task('default', function(next) { 206 | count++; 207 | next(); 208 | }); 209 | }); 210 | 211 | base.register('bar', function(app) { 212 | app.task('baz', function(next) { 213 | count++; 214 | next(); 215 | }); 216 | }); 217 | 218 | base.task('foo', function() { 219 | cb(new Error('expected the generator to run')); 220 | }); 221 | 222 | base.generate(['foo:default', 'bar:baz'], function(err) { 223 | assert(!err); 224 | assert.equal(count, 2); 225 | cb(); 226 | }); 227 | }); 228 | 229 | it('should run a generator from a task with the same name', function(cb) { 230 | base.register('foo', function(app) { 231 | app.task('default', function() { 232 | cb(); 233 | }); 234 | }); 235 | 236 | base.task('foo', function(cb) { 237 | base.generate('foo', cb); 238 | }); 239 | 240 | base.build('foo', function(err) { 241 | if (err) cb(err); 242 | }); 243 | }); 244 | 245 | it('should run the default task on a generator', function(cb) { 246 | base.register('foo', function(app) { 247 | app.task('default', function(next) { 248 | next(); 249 | }); 250 | }); 251 | 252 | base.generate('foo', function(err) { 253 | assert(!err); 254 | cb(); 255 | }); 256 | }); 257 | 258 | it('should run a stringified array of tasks on the instance', function(cb) { 259 | var count = 0; 260 | base.task('a', function(next) { 261 | count++; 262 | next(); 263 | }); 264 | base.task('b', function(next) { 265 | count++; 266 | next(); 267 | }); 268 | base.task('c', function(next) { 269 | count++; 270 | next(); 271 | }); 272 | 273 | base.generate('a,b,c', function(err) { 274 | assert.equal(count, 3); 275 | assert(!err); 276 | cb(); 277 | }); 278 | }); 279 | 280 | it('should run an array of tasks on the instance', function(cb) { 281 | var count = 0; 282 | base.task('a', function(next) { 283 | count++; 284 | next(); 285 | }); 286 | base.task('b', function(next) { 287 | count++; 288 | next(); 289 | }); 290 | base.task('c', function(next) { 291 | count++; 292 | next(); 293 | }); 294 | 295 | base.generate(['a', 'b', 'c'], function(err) { 296 | if (err) return cb(err); 297 | assert.equal(count, 3); 298 | assert(!err); 299 | cb(); 300 | }); 301 | }); 302 | 303 | it('should run the default task on a registered generator', function(cb) { 304 | var count = 0; 305 | base.register('foo', function(app) { 306 | app.task('default', function(next) { 307 | count++; 308 | next(); 309 | }); 310 | }); 311 | 312 | base.generate('foo', function(err) { 313 | if (err) return cb(err); 314 | assert.equal(count, 1); 315 | cb(); 316 | }); 317 | }); 318 | 319 | it('should run an array of generators', function(cb) { 320 | var count = 0; 321 | base.register('foo', function(app) { 322 | app.task('default', function(next) { 323 | count++; 324 | next(); 325 | }); 326 | }); 327 | 328 | base.register('bar', function(app) { 329 | app.task('default', function(next) { 330 | count++; 331 | next(); 332 | }); 333 | }); 334 | 335 | base.generate(['foo', 'bar'], function(err) { 336 | if (err) return cb(err); 337 | assert.equal(count, 2); 338 | cb(); 339 | }); 340 | }); 341 | 342 | it('should run the default task on the default generator', function(cb) { 343 | var count = 0; 344 | base.register('default', function(app) { 345 | app.task('default', function(next) { 346 | count++; 347 | next(); 348 | }); 349 | }); 350 | 351 | base.generate(function(err) { 352 | if (err) return cb(err); 353 | assert.equal(count, 1); 354 | cb(); 355 | }); 356 | }); 357 | 358 | it('should run the specified task on a registered generator', function(cb) { 359 | var count = 0; 360 | base.register('foo', function(app) { 361 | app.task('default', function(next) { 362 | count++; 363 | next(); 364 | }); 365 | 366 | app.task('abc', function(next) { 367 | count++; 368 | next(); 369 | }); 370 | }); 371 | 372 | base.generate('foo:abc', function(err) { 373 | if (err) return cb(err); 374 | assert.equal(count, 1); 375 | cb(); 376 | }); 377 | }); 378 | 379 | it('should run an array of tasks on a registered generator', function(cb) { 380 | var count = 0; 381 | base.register('foo', function(app) { 382 | app.task('default', function(next) { 383 | count++; 384 | next(); 385 | }); 386 | 387 | app.task('a', function(next) { 388 | count++; 389 | next(); 390 | }); 391 | 392 | app.task('b', function(next) { 393 | count++; 394 | next(); 395 | }); 396 | 397 | app.task('c', function(next) { 398 | count++; 399 | next(); 400 | }); 401 | }); 402 | 403 | base.generate('foo:a,b,c', function(err) { 404 | if (err) return cb(err); 405 | assert.equal(count, 3); 406 | cb(); 407 | }); 408 | }); 409 | 410 | it('should run the default tasks on an array of generators', function(cb) { 411 | var count = 0; 412 | base.register('a', function(app) { 413 | this.task('default', function(cb) { 414 | count++; 415 | cb(); 416 | }); 417 | }); 418 | 419 | base.register('b', function(app) { 420 | this.task('default', function(cb) { 421 | count++; 422 | cb(); 423 | }); 424 | }); 425 | 426 | base.register('c', function(app) { 427 | this.task('default', function(cb) { 428 | count++; 429 | cb(); 430 | }); 431 | }); 432 | 433 | base.generate(['a', 'b', 'c'], function(err) { 434 | if (err) return cb(err); 435 | assert.equal(count, 3); 436 | assert(!err); 437 | cb(); 438 | }); 439 | }); 440 | }); 441 | 442 | describe('options', function(cb) { 443 | it('should pass options to generator.options', function(cb) { 444 | var count = 0; 445 | base.register('default', function(app, base, env, options) { 446 | app.task('default', function(next) { 447 | count++; 448 | assert.equal(app.options.foo, 'bar'); 449 | next(); 450 | }); 451 | }); 452 | 453 | base.generate({foo: 'bar'}, function(err) { 454 | if (err) return cb(err); 455 | assert.equal(count, 1); 456 | cb(); 457 | }); 458 | }); 459 | 460 | it('should expose options on generator options', function(cb) { 461 | var count = 0; 462 | base.register('default', function(app, base, env, options) { 463 | app.task('default', function(next) { 464 | count++; 465 | assert.equal(options.foo, 'bar'); 466 | next(); 467 | }); 468 | }); 469 | 470 | base.generate({foo: 'bar'}, function(err) { 471 | if (err) return cb(err); 472 | assert.equal(count, 1); 473 | cb(); 474 | }); 475 | }); 476 | 477 | it('should not mutate options on parent instance', function(cb) { 478 | var count = 0; 479 | base.register('default', function(app, base, env, options) { 480 | app.task('default', function(next) { 481 | count++; 482 | assert.equal(options.foo, 'bar'); 483 | assert(!base.options.foo); 484 | next(); 485 | }); 486 | }); 487 | 488 | base.generate({foo: 'bar'}, function(err) { 489 | if (err) return cb(err); 490 | assert.equal(count, 1); 491 | cb(); 492 | }); 493 | }); 494 | }); 495 | 496 | describe('default tasks', function(cb) { 497 | it('should run the default task on the default generator', function(cb) { 498 | var count = 0; 499 | base.register('default', function(app) { 500 | app.task('default', function(next) { 501 | count++; 502 | next(); 503 | }); 504 | }); 505 | 506 | base.generate(function(err) { 507 | if (err) return cb(err); 508 | assert.equal(count, 1); 509 | cb(); 510 | }); 511 | }); 512 | 513 | it('should run the default task on a registered generator', function(cb) { 514 | var count = 0; 515 | base.register('foo', function(app) { 516 | app.task('default', function(next) { 517 | count++; 518 | next(); 519 | }); 520 | }); 521 | 522 | base.generate('foo', function(err) { 523 | if (err) return cb(err); 524 | assert.equal(count, 1); 525 | cb(); 526 | }); 527 | }); 528 | }); 529 | 530 | describe('specified tasks', function(cb) { 531 | it('should run the specified task on a registered generator', function(cb) { 532 | var count = 0; 533 | base.register('foo', function(app) { 534 | app.task('default', function(next) { 535 | count++; 536 | next(); 537 | }); 538 | 539 | app.task('abc', function(next) { 540 | count++; 541 | next(); 542 | }); 543 | }); 544 | 545 | base.generate('foo', ['abc'], function(err) { 546 | if (err) return cb(err); 547 | assert.equal(count, 1); 548 | cb(); 549 | }); 550 | }); 551 | 552 | it('should run an array of tasks on a registered generator', function(cb) { 553 | var count = 0; 554 | base.register('foo', function(app) { 555 | app.task('default', function(next) { 556 | count++; 557 | next(); 558 | }); 559 | 560 | app.task('a', function(next) { 561 | count++; 562 | next(); 563 | }); 564 | 565 | app.task('b', function(next) { 566 | count++; 567 | next(); 568 | }); 569 | 570 | app.task('c', function(next) { 571 | count++; 572 | next(); 573 | }); 574 | }); 575 | 576 | base.generate('foo', 'a,b,c', function(err) { 577 | if (err) return cb(err); 578 | assert.equal(count, 3); 579 | cb(); 580 | }); 581 | }); 582 | }); 583 | 584 | describe('sub-generators', function(cb) { 585 | it('should run the default task on a registered sub-generator', function(cb) { 586 | var count = 0; 587 | base.register('foo', function(app) { 588 | app.register('sub', function(sub) { 589 | sub.task('default', function(next) { 590 | count++; 591 | next(); 592 | }); 593 | 594 | sub.task('abc', function(next) { 595 | count++; 596 | next(); 597 | }); 598 | }); 599 | }); 600 | 601 | base.generate('foo.sub', function(err) { 602 | if (err) return cb(err); 603 | assert.equal(count, 1); 604 | cb(); 605 | }); 606 | }); 607 | 608 | it('should run the specified task string on a registered sub-generator', function(cb) { 609 | var count = 0; 610 | base.register('foo', function(app) { 611 | app.register('sub', function(sub) { 612 | sub.task('default', function(next) { 613 | count++; 614 | next(); 615 | }); 616 | 617 | sub.task('abc', function(next) { 618 | count++; 619 | next(); 620 | }); 621 | }); 622 | }); 623 | 624 | base.generate('foo.sub:abc', function(err) { 625 | if (err) return cb(err); 626 | assert.equal(count, 1); 627 | cb(); 628 | }); 629 | }); 630 | 631 | it('should run the specified task array on a registered sub-generator', function(cb) { 632 | var count = 0; 633 | base.register('foo', function(app) { 634 | app.register('sub', function(sub) { 635 | sub.task('default', function(next) { 636 | count++; 637 | next(); 638 | }); 639 | 640 | sub.task('abc', function(next) { 641 | count++; 642 | next(); 643 | }); 644 | }); 645 | }); 646 | 647 | base.generate('foo.sub', ['abc'], function(err) { 648 | if (err) return cb(err); 649 | assert.equal(count, 1); 650 | cb(); 651 | }); 652 | }); 653 | 654 | it('should run an of stringified-tasks on a registered sub-generator', function(cb) { 655 | var count = 0; 656 | base.register('foo', function(app) { 657 | app.register('bar', function(bar) { 658 | bar.task('default', function(next) { 659 | count++; 660 | next(); 661 | }); 662 | 663 | bar.task('a', function(next) { 664 | count++; 665 | next(); 666 | }); 667 | 668 | bar.task('b', function(next) { 669 | count++; 670 | next(); 671 | }); 672 | 673 | bar.task('c', function(next) { 674 | count++; 675 | next(); 676 | }); 677 | }); 678 | }); 679 | 680 | base.generate('foo.bar:a,b,c', function(err) { 681 | if (err) return cb(err); 682 | assert.equal(count, 3); 683 | cb(); 684 | }); 685 | }); 686 | 687 | it('should run an array of tasks on a registered sub-generator', function(cb) { 688 | var count = 0; 689 | base.register('foo', function(app) { 690 | app.register('bar', function(bar) { 691 | bar.task('default', function(next) { 692 | count++; 693 | next(); 694 | }); 695 | 696 | bar.task('a', function(next) { 697 | count++; 698 | next(); 699 | }); 700 | 701 | bar.task('b', function(next) { 702 | count++; 703 | next(); 704 | }); 705 | 706 | bar.task('c', function(next) { 707 | count++; 708 | next(); 709 | }); 710 | }); 711 | }); 712 | 713 | base.generate('foo.bar', ['a', 'b', 'c'], function(err) { 714 | if (err) return cb(err); 715 | assert.equal(count, 3); 716 | cb(); 717 | }); 718 | }); 719 | 720 | it('should run an multiple tasks on a registered sub-generator', function(cb) { 721 | var count = 0; 722 | base.register('foo', function(app) { 723 | app.register('bar', function(bar) { 724 | bar.task('default', function(next) { 725 | count++; 726 | next(); 727 | }); 728 | 729 | bar.task('a', function(next) { 730 | count++; 731 | next(); 732 | }); 733 | 734 | bar.task('b', function(next) { 735 | count++; 736 | next(); 737 | }); 738 | 739 | bar.task('c', function(next) { 740 | count++; 741 | next(); 742 | }); 743 | }); 744 | }); 745 | 746 | base.generate('foo.bar', 'a,b,c', function(err) { 747 | if (err) return cb(err); 748 | assert.equal(count, 3); 749 | cb(); 750 | }); 751 | }); 752 | 753 | it('should run an multiple tasks on a registered sub-generator', function(cb) { 754 | var count = 0; 755 | base.register('foo', function(app) { 756 | app.register('bar', function(bar) { 757 | bar.task('default', function(next) { 758 | count++; 759 | next(); 760 | }); 761 | 762 | bar.task('a', function(next) { 763 | count++; 764 | next(); 765 | }); 766 | 767 | bar.task('b', function(next) { 768 | count++; 769 | next(); 770 | }); 771 | 772 | bar.task('c', function(next) { 773 | count++; 774 | next(); 775 | }); 776 | }); 777 | }); 778 | 779 | base.register('qux', function(app) { 780 | app.register('fez', function(fez) { 781 | fez.task('default', function(next) { 782 | count++; 783 | next(); 784 | }); 785 | 786 | fez.task('a', function(next) { 787 | count++; 788 | next(); 789 | }); 790 | 791 | fez.task('b', function(next) { 792 | count++; 793 | next(); 794 | }); 795 | 796 | fez.task('c', function(next) { 797 | count++; 798 | next(); 799 | }); 800 | }); 801 | }); 802 | 803 | base.generate(['foo.bar:a,b,c', 'qux.fez:a,b,c'], function(err) { 804 | if (err) return cb(err); 805 | assert.equal(count, 6); 806 | cb(); 807 | }); 808 | }); 809 | }); 810 | 811 | describe('cross-generator', function(cb) { 812 | it('should run a generator from another generator', function(cb) { 813 | var res = ''; 814 | 815 | base.register('foo', function(app, two) { 816 | app.register('sub', function(sub) { 817 | sub.task('default', function(next) { 818 | res += 'foo > sub > default '; 819 | base.generate('bar.sub', next); 820 | }); 821 | }); 822 | }); 823 | 824 | base.register('bar', function(app) { 825 | app.register('sub', function(sub) { 826 | sub.task('default', function(next) { 827 | res += 'bar > sub > default '; 828 | next(); 829 | }); 830 | }); 831 | }); 832 | 833 | base.generate('foo.sub', function(err) { 834 | if (err) return cb(err); 835 | assert.equal(res, 'foo > sub > default bar > sub > default '); 836 | cb(); 837 | }); 838 | }); 839 | 840 | it('should run the specified task on a registered sub-generator', function(cb) { 841 | var count = 0; 842 | base.register('foo', function(app) { 843 | app.register('sub', function(sub) { 844 | sub.task('default', function(next) { 845 | count++; 846 | next(); 847 | }); 848 | 849 | sub.task('abc', function(next) { 850 | count++; 851 | next(); 852 | }); 853 | }); 854 | }); 855 | 856 | base.generate('foo.sub:abc', function(err) { 857 | if (err) return cb(err); 858 | assert.equal(count, 1); 859 | cb(); 860 | }); 861 | }); 862 | }); 863 | 864 | describe('events', function(cb) { 865 | it('should emit generate', function(cb) { 866 | var count = 0; 867 | 868 | base.on('generate', function() { 869 | count++; 870 | }); 871 | 872 | base.register('foo', function(app) { 873 | app.register('sub', function(sub) { 874 | sub.task('default', function(next) { 875 | next(); 876 | }); 877 | 878 | sub.task('abc', function(next) { 879 | count++; 880 | next(); 881 | }); 882 | }); 883 | }); 884 | 885 | base.generate('foo.sub', ['abc'], function(err) { 886 | if (err) return cb(err); 887 | assert.equal(count, 2); 888 | cb(); 889 | }); 890 | }); 891 | 892 | it('should expose the generator alias as the first parameter', function(cb) { 893 | base.on('generate', function(name) { 894 | assert.equal(name, 'sub'); 895 | cb(); 896 | }); 897 | 898 | base.register('foo', function(app) { 899 | app.register('sub', function(sub) { 900 | sub.task('default', function(next) { 901 | next(); 902 | }); 903 | 904 | sub.task('abc', function(next) { 905 | next(); 906 | }); 907 | }); 908 | }); 909 | 910 | base.generate('foo.sub:abc', function(err) { 911 | if (err) return cb(err); 912 | }); 913 | }); 914 | 915 | it('should expose the tasks array as the second parameter', function(cb) { 916 | base.on('generate', function(name, tasks) { 917 | assert.deepEqual(tasks, ['abc']); 918 | cb(); 919 | }); 920 | 921 | base.register('foo', function(app) { 922 | app.register('sub', function(sub) { 923 | sub.task('default', function(next) { 924 | next(); 925 | }); 926 | 927 | sub.task('abc', function(next) { 928 | next(); 929 | }); 930 | }); 931 | }); 932 | 933 | base.generate('foo.sub:abc', function(err) { 934 | if (err) return cb(err); 935 | }); 936 | }); 937 | }); 938 | }); 939 | -------------------------------------------------------------------------------- /test/app.generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var path = require('path'); 5 | var assert = require('assert'); 6 | var isApp = require('./support/is-app'); 7 | var option = require('base-option'); 8 | var Base = require('base'); 9 | var generators = require('..'); 10 | var base; 11 | 12 | var fixtures = path.resolve.bind(path, __dirname, 'fixtures'); 13 | 14 | describe('.generator', function() { 15 | beforeEach(function() { 16 | Base.use(isApp()); 17 | base = new Base(); 18 | base.use(generators()); 19 | base.use(option()); 20 | 21 | base.option('toAlias', function(key) { 22 | return key.replace(/^generate-(.*)/, '$1'); 23 | }); 24 | }); 25 | 26 | describe('generator', function() { 27 | it('should get a generator by alias', function() { 28 | base.register('generate-foo', require('generate-foo')); 29 | var gen = base.getGenerator('foo'); 30 | assert(gen); 31 | assert.equal(gen.env.name, 'generate-foo'); 32 | assert.equal(gen.env.alias, 'foo'); 33 | }); 34 | 35 | it('should get a generator using a custom lookup function', function() { 36 | base.register('generate-foo', function() {}); 37 | base.register('generate-bar', function() {}); 38 | 39 | var gen = base.getGenerator('foo', { 40 | lookup: function(key) { 41 | return ['generate-' + key, 'verb-' + key + '-generator', key]; 42 | } 43 | }); 44 | 45 | assert(gen); 46 | assert.equal(gen.env.name, 'generate-foo'); 47 | assert.equal(gen.env.alias, 'foo'); 48 | }); 49 | }); 50 | 51 | describe('register > function', function() { 52 | it('should register a generator function by name', function() { 53 | base.generator('foo', function() {}); 54 | assert(base.generators.hasOwnProperty('foo')); 55 | }); 56 | 57 | it('should register a generator function by alias', function() { 58 | base.generator('generate-abc', function() {}); 59 | assert(base.generators.hasOwnProperty('generate-abc')); 60 | }); 61 | }); 62 | 63 | describe('get > alias', function() { 64 | it('should get a generator by alias', function() { 65 | base.generator('generate-abc', function() {}); 66 | var abc = base.generator('abc'); 67 | assert(abc); 68 | assert.equal(typeof abc, 'object'); 69 | }); 70 | }); 71 | 72 | describe('get > name', function() { 73 | it('should get a generator by name', function() { 74 | base.generator('generate-abc', function() {}); 75 | var abc = base.generator('generate-abc'); 76 | assert(abc); 77 | assert.equal(typeof abc, 'object'); 78 | }); 79 | }); 80 | 81 | describe('generators', function() { 82 | it('should invoke a registered generator when `getGenerator` is called', function(cb) { 83 | base.register('foo', function(app) { 84 | app.task('default', function() {}); 85 | cb(); 86 | }); 87 | base.getGenerator('foo'); 88 | }); 89 | 90 | it('should expose the generator instance on `app`', function(cb) { 91 | base.register('foo', function(app) { 92 | app.task('default', function(next) { 93 | assert.equal(app.get('a'), 'b'); 94 | next(); 95 | }); 96 | }); 97 | 98 | var foo = base.getGenerator('foo'); 99 | foo.set('a', 'b'); 100 | foo.build('default', function(err) { 101 | if (err) return cb(err); 102 | cb(); 103 | }); 104 | }); 105 | 106 | it('should expose the "base" instance on `base`', function(cb) { 107 | base.set('x', 'z'); 108 | base.register('foo', function(app, base) { 109 | app.task('default', function(next) { 110 | assert.equal(base.get('x'), 'z'); 111 | next(); 112 | }); 113 | }); 114 | 115 | var foo = base.getGenerator('foo'); 116 | foo.set('a', 'b'); 117 | foo.build('default', function(err) { 118 | if (err) return cb(err); 119 | cb(); 120 | }); 121 | }); 122 | 123 | it('should expose the "env" object on `env`', function(cb) { 124 | base.register('foo', function(app, base, env) { 125 | app.task('default', function(next) { 126 | assert.equal(env.alias, 'foo'); 127 | next(); 128 | }); 129 | }); 130 | 131 | base.getGenerator('foo').build('default', function(err) { 132 | if (err) return cb(err); 133 | cb(); 134 | }); 135 | }); 136 | 137 | it('should expose an app\'s generators on app.generators', function(cb) { 138 | base.register('foo', function(app) { 139 | app.register('a', function() {}); 140 | app.register('b', function() {}); 141 | 142 | app.generators.hasOwnProperty('a'); 143 | app.generators.hasOwnProperty('b'); 144 | cb(); 145 | }); 146 | 147 | base.getGenerator('foo'); 148 | }); 149 | 150 | it('should expose all root generators on base.generators', function(cb) { 151 | base.register('foo', function(app, b) { 152 | b.generators.hasOwnProperty('foo'); 153 | b.generators.hasOwnProperty('bar'); 154 | b.generators.hasOwnProperty('baz'); 155 | cb(); 156 | }); 157 | 158 | base.register('bar', function(app, base) {}); 159 | base.register('baz', function(app, base) {}); 160 | base.getGenerator('foo'); 161 | }); 162 | }); 163 | 164 | describe('cross-generators', function() { 165 | it('should get a generator from another generator', function(cb) { 166 | base.register('foo', function(app, b) { 167 | var bar = b.getGenerator('bar'); 168 | assert(bar); 169 | cb(); 170 | }); 171 | 172 | base.register('bar', function(app, base) {}); 173 | base.register('baz', function(app, base) {}); 174 | base.getGenerator('foo'); 175 | }); 176 | 177 | it('should set options on another generator instance', function(cb) { 178 | base.generator('foo', function(app) { 179 | app.task('default', function(next) { 180 | assert.equal(app.option('abc'), 'xyz'); 181 | next(); 182 | }); 183 | }); 184 | 185 | base.generator('bar', function(app, b) { 186 | var foo = b.getGenerator('foo'); 187 | foo.option('abc', 'xyz'); 188 | foo.build(function(err) { 189 | if (err) return cb(err); 190 | cb(); 191 | }); 192 | }); 193 | }); 194 | }); 195 | 196 | describe('generators > filepath', function() { 197 | it('should register a generator function from a file path', function() { 198 | var one = base.generator('one', fixtures('one/generator.js')); 199 | assert(base.generators.hasOwnProperty('one')); 200 | assert(typeof base.generators.one === 'object'); 201 | assert.deepEqual(base.generators.one, one); 202 | }); 203 | 204 | it('should get a registered generator by name', function() { 205 | var one = base.generator('one', fixtures('one/generator.js')); 206 | var two = base.generator('two', fixtures('two/generator.js')); 207 | assert(base.generator('one')); 208 | assert(base.generator('two')); 209 | }); 210 | }); 211 | 212 | describe('tasks', function() { 213 | it('should expose a generator\'s tasks on app.tasks', function(cb) { 214 | base.register('foo', function(app) { 215 | app.task('a', function() {}); 216 | app.task('b', function() {}); 217 | assert(app.tasks.a); 218 | assert(app.tasks.b); 219 | cb(); 220 | }); 221 | 222 | base.getGenerator('foo'); 223 | }); 224 | 225 | it('should get tasks from another generator', function(cb) { 226 | base.register('foo', function(app, b) { 227 | var baz = b.getGenerator('baz'); 228 | var task = baz.tasks.aaa; 229 | assert(task); 230 | cb(); 231 | }); 232 | 233 | base.register('bar', function(app, base) {}); 234 | base.register('baz', function(app, base) { 235 | app.task('aaa', function() {}); 236 | }); 237 | base.getGenerator('foo'); 238 | }); 239 | }); 240 | 241 | describe('namespace', function() { 242 | it('should expose `app.namespace`', function(cb) { 243 | base.generator('foo', function(app) { 244 | assert(typeof app.namespace, 'string'); 245 | cb(); 246 | }); 247 | }); 248 | 249 | it('should create namespace from generator alias', function(cb) { 250 | base.generator('generate-foo', function(app) { 251 | assert.equal(app.namespace, 'base.foo'); 252 | cb(); 253 | }); 254 | }); 255 | 256 | it('should create sub-generator namespace from parent namespace and alias', function(cb) { 257 | var name = base._name; 258 | base.generator('generate-foo', function(app) { 259 | assert.equal(app.namespace, name + '.foo'); 260 | 261 | app.generator('generate-bar', function(bar) { 262 | assert.equal(bar.namespace, name + '.foo.bar'); 263 | 264 | bar.generator('generate-baz', function(baz) { 265 | assert.equal(baz.namespace, name + '.foo.bar.baz'); 266 | 267 | baz.generator('generate-qux', function(qux) { 268 | assert.equal(qux.namespace, name + '.foo.bar.baz.qux'); 269 | cb(); 270 | }); 271 | }); 272 | }); 273 | }); 274 | }); 275 | 276 | it('should expose namespace on `this`', function(cb) { 277 | base.generator('generate-foo', function(app, first) { 278 | assert.equal(this.namespace, 'base.foo'); 279 | 280 | this.generator('generate-bar', function() { 281 | assert.equal(this.namespace, 'base.foo.bar'); 282 | 283 | this.generator('generate-baz', function() { 284 | assert.equal(this.namespace, 'base.foo.bar.baz'); 285 | 286 | this.generator('generate-qux', function() { 287 | assert.equal(this.namespace, 'base.foo.bar.baz.qux'); 288 | assert.equal(app.namespace, 'base.foo'); 289 | assert.equal(first.namespace, 'base'); 290 | cb(); 291 | }); 292 | }); 293 | }); 294 | }); 295 | }); 296 | }); 297 | }); 298 | -------------------------------------------------------------------------------- /test/app.getGenerator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var assert = require('assert'); 5 | var isApp = require('./support/is-app'); 6 | var Base = require('base'); 7 | var generators = require('..'); 8 | var base; 9 | 10 | var fixtures = path.resolve.bind(path, __dirname + '/fixtures'); 11 | 12 | describe('.generator', function() { 13 | beforeEach(function() { 14 | Base.use(isApp()); 15 | base = new Base(); 16 | base.use(generators()); 17 | }); 18 | 19 | it('should get a generator from the base instance', function() { 20 | base.register('abc', function() {}); 21 | var generator = base.getGenerator('abc'); 22 | assert(generator); 23 | assert.equal(typeof generator, 'object'); 24 | assert.equal(generator.name, 'abc'); 25 | }); 26 | 27 | it('should fail when a generator is not found', function() { 28 | var generator = base.getGenerator('whatever'); 29 | assert(!generator); 30 | }); 31 | 32 | it('should get a generator from the base instance from a nested generator', function() { 33 | base.register('abc', function() {}); 34 | base.register('xyz', function(app) { 35 | app.register('sub', function(sub) { 36 | var generator = base.getGenerator('abc'); 37 | assert(generator); 38 | assert.equal(typeof generator, 'object'); 39 | assert.equal(generator.name, 'abc'); 40 | }); 41 | }); 42 | base.getGenerator('xyz'); 43 | }); 44 | 45 | it('should get a generator from the base instance using `this`', function() { 46 | base.register('abc', function() {}); 47 | base.register('xyz', function(app) { 48 | app.register('sub', function(sub) { 49 | var generator = this.getGenerator('abc'); 50 | assert(generator); 51 | assert.equal(typeof generator, 'object'); 52 | assert.equal(generator.name, 'abc'); 53 | }); 54 | }); 55 | base.getGenerator('xyz'); 56 | }); 57 | 58 | it('should get a base generator from "app" from a nested generator', function() { 59 | base.register('abc', function() {}); 60 | base.register('xyz', function(app) { 61 | app.register('sub', function(sub) { 62 | var generator = app.getGenerator('abc'); 63 | assert(generator); 64 | assert.equal(typeof generator, 'object'); 65 | assert.equal(generator.name, 'abc'); 66 | }); 67 | }); 68 | base.getGenerator('xyz'); 69 | }); 70 | 71 | it('should get a nested generator', function() { 72 | base.register('abc', function(abc) { 73 | abc.register('def', function(def) {}); 74 | }); 75 | 76 | var generator = base.getGenerator('abc.def'); 77 | assert(generator); 78 | assert.equal(typeof generator, 'object'); 79 | assert.equal(generator.name, 'def'); 80 | }); 81 | 82 | it('should get a deeply nested generator', function() { 83 | base.register('abc', function(abc) { 84 | abc.register('def', function(def) { 85 | def.register('ghi', function(ghi) { 86 | ghi.register('jkl', function(jkl) { 87 | jkl.register('mno', function() {}); 88 | }); 89 | }); 90 | }); 91 | }); 92 | 93 | var generator = base.getGenerator('abc.def.ghi.jkl.mno'); 94 | assert(generator); 95 | assert.equal(typeof generator, 'object'); 96 | assert.equal(generator.name, 'mno'); 97 | }); 98 | 99 | it('should get a generator that was registered by path', function() { 100 | base.register('a', fixtures('generators/a')); 101 | var generator = base.getGenerator('a'); 102 | 103 | assert(generator); 104 | assert(generator.tasks); 105 | assert(generator.tasks.hasOwnProperty('default')); 106 | }); 107 | }); 108 | -------------------------------------------------------------------------------- /test/app.lookupGenerator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var isApp = require('./support/is-app'); 6 | var option = require('base-option'); 7 | var Base = require('base'); 8 | var generators = require('..'); 9 | var base; 10 | 11 | describe('.lookupGenerator', function() { 12 | beforeEach(function() { 13 | Base.use(isApp()); 14 | base = new Base(); 15 | base.use(generators()); 16 | base.use(option()); 17 | 18 | base.option('toAlias', function(key) { 19 | return key.replace(/^generate-(.*)/, '$1'); 20 | }); 21 | }); 22 | 23 | it('should get a generator using a custom lookup function', function() { 24 | base.register('generate-foo', function() {}); 25 | base.register('generate-bar', function() {}); 26 | var gen = base.lookupGenerator('foo', function(key) { 27 | return ['generate-' + key, 'verb-' + key + '-generator', key]; 28 | }); 29 | 30 | assert(gen); 31 | assert.equal(gen.env.name, 'generate-foo'); 32 | assert.equal(gen.env.alias, 'foo'); 33 | }); 34 | 35 | it('should get a generator using a custom lookup function passed on options', function() { 36 | base.register('generate-foo', function() {}); 37 | base.register('generate-bar', function() {}); 38 | 39 | var gen = base.getGenerator('foo', { 40 | lookup: function(key) { 41 | return ['generate-' + key, 'verb-' + key + '-generator', key]; 42 | } 43 | }); 44 | 45 | assert(gen); 46 | assert.equal(gen.env.name, 'generate-foo'); 47 | assert.equal(gen.env.alias, 'foo'); 48 | }); 49 | 50 | it('should return undefined when nothing is found', function() { 51 | var gen = base.lookupGenerator('fofofofofo', function(key) { 52 | return ['generate-' + key, 'verb-' + key + '-generator', key]; 53 | }); 54 | 55 | assert(!gen); 56 | }); 57 | 58 | it('should throw an error when a function is not passed', function(cb) { 59 | try { 60 | base.lookupGenerator('foo'); 61 | cb(new Error('expected an error')); 62 | } catch (err) { 63 | assert.equal(err.message, 'expected `fn` to be a lookup function'); 64 | cb(); 65 | } 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/app.matchGenerator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var path = require('path'); 5 | var assert = require('assert'); 6 | var option = require('base-option'); 7 | var spawn = require('cross-spawn'); 8 | var exists = require('fs-exists-sync'); 9 | var Base = require('base'); 10 | var isApp = require('./support/is-app'); 11 | var generators = require('..'); 12 | var base; 13 | 14 | describe('.matchGenerator', function() { 15 | before(function(cb) { 16 | if (!exists(path.resolve(__dirname, '../node_modules/generate-foo'))) { 17 | spawn('npm', ['install', '--global', 'generate-foo'], {stdio: 'inherit'}) 18 | .on('error', cb) 19 | .on('close', function(code, err) { 20 | cb(err, code); 21 | }); 22 | } else { 23 | cb(); 24 | } 25 | }); 26 | 27 | beforeEach(function() { 28 | Base.use(isApp()); 29 | base = new Base(); 30 | base.use(generators()); 31 | base.use(option()); 32 | 33 | base.option('toAlias', function(key) { 34 | return key.replace(/^generate-(.*)/, '$1'); 35 | }); 36 | }); 37 | 38 | it('should match a generator by name', function() { 39 | base.register('generate-foo'); 40 | 41 | var gen = base.matchGenerator('generate-foo'); 42 | assert(gen); 43 | assert.equal(gen.env.name, 'generate-foo'); 44 | assert.equal(gen.env.alias, 'foo'); 45 | }); 46 | 47 | it('should match a generator by alias', function() { 48 | base.register('generate-foo'); 49 | 50 | var gen = base.matchGenerator('foo'); 51 | assert(gen); 52 | assert.equal(gen.env.name, 'generate-foo'); 53 | assert.equal(gen.env.alias, 'foo'); 54 | }); 55 | 56 | it('should match a generator by path', function() { 57 | base.register('generate-foo'); 58 | var gen = base.matchGenerator(require.resolve('generate-foo')); 59 | assert(gen); 60 | assert.equal(gen.env.name, 'generate-foo'); 61 | assert.equal(gen.env.alias, 'foo'); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/app.register.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var path = require('path'); 5 | var assert = require('assert'); 6 | var option = require('base-option'); 7 | var Base = require('./support/app'); 8 | var generators = require('..'); 9 | var base; 10 | 11 | var fixtures = path.resolve.bind(path, __dirname + '/fixtures'); 12 | 13 | describe('.register', function() { 14 | beforeEach(function() { 15 | base = new Base(); 16 | base.use(option()); 17 | base.use(generators()); 18 | }); 19 | 20 | describe('function', function() { 21 | it('should register a generator a function', function() { 22 | base.register('foo', function() {}); 23 | var foo = base.getGenerator('foo'); 24 | assert(foo); 25 | assert.equal(foo.env.alias, 'foo'); 26 | }); 27 | 28 | it('should get a task from a generator registered as a function', function() { 29 | base.register('foo', function(foo) { 30 | foo.task('default', function() {}); 31 | }); 32 | var generator = base.getGenerator('foo'); 33 | assert(generator); 34 | assert(generator.tasks); 35 | assert(generator.tasks.hasOwnProperty('default')); 36 | }); 37 | 38 | it('should get a generator from a generator registered as a function', function() { 39 | base.register('foo', function(foo) { 40 | foo.register('bar', function(bar) {}); 41 | }); 42 | var bar = base.getGenerator('foo.bar'); 43 | assert(bar); 44 | assert.equal(bar.env.alias, 'bar'); 45 | }); 46 | 47 | it('should get a sub-generator from a generator registered as a function', function() { 48 | base.register('foo', function(foo) { 49 | foo.register('bar', function(bar) { 50 | bar.task('something', function() {}); 51 | }); 52 | }); 53 | var bar = base.getGenerator('foo.bar'); 54 | assert(bar); 55 | assert(bar.tasks); 56 | assert(bar.tasks.hasOwnProperty('something')); 57 | }); 58 | 59 | it('should get a deeply-nested sub-generator registered as a function', function() { 60 | base.register('foo', function(foo) { 61 | foo.register('bar', function(bar) { 62 | bar.register('baz', function(baz) { 63 | baz.register('qux', function(qux) { 64 | qux.task('qux-one', function() {}); 65 | }); 66 | }); 67 | }); 68 | }); 69 | 70 | var qux = base.getGenerator('foo.bar.baz.qux'); 71 | assert(qux); 72 | assert(qux.tasks); 73 | assert(qux.tasks.hasOwnProperty('qux-one')); 74 | }); 75 | 76 | it('should expose the instance from each generator', function() { 77 | base.register('foo', function(foo) { 78 | foo.register('bar', function(bar) { 79 | bar.register('baz', function(baz) { 80 | baz.register('qux', function(qux) { 81 | qux.task('qux-one', function() {}); 82 | }); 83 | }); 84 | }); 85 | }); 86 | 87 | var qux = base 88 | .getGenerator('foo') 89 | .getGenerator('bar') 90 | .getGenerator('baz') 91 | .getGenerator('qux'); 92 | 93 | assert(qux); 94 | assert(qux.tasks); 95 | assert(qux.tasks.hasOwnProperty('qux-one')); 96 | }); 97 | 98 | it('should fail when a generator that does not exist is defined', function() { 99 | base.register('foo', function(foo) { 100 | foo.register('bar', function(bar) { 101 | bar.register('baz', function(baz) { 102 | baz.register('qux', function(qux) { 103 | }); 104 | }); 105 | }); 106 | }); 107 | var fez = base.getGenerator('foo.bar.fez'); 108 | assert.equal(typeof fez, 'undefined'); 109 | }); 110 | 111 | it('should expose the `base` instance as the second param', function(cb) { 112 | base.register('foo', function(foo, base) { 113 | assert(base.generators.hasOwnProperty('foo')); 114 | cb(); 115 | }); 116 | base.getGenerator('foo'); 117 | }); 118 | 119 | it('should expose sibling generators on the `base` instance', function(cb) { 120 | base.register('foo', function(foo, base) { 121 | foo.task('abc', function() {}); 122 | }); 123 | base.register('bar', function(bar, base) { 124 | assert(base.generators.hasOwnProperty('foo')); 125 | assert(base.generators.hasOwnProperty('bar')); 126 | cb(); 127 | }); 128 | 129 | base.getGenerator('foo'); 130 | base.getGenerator('bar'); 131 | }); 132 | }); 133 | 134 | describe('alias', function() { 135 | it('should use a custom function to create the alias', function() { 136 | base.option('toAlias', function(name) { 137 | return name.slice(name.lastIndexOf('-') + 1); 138 | }); 139 | 140 | base.register('base-abc-xyz', function() {}); 141 | var xyz = base.getGenerator('xyz'); 142 | assert(xyz); 143 | assert.equal(xyz.env.alias, 'xyz'); 144 | }); 145 | }); 146 | 147 | describe('path', function() { 148 | it('should register a generator function by name', function() { 149 | base.register('foo', function() {}); 150 | assert(base.generators.hasOwnProperty('foo')); 151 | }); 152 | 153 | it('should register a generator function by alias', function() { 154 | base.register('abc', function() {}); 155 | assert(base.generators.hasOwnProperty('abc')); 156 | }); 157 | 158 | it('should register a generator by dirname', function() { 159 | base.register('a', fixtures('generators/a')); 160 | assert(base.generators.hasOwnProperty('a')); 161 | }); 162 | 163 | it('should register a generator from a configfile filepath', function() { 164 | base.register('base-abc', fixtures('generators/a/generator.js')); 165 | assert(base.generators.hasOwnProperty('base-abc')); 166 | }); 167 | 168 | it('should throw when a generator does not expose the instance', function(cb) { 169 | try { 170 | base.register('not-exposed', require(fixtures('not-exposed.js'))); 171 | cb(new Error('expected an error')); 172 | } catch (err) { 173 | assert.equal(err.message, `cannot resolve: 'not-exposed'`); 174 | cb(); 175 | } 176 | }); 177 | }); 178 | 179 | describe('instance', function() { 180 | it('should register an instance', function() { 181 | base.register('base-inst', new Base()); 182 | assert(base.generators.hasOwnProperty('base-inst')); 183 | }); 184 | 185 | it('should get a generator that was registered as an instance', function() { 186 | var foo = new Base(); 187 | foo.task('default', function() {}); 188 | base.register('foo', foo); 189 | assert(base.getGenerator('foo')); 190 | }); 191 | 192 | it('should register multiple instances', function() { 193 | var foo = new Base(); 194 | var bar = new Base(); 195 | var baz = new Base(); 196 | base.register('foo', foo); 197 | base.register('bar', bar); 198 | base.register('baz', baz); 199 | assert(base.getGenerator('foo')); 200 | assert(base.getGenerator('bar')); 201 | assert(base.getGenerator('baz')); 202 | }); 203 | 204 | it('should get tasks from a generator that was registered as an instance', function() { 205 | var foo = new Base(); 206 | foo.task('default', function() {}); 207 | base.register('foo', foo); 208 | var generator = base.getGenerator('foo'); 209 | assert(generator); 210 | assert(generator.tasks.hasOwnProperty('default')); 211 | }); 212 | 213 | it('should get sub-generators from a generator registered as an instance', function() { 214 | var foo = new Base(); 215 | foo.use(generators()); 216 | foo.register('bar', function() {}); 217 | base.register('foo', foo); 218 | var generator = base.getGenerator('foo.bar'); 219 | assert(generator); 220 | }); 221 | 222 | it('should get tasks from sub-generators registered as an instance', function() { 223 | var foo = new Base(); 224 | foo.use(generators()); 225 | 226 | foo.options.isFoo = true; 227 | foo.register('bar', function(bar) { 228 | bar.task('whatever', function() {}); 229 | }); 230 | 231 | base.register('foo', foo); 232 | var generator = base.getGenerator('foo.bar'); 233 | assert(generator.tasks); 234 | assert(generator.tasks.hasOwnProperty('whatever')); 235 | }); 236 | }); 237 | }); 238 | -------------------------------------------------------------------------------- /test/app.task.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var isApp = require('./support/is-app'); 6 | var generators = require('..'); 7 | var Base = require('base'); 8 | var base; 9 | 10 | describe('.generate', function() { 11 | beforeEach(function() { 12 | Base.use(isApp()); 13 | base = new Base(); 14 | base.use(generators()); 15 | }); 16 | 17 | it('should register a task', function() { 18 | var fn = function(cb) { 19 | cb(); 20 | }; 21 | base.task('default', fn); 22 | assert.equal(typeof base.tasks.default, 'object'); 23 | assert.equal(base.tasks.default.fn, fn); 24 | }); 25 | 26 | it('should register a task with an array of dependencies', function(cb) { 27 | var count = 0; 28 | base.task('foo', function(next) { 29 | count++; 30 | next(); 31 | }); 32 | base.task('bar', function(next) { 33 | count++; 34 | next(); 35 | }); 36 | base.task('default', ['foo', 'bar'], function(next) { 37 | count++; 38 | next(); 39 | }); 40 | assert.equal(typeof base.tasks.default, 'object'); 41 | assert.deepEqual(base.tasks.default.deps, ['foo', 'bar']); 42 | base.build('default', function(err) { 43 | if (err) return cb(err); 44 | assert.equal(count, 3); 45 | cb(); 46 | }); 47 | }); 48 | 49 | it('should run a glob of tasks', function(cb) { 50 | var count = 0; 51 | base.task('foo', function(next) { 52 | count++; 53 | next(); 54 | }); 55 | base.task('bar', function(next) { 56 | count++; 57 | next(); 58 | }); 59 | base.task('baz', function(next) { 60 | count++; 61 | next(); 62 | }); 63 | base.task('qux', function(next) { 64 | count++; 65 | next(); 66 | }); 67 | base.task('default', ['b*']); 68 | assert.equal(typeof base.tasks.default, 'object'); 69 | base.build('default', function(err) { 70 | if (err) return cb(err); 71 | assert.equal(count, 2); 72 | cb(); 73 | }); 74 | }); 75 | 76 | it('should register a task with a list of strings as dependencies', function() { 77 | base.task('default', 'foo', 'bar', function(cb) { 78 | cb(); 79 | }); 80 | assert.equal(typeof base.tasks.default, 'object'); 81 | assert.deepEqual(base.tasks.default.deps, ['foo', 'bar']); 82 | }); 83 | 84 | it('should run a task', function(cb) { 85 | var count = 0; 86 | base.task('default', function(cb) { 87 | count++; 88 | cb(); 89 | }); 90 | 91 | base.build('default', function(err) { 92 | if (err) return cb(err); 93 | assert.equal(count, 1); 94 | cb(); 95 | }); 96 | }); 97 | 98 | it('should throw an error when a task with unregistered dependencies is run', function(cb) { 99 | base.task('default', ['foo', 'bar']); 100 | base.build('default', function(err) { 101 | assert(err); 102 | cb(); 103 | }); 104 | }); 105 | 106 | it('should throw an error when `.build` is called without a callback function.', function() { 107 | try { 108 | base.build('default'); 109 | throw new Error('Expected an error to be thrown.'); 110 | } catch (err) { 111 | } 112 | }); 113 | 114 | it('should emit task events', function(cb) { 115 | var events = []; 116 | base.on('task:starting', function(task) { 117 | events.push('starting.' + task.name); 118 | }); 119 | base.on('task:finished', function(task) { 120 | events.push('finished.' + task.name); 121 | }); 122 | base.on('task:error', function(e, task) { 123 | events.push('error.' + task.name); 124 | }); 125 | base.task('foo', function(cb) { 126 | cb(); 127 | }); 128 | base.task('bar', ['foo'], function(cb) { 129 | cb(); 130 | }); 131 | base.task('default', ['bar']); 132 | base.build('default', function(err) { 133 | if (err) return cb(err); 134 | assert.deepEqual(events, [ 135 | 'starting.default', 136 | 'starting.bar', 137 | 'starting.foo', 138 | 'finished.foo', 139 | 'finished.bar', 140 | 'finished.default' 141 | ]); 142 | cb(); 143 | }); 144 | }); 145 | 146 | it('should emit an error event when an error is passed back in a task', function(cb) { 147 | base.on('error', function(err) { 148 | assert(err); 149 | assert.equal(err.message, 'This is an error'); 150 | }); 151 | base.task('default', function(cb) { 152 | return cb(new Error('This is an error')); 153 | }); 154 | base.build('default', function(err) { 155 | if (err) return cb(); 156 | cb(new Error('Expected an error')); 157 | }); 158 | }); 159 | 160 | it('should emit an error event when an error is thrown in a task', function(cb) { 161 | base.on('error', function(err) { 162 | assert(err); 163 | assert.equal(err.message, 'This is an error'); 164 | }); 165 | base.task('default', function(cb) { 166 | cb(new Error('This is an error')); 167 | }); 168 | base.build('default', function(err) { 169 | assert(err); 170 | cb(); 171 | }); 172 | }); 173 | 174 | it('should run dependencies before running the dependent task.', function(cb) { 175 | var seq = []; 176 | base.task('foo', function(cb) { 177 | seq.push('foo'); 178 | cb(); 179 | }); 180 | base.task('bar', function(cb) { 181 | seq.push('bar'); 182 | cb(); 183 | }); 184 | base.task('default', ['foo', 'bar'], function(cb) { 185 | seq.push('default'); 186 | cb(); 187 | }); 188 | 189 | base.build('default', function(err) { 190 | if (err) return cb(err); 191 | assert.deepEqual(seq, ['foo', 'bar', 'default']); 192 | cb(); 193 | }); 194 | }); 195 | }); 196 | -------------------------------------------------------------------------------- /test/app.toAlias.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var isApp = require('./support/is-app'); 6 | var Base = require('base'); 7 | var generators = require('..'); 8 | var base; 9 | 10 | describe('.toAlias', function() { 11 | beforeEach(function() { 12 | Base.use(isApp()); 13 | Base.use(generators()); 14 | base = new Base(); 15 | }); 16 | 17 | it('should not create an alias when no prefix is given', function() { 18 | assert.equal(base.toAlias('foo-bar'), 'foo-bar'); 19 | }); 20 | 21 | it('should create an alias using the `options.toAlias` function', function() { 22 | var alias = base.toAlias('one-two-three', { 23 | toAlias: function(name) { 24 | return name.slice(name.lastIndexOf('-') + 1); 25 | } 26 | }); 27 | assert.equal(alias, 'three'); 28 | }); 29 | 30 | it('should create an alias using the given function', function() { 31 | var alias = base.toAlias('one-two-three', function(name) { 32 | return name.slice(name.lastIndexOf('-') + 1); 33 | }); 34 | assert.equal(alias, 'three'); 35 | }); 36 | 37 | it('should create an alias using base.options.toAlias function', function() { 38 | base.options.toAlias = function(name) { 39 | return name.slice(name.lastIndexOf('-') + 1); 40 | }; 41 | 42 | var alias = base.toAlias('one-two-three'); 43 | assert.equal(alias, 'three'); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/fixtures/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app) { 4 | app.register('generate-aaa', function(app) { 5 | app.task('default', function(cb) { 6 | console.log('generate > default'); 7 | cb(); 8 | }); 9 | 10 | app.register('sub', function(sub) { 11 | sub.task('default', function(cb) { 12 | console.log('aaa > sub > default'); 13 | cb(); 14 | }); 15 | 16 | sub.register('bbb', function(bbb) { 17 | bbb.task('default', function(cb) { 18 | console.log('aaa > sub > bbb > default'); 19 | cb(); 20 | }); 21 | }); 22 | }); 23 | }); 24 | 25 | app.register('generate-abc', 'test/fixtures/generators/a/generator.js'); 26 | 27 | app.register('generate-bbb', function(app) { 28 | app.task('default', function(cb) { 29 | app.generate('aaa.sub.bbb', 'default', cb); 30 | }); 31 | }); 32 | 33 | app.register('generate-ccc', function(app) { 34 | app.task('default', function(cb) { 35 | app.generate('abc', 'default', cb); 36 | }); 37 | }); 38 | 39 | app.register('generate-ddd', function(app) { 40 | app.task('default', function(cb) { 41 | app.generate('abc.docs', 'x', cb); 42 | }); 43 | }); 44 | 45 | app.generate('aaa.sub', ['default'], function(err) { 46 | if (err) throw err; 47 | console.log('done'); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /test/fixtures/generators/a/.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.sublime-* 3 | _gh_pages 4 | bower_components 5 | node_modules 6 | npm-debug.log 7 | actual 8 | test/actual 9 | temp 10 | tmp 11 | TODO.md 12 | vendor 13 | .idea 14 | benchmark 15 | coverage 16 | -------------------------------------------------------------------------------- /test/fixtures/generators/a/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app) { 4 | app.task('default', function(cb) { 5 | console.log('fixtures/a > default'); 6 | cb(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/fixtures/generators/a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-a", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["index.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/generators/a/post.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Post 3 | --- 4 | 5 | This is SOME POST -------------------------------------------------------------------------------- /test/fixtures/generators/b/.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.sublime-* 3 | _gh_pages 4 | bower_components 5 | node_modules 6 | npm-debug.log 7 | actual 8 | test/actual 9 | temp 10 | tmp 11 | TODO.md 12 | vendor 13 | .idea 14 | benchmark 15 | coverage 16 | -------------------------------------------------------------------------------- /test/fixtures/generators/b/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | module.exports = function() { 11 | // do stuff 12 | }; 13 | -------------------------------------------------------------------------------- /test/fixtures/generators/b/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bbb", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["index.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/generators/c/.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.sublime-* 3 | _gh_pages 4 | bower_components 5 | node_modules 6 | npm-debug.log 7 | actual 8 | test/actual 9 | temp 10 | tmp 11 | TODO.md 12 | vendor 13 | .idea 14 | benchmark 15 | coverage 16 | -------------------------------------------------------------------------------- /test/fixtures/generators/c/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app) { 4 | app.task('default', function(cb) { 5 | console.log('c > default'); 6 | cb(); 7 | }); 8 | app.task('c_a', function(cb) { 9 | console.log('c > a'); 10 | cb(); 11 | }); 12 | app.task('c_b', function(cb) { 13 | console.log('c > b'); 14 | cb(); 15 | }); 16 | app.task('c_c', function(cb) { 17 | console.log('c > c'); 18 | cb(); 19 | }); 20 | 21 | app.register('docs', function(docs, base) { 22 | docs.task('default', function(cb) { 23 | console.log('c > x'); 24 | cb(); 25 | }); 26 | docs.task('c_x', function(cb) { 27 | console.log('c > x'); 28 | cb(); 29 | }); 30 | docs.task('c_y', function(cb) { 31 | console.log('c > y'); 32 | cb(); 33 | }); 34 | docs.task('c_z', function(cb) { 35 | console.log('c > z'); 36 | cb(); 37 | }); 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /test/fixtures/generators/c/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "a", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["index.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/generators/e/.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.sublime-* 3 | _gh_pages 4 | bower_components 5 | node_modules 6 | npm-debug.log 7 | actual 8 | test/actual 9 | temp 10 | tmp 11 | TODO.md 12 | vendor 13 | .idea 14 | benchmark 15 | coverage 16 | -------------------------------------------------------------------------------- /test/fixtures/generators/e/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * testing... 5 | */ 6 | 7 | module.exports = function(app, base, env) { 8 | app.task('default', function(cb) { 9 | console.log('e > default'); 10 | cb(); 11 | }); 12 | app.task('one', function(cb) { 13 | console.log('e > one'); 14 | cb(); 15 | }); 16 | app.task('two', function(cb) { 17 | console.log('e > two'); 18 | cb(); 19 | }); 20 | 21 | // console.log(app) 22 | app.task('three', function(cb) { 23 | base.data({title: 'three'}); 24 | base.build('readme', cb); 25 | }); 26 | 27 | app.register('eee', '../c'); 28 | 29 | app.register('e_docs', function(docs) { 30 | docs.task('e_x', function(cb) { 31 | console.log('e > x'); 32 | cb(); 33 | }); 34 | docs.task('e_y', function(cb) { 35 | console.log('e > y'); 36 | cb(); 37 | }); 38 | docs.task('e_z', function(cb) { 39 | console.log('e > z'); 40 | cb(); 41 | }); 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /test/fixtures/generators/e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-e", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["index.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/generators/e/templates/post.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Post 3 | --- 4 | 5 | This is three -------------------------------------------------------------------------------- /test/fixtures/generators/qux/.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.sublime-* 3 | _gh_pages 4 | bower_components 5 | node_modules 6 | npm-debug.log 7 | actual 8 | test/actual 9 | temp 10 | tmp 11 | TODO.md 12 | vendor 13 | .idea 14 | benchmark 15 | coverage 16 | -------------------------------------------------------------------------------- /test/fixtures/generators/qux/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app, base, env) { 4 | app.task('a', function() {}); 5 | app.task('b', function() {}); 6 | app.task('c', function() {}); 7 | }; 8 | -------------------------------------------------------------------------------- /test/fixtures/generators/qux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generate-qux", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": ["generator.js"], 6 | "main": "generator.js" 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/generators2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Generate = require('./'); 4 | var app = new Generate({foo: 'bar'}); 5 | 6 | app.register('a', function(a, base) { 7 | a.register('a1', function(aa) { 8 | aa.register('aaa', require('./generators/f/generator.js')); 9 | aa.task('default', function(cb) { 10 | console.log('aa > default'); 11 | cb(); 12 | }); 13 | }); 14 | a.register('a2', function(aa) { 15 | }); 16 | }); 17 | 18 | app.register('b', new Generate()); 19 | app.generators.b.register('bb', function(bb) { 20 | bb.register('bbb', function() {}); 21 | bb.task('default', function(cb) { 22 | console.log('bb > default'); 23 | cb(); 24 | }); 25 | }); 26 | 27 | app.register('c', function(c, base) { 28 | c.register('cc', function(cc, basecc) { 29 | cc.task('default', function(cb) { 30 | console.log('cc > default'); 31 | cb(); 32 | }); 33 | 34 | cc.register('base', require('./generator')); 35 | }); 36 | }); 37 | 38 | app.generate('a.a1.aaa', ['default'], function(err) { 39 | if (err) throw err; 40 | console.log('DONE!!!'); 41 | }); 42 | -------------------------------------------------------------------------------- /test/fixtures/not-exposed.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var generators = require('../..'); 4 | var Base = require('base'); 5 | var base = new Base({isApp: true}); 6 | base.use(generators()); 7 | 8 | base.register('not-exposed', function(app) { 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /test/fixtures/one/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app, base, env) { 4 | app.task('default', function(cb) { 5 | console.log('one > default'); 6 | cb(); 7 | }); 8 | 9 | app.task('a', function() {}); 10 | app.task('b', function() {}); 11 | app.task('c', function() {}); 12 | 13 | app.register('foo', function(app) { 14 | app.task('x', function() {}); 15 | app.task('y', function() {}); 16 | app.task('z', function() {}); 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /test/fixtures/one/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "one", 3 | "description": "The most interesting project in the world > Verb", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/jonschlinkert/one", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "jonschlinkert/one", 8 | "bugs": { 9 | "url": "https://github.com/jonschlinkert/one/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js" 14 | ], 15 | "main": "index.js", 16 | "engines": { 17 | "node": ">=0.10.0" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "dependencies": { 23 | "resolve-modules": "^0.1.2" 24 | }, 25 | "devDependencies": { 26 | "mocha": "*", 27 | "should": "*" 28 | }, 29 | "keywords": [] 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/one/templates/a.txt: -------------------------------------------------------------------------------- 1 | one: aaa -------------------------------------------------------------------------------- /test/fixtures/one/templates/x.txt: -------------------------------------------------------------------------------- 1 | one: xxx -------------------------------------------------------------------------------- /test/fixtures/one/templates/y.txt: -------------------------------------------------------------------------------- 1 | one: yyy -------------------------------------------------------------------------------- /test/fixtures/one/templates/z.txt: -------------------------------------------------------------------------------- 1 | one: zzz -------------------------------------------------------------------------------- /test/fixtures/three/four/five/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(generate, base) { 4 | generate.task('default', function() {}); 5 | generate.task('a', function() {}); 6 | generate.task('b', function() {}); 7 | generate.task('c', function() {}); 8 | 9 | generate.register('foo', function(app) { 10 | app.task('x', function() {}); 11 | app.task('y', function() {}); 12 | app.task('z', function() {}); 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/fixtures/three/four/five/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "five", 3 | "description": "The most interesting project in the world > Verb", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/jonschlinkert/five", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "jonschlinkert/five", 8 | "bugs": { 9 | "url": "https://github.com/jonschlinkert/five/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js" 14 | ], 15 | "main": "index.js", 16 | "engines": { 17 | "node": ">=0.10.0" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "dependencies": { 23 | "resolve-modules": "^0.1.2" 24 | }, 25 | "devDependencies": { 26 | "mocha": "*", 27 | "should": "*" 28 | }, 29 | "keywords": [] 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/three/four/five/templates/a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/four/five/templates/a.txt -------------------------------------------------------------------------------- /test/fixtures/three/four/five/templates/b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/four/five/templates/b.txt -------------------------------------------------------------------------------- /test/fixtures/three/four/five/templates/c.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/four/five/templates/c.txt -------------------------------------------------------------------------------- /test/fixtures/three/four/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(generate, base) { 4 | generate.task('default', function() {}); 5 | generate.task('a', function() {}); 6 | generate.task('b', function() {}); 7 | generate.task('c', function() {}); 8 | 9 | generate.register('foo', function(app) { 10 | app.task('x', function() {}); 11 | app.task('y', function() {}); 12 | app.task('z', function() {}); 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/fixtures/three/four/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "four", 3 | "description": "The most interesting project in the world > Verb", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/jonschlinkert/four", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "jonschlinkert/four", 8 | "bugs": { 9 | "url": "https://github.com/jonschlinkert/four/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js" 14 | ], 15 | "main": "index.js", 16 | "engines": { 17 | "node": ">=0.10.0" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "dependencies": { 23 | "resolve-modules": "^0.1.2" 24 | }, 25 | "devDependencies": { 26 | "mocha": "*", 27 | "should": "*" 28 | }, 29 | "keywords": [] 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/three/four/templates/a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/four/templates/a.txt -------------------------------------------------------------------------------- /test/fixtures/three/four/templates/b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/four/templates/b.txt -------------------------------------------------------------------------------- /test/fixtures/three/four/templates/c.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/four/templates/c.txt -------------------------------------------------------------------------------- /test/fixtures/three/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(generate, base) { 4 | generate.task('default', function() {}); 5 | generate.task('a', function() {}); 6 | generate.task('b', function() {}); 7 | generate.task('c', function() {}); 8 | 9 | generate.register('foo', function(app) { 10 | app.task('x', function() {}); 11 | app.task('y', function() {}); 12 | app.task('z', function() {}); 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/fixtures/three/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "three", 3 | "description": "The most interesting project in the world > Verb", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/jonschlinkert/three", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "jonschlinkert/three", 8 | "bugs": { 9 | "url": "https://github.com/jonschlinkert/three/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js" 14 | ], 15 | "main": "index.js", 16 | "engines": { 17 | "node": ">=0.10.0" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "dependencies": { 23 | "resolve-modules": "^0.1.2" 24 | }, 25 | "devDependencies": { 26 | "mocha": "*", 27 | "should": "*" 28 | }, 29 | "keywords": [] 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/three/templates/a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/templates/a.txt -------------------------------------------------------------------------------- /test/fixtures/three/templates/b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/templates/b.txt -------------------------------------------------------------------------------- /test/fixtures/three/templates/c.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/three/templates/c.txt -------------------------------------------------------------------------------- /test/fixtures/two/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var generators = require('../../..'); 4 | var Base = require('../../support/app'); 5 | Base.use(generators()); 6 | var base = new Base(); 7 | 8 | base.task('default', function() {}); 9 | base.task('a', function() {}); 10 | base.task('b', function() {}); 11 | base.task('c', function() {}); 12 | 13 | base.register('foo', function(app) { 14 | app.task('x', function() {}); 15 | app.task('y', function() {}); 16 | app.task('z', function() {}); 17 | }); 18 | 19 | /** 20 | * Expose this instance of `Generate` 21 | */ 22 | 23 | module.exports = base; 24 | -------------------------------------------------------------------------------- /test/fixtures/two/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "two", 3 | "description": "The most interesting project in the world > Verb", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/jonschlinkert/two", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "jonschlinkert/two", 8 | "bugs": { 9 | "url": "https://github.com/jonschlinkert/two/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js" 14 | ], 15 | "main": "index.js", 16 | "engines": { 17 | "node": ">=0.10.0" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "dependencies": { 23 | "resolve-modules": "^0.1.2" 24 | }, 25 | "devDependencies": { 26 | "mocha": "*", 27 | "should": "*" 28 | }, 29 | "keywords": [] 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/two/templates/a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/two/templates/a.txt -------------------------------------------------------------------------------- /test/fixtures/two/templates/b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/two/templates/b.txt -------------------------------------------------------------------------------- /test/fixtures/two/templates/c.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base-repos/base-generators/9a741117b80ed19b281177169c0f98059cb97c90/test/fixtures/two/templates/c.txt -------------------------------------------------------------------------------- /test/generators.env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var path = require('path'); 5 | var assert = require('assert'); 6 | var isApp = require('./support/is-app'); 7 | var Base = require('base'); 8 | var generators = require('..'); 9 | var base, env; 10 | 11 | Base.use(isApp()); 12 | var fixtures = path.resolve.bind(path, __dirname + '/fixtures'); 13 | 14 | describe('env', function() { 15 | describe('plugin', function() { 16 | it('should work as a plugin', function() { 17 | base = new Base(); 18 | base.use(generators()); 19 | assert.equal(typeof base.createEnv, 'function'); 20 | }); 21 | }); 22 | 23 | describe('createEnv paths', function() { 24 | beforeEach(function() { 25 | base = new Base(); 26 | base.use(generators()); 27 | }); 28 | 29 | describe('alias and function', function() { 30 | it('should make the alias the exact name when the second arg is a function', function() { 31 | var fn = function() {}; 32 | var env = base.createEnv('foo-bar-baz', fn); 33 | assert(env); 34 | assert(env.alias); 35 | assert.equal(env.alias, 'foo-bar-baz'); 36 | }); 37 | 38 | it('should not change the name when the second arg is a function', function() { 39 | var fn = function() {}; 40 | var env = base.createEnv('foo-bar-baz', fn); 41 | assert(env); 42 | assert(env.name); 43 | assert.equal(env.name, 'foo-bar-baz'); 44 | }); 45 | }); 46 | 47 | describe('alias and path', function() { 48 | it('should set the env.name using the given name', function() { 49 | var env = base.createEnv('foo', 'generate-foo/generator.js'); 50 | assert.equal(env.name, 'foo'); 51 | }); 52 | 53 | it('should not change the name when the second arg is a function', function() { 54 | var fn = function() {}; 55 | var env = base.createEnv('foo-bar-baz', fn); 56 | assert(env); 57 | assert(env.name); 58 | assert.equal(env.name, 'foo-bar-baz'); 59 | }); 60 | }); 61 | }); 62 | 63 | describe('createEnv', function() { 64 | beforeEach(function() { 65 | base = new Base(); 66 | base.use(generators()); 67 | }); 68 | 69 | it('should add an env object to the instance', function() { 70 | var fn = function() {}; 71 | env = base.createEnv('foo', fn); 72 | assert(env); 73 | }); 74 | 75 | it('should take options as the second arg', function() { 76 | var fn = function() {}; 77 | env = base.createEnv('foo', {}, fn); 78 | assert(env); 79 | }); 80 | 81 | it('should prime `env` if it doesn\'t exist', function() { 82 | var fn = function() {}; 83 | env = base.createEnv('foo', {}, fn); 84 | assert(env); 85 | }); 86 | 87 | it('should add an alias to the env object', function() { 88 | var fn = function() {}; 89 | env = base.createEnv('foo', {}, fn); 90 | assert.equal(env.alias, 'foo'); 91 | }); 92 | 93 | it('should not prefix the alias when a function is passed', function() { 94 | var fn = function() {}; 95 | delete base.prefix; 96 | env = base.createEnv('foo', {}, fn); 97 | assert.equal(env.name, 'foo'); 98 | }); 99 | 100 | it('should not prefix a custom alias when a function is passed', function() { 101 | var fn = function() {}; 102 | base.prefix = 'whatever'; 103 | env = base.createEnv('foo', {}, fn); 104 | assert.equal(env.name, 'foo'); 105 | }); 106 | 107 | it('should try to resolve an absolute path passed as the second arg', function() { 108 | env = base.createEnv('foo', fixtures('generator.js')); 109 | assert.equal(env.alias, 'foo'); 110 | assert.equal(env.name, 'foo'); 111 | }); 112 | 113 | it('should try to resolve a relative path passed as the second arg', function() { 114 | env = base.createEnv('foo', 'generate-foo/generator.js'); 115 | assert.equal(env.key, 'foo'); 116 | assert.equal(env.alias, 'foo'); 117 | assert.equal(env.name, 'foo'); 118 | }); 119 | 120 | it('should throw an error when the path is not resolved', function(cb) { 121 | try { 122 | var env = base.createEnv('foo', fixtures('whatever.js')); 123 | env.invoke(); 124 | env.path; 125 | cb(new Error('expected an error')); 126 | } catch (err) { 127 | assert.equal(err.message, 'cannot resolve: \'' + fixtures('whatever.js') + '\''); 128 | cb(); 129 | } 130 | }); 131 | }); 132 | }); 133 | -------------------------------------------------------------------------------- /test/generators.events.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var isApp = require('./support/is-app'); 6 | var Base = require('base'); 7 | var base; 8 | 9 | var generators = require('..'); 10 | 11 | describe('generators events', function() { 12 | describe('generator', function() { 13 | beforeEach(function() { 14 | Base.use(isApp()); 15 | Base.use(generators()); 16 | base = new Base(); 17 | }); 18 | 19 | it('should emit generator when a generator is registered', function(cb) { 20 | base = new Base(); 21 | base.on('generator', function(generator) { 22 | assert.equal(generator.alias, 'foo'); 23 | cb(); 24 | }); 25 | 26 | base.register('foo', function() {}); 27 | }); 28 | 29 | it('should emit generator when base.generators.get is called', function(cb) { 30 | base = new Base(); 31 | 32 | base.on('generator', function(generator) { 33 | assert.equal(generator.alias, 'foo'); 34 | cb(); 35 | }); 36 | 37 | base.register('foo', function() {}); 38 | base.getGenerator('foo'); 39 | }); 40 | 41 | it('should emit generator.get when base.generators.get is called', function(cb) { 42 | base = new Base(); 43 | base.on('generator', function(generator) { 44 | assert.equal(generator.alias, 'foo'); 45 | cb(); 46 | }); 47 | 48 | base.register('foo', function() {}); 49 | base.getGenerator('foo'); 50 | }); 51 | 52 | it('should emit error on base when a base generator emits an error', function(cb) { 53 | base = new Base(); 54 | var called = 0; 55 | 56 | base.on('error', function(err) { 57 | assert.equal(err.message, 'whatever'); 58 | called++; 59 | }); 60 | 61 | base.register('foo', function(app) { 62 | app.emit('error', new Error('whatever')); 63 | }); 64 | 65 | base.getGenerator('foo'); 66 | assert.equal(called, 1); 67 | cb(); 68 | }); 69 | 70 | it('should emit error on base when a base generator throws an error', function(cb) { 71 | base = new Base(); 72 | var called = 0; 73 | 74 | base.on('error', function(err) { 75 | assert.equal(err.message, 'whatever'); 76 | called++; 77 | }); 78 | 79 | base.register('foo', function(app) { 80 | app.task('default', function(cb) { 81 | cb(new Error('whatever')); 82 | }); 83 | }); 84 | 85 | base.getGenerator('foo') 86 | .build(function(err) { 87 | assert(err); 88 | assert.equal(called, 1); 89 | cb(); 90 | }); 91 | 92 | }); 93 | 94 | it('should emit errors on base from deeply nested generators', function(cb) { 95 | base = new Base(); 96 | var called = 0; 97 | 98 | base.on('error', function(err) { 99 | assert.equal(err.message, 'whatever'); 100 | called++; 101 | }); 102 | 103 | base.register('a', function() { 104 | this.register('b', function() { 105 | this.register('c', function() { 106 | this.register('d', function() { 107 | this.task('default', function(cb) { 108 | cb(new Error('whatever')); 109 | }); 110 | }); 111 | }); 112 | }); 113 | }); 114 | 115 | base.getGenerator('a.b.c.d') 116 | .build(function(err) { 117 | assert(err); 118 | assert.equal(called, 1); 119 | cb(); 120 | }); 121 | 122 | }); 123 | 124 | it('should bubble up errors to all parent generators', function(cb) { 125 | base = new Base(); 126 | var called = 0; 127 | 128 | function count() { 129 | called++; 130 | } 131 | 132 | base.on('error', function(err) { 133 | assert.equal(err.message, 'whatever'); 134 | called++; 135 | }); 136 | 137 | base.register('a', function() { 138 | this.on('error', count); 139 | 140 | this.register('b', function() { 141 | this.on('error', count); 142 | 143 | this.register('c', function() { 144 | this.on('error', count); 145 | 146 | this.register('d', function() { 147 | this.on('error', count); 148 | 149 | this.task('default', function(cb) { 150 | cb(new Error('whatever')); 151 | }); 152 | }); 153 | }); 154 | }); 155 | }); 156 | 157 | base.getGenerator('a.b.c.d') 158 | .build(function(err) { 159 | assert(err); 160 | assert.equal(called, 6); 161 | assert.equal(err.message, 'whatever'); 162 | cb(); 163 | }); 164 | }); 165 | }); 166 | }); 167 | -------------------------------------------------------------------------------- /test/generators.plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var path = require('path'); 5 | var assert = require('assert'); 6 | var isApp = require('./support/is-app'); 7 | var Base = require('base'); 8 | var generators = require('..'); 9 | var base; 10 | 11 | describe('base-generators', function() { 12 | describe('plugin', function() { 13 | it('should register as a plugin on `base`', function() { 14 | Base.use(isApp()); 15 | base = new Base(); 16 | base.use(generators()); 17 | assert.equal(base.isRegistered('base-generators'), true); 18 | }); 19 | 20 | it('should only register the plugin once', function(cb) { 21 | base = new Base(); 22 | base.registered = {}; 23 | 24 | var count = 0; 25 | base.on('plugin', function(name) { 26 | if (name === 'base-generators') { 27 | count++; 28 | } 29 | }); 30 | 31 | base.use(generators()); 32 | base.use(generators()); 33 | base.use(generators()); 34 | base.use(generators()); 35 | base.use(generators()); 36 | assert.equal(count, 1); 37 | cb(); 38 | }); 39 | }); 40 | 41 | describe('cwd', function() { 42 | beforeEach(function() { 43 | Base.use(isApp()); 44 | base = new Base(); 45 | base.use(generators()); 46 | }); 47 | 48 | it('should get the current working directory', function() { 49 | assert.equal(base.cwd, process.cwd()); 50 | }); 51 | 52 | it('should set the current working directory', function() { 53 | base.cwd = 'test/fixtures'; 54 | assert.equal(base.cwd, path.join(process.cwd(), 'test/fixtures')); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/support/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Base = require('base'); 4 | var task = require('base-task'); 5 | 6 | function App() { 7 | this.isApp = true; 8 | Base.call(this); 9 | this.use(task()); 10 | } 11 | 12 | Base.extend(App); 13 | 14 | /** 15 | * Expose `App` 16 | */ 17 | 18 | module.exports = App; 19 | -------------------------------------------------------------------------------- /test/support/is-app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function() { 4 | return function() { 5 | this.isApp = true; 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /test/tasks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var tasks = require('../lib/tasks'); 6 | var Base = require('base'); 7 | var app; 8 | 9 | /** 10 | * $ gen 11 | * $ gen default 12 | * $ gen foo 13 | * $ gen foo:default 14 | * $ gen foo,bar 15 | * $ gen foo bar 16 | * $ gen foo bar:baz 17 | * $ gen foo:bar,baz 18 | * $ gen foo.bar 19 | * $ gen foo.bar:baz 20 | * $ gen foo.bar baz 21 | * $ gen foo.bar baz.qux 22 | * $ gen foo.bar:baz qux.fez:default 23 | */ 24 | 25 | describe('tasks', function() { 26 | beforeEach(function() { 27 | app = new Base({isApp: true}); 28 | app.use(require('base-task')()); 29 | app.use(require('..')()); 30 | }); 31 | 32 | it('should not throw an error when a task or generator is not found', function(cb) { 33 | try { 34 | tasks.parse(app, 'foo'); 35 | cb(); 36 | } catch (err) { 37 | cb(err); 38 | } 39 | }); 40 | 41 | it('should add unresolved tasks or generators to a splat array', function() { 42 | var res = tasks.parse(app, 'foo'); 43 | assert.deepEqual(res[0]._, ['foo']); 44 | }); 45 | 46 | it('should detect a task', function() { 47 | app.task('foo', function() {}); 48 | var res = tasks.parse(app, 'foo'); 49 | assert.deepEqual(res, [{name: 'this', tasks: ['foo']}]); 50 | }); 51 | 52 | it('should detect a default task', function() { 53 | app.task('default', function() {}); 54 | var res = tasks.parse(app, 'default'); 55 | assert.deepEqual(res, [{name: 'this', tasks: ['default']}]); 56 | }); 57 | 58 | it('should detect a default generator', function() { 59 | app.register('default', function() {}); 60 | var res = tasks.parse(app, 'default'); 61 | assert.deepEqual(res, [{name: 'default', tasks: ['default']}]); 62 | }); 63 | 64 | it('should detect a sub generator on the default generator', function() { 65 | app.register('default', function(sub) { 66 | sub.register('foo', function() {}); 67 | }); 68 | 69 | var res = tasks.parse(app, 'foo'); 70 | assert.deepEqual(res, [{name: 'default.foo', tasks: ['default']}]); 71 | }); 72 | 73 | it('should support passing an array of tasks', function() { 74 | app.task('foo', function() {}); 75 | app.task('bar', function() {}); 76 | assert.deepEqual(tasks.parse(app, ['foo']), [{name: 'this', tasks: ['foo']}]); 77 | assert.deepEqual(tasks.parse(app, ['foo', 'bar']), [{name: 'this', tasks: ['foo', 'bar']}]); 78 | }); 79 | 80 | it('should detect comma-separated tasks', function() { 81 | app.task('foo', function() {}); 82 | app.task('bar', function() {}); 83 | app.task('baz', function() {}); 84 | var res = tasks.parse(app, 'foo,bar,baz'); 85 | assert.deepEqual(res, [{name: 'this', tasks: ['foo', 'bar', 'baz']}]); 86 | }); 87 | 88 | it('should detect a generator', function() { 89 | app.register('foo', function() {}); 90 | var res = tasks.parse(app, 'foo'); 91 | assert.deepEqual(res, [{name: 'foo', tasks: ['default']}]); 92 | }); 93 | 94 | it('should detect comma-separated generators', function() { 95 | app.register('foo', function() {}); 96 | app.register('bar', function() {}); 97 | app.register('baz', function() {}); 98 | var res = tasks.parse(app, 'foo,bar,baz'); 99 | 100 | assert.deepEqual(res, [ 101 | {name: 'foo', tasks: ['default']}, 102 | {name: 'bar', tasks: ['default']}, 103 | {name: 'baz', tasks: ['default']} 104 | ]); 105 | }); 106 | 107 | it('should detect sub-generators', function() { 108 | var res = tasks.parse(app, 'foo.bar'); 109 | assert.deepEqual(res, [{name: 'foo.bar', tasks: ['default']}]); 110 | }); 111 | 112 | it('should detect sub-generator tasks separated by colon', function() { 113 | var res = tasks.parse(app, 'foo.bar:baz'); 114 | assert.deepEqual(res, [{name: 'foo.bar', tasks: ['baz']}]); 115 | }); 116 | 117 | it('should detect an array of sub-generators with tasks separated by colon', function() { 118 | var res = tasks.parse(app, ['foo.bar:baz', 'one.two:three']); 119 | assert.deepEqual(res, [ 120 | {name: 'foo.bar', tasks: ['baz']}, 121 | {name: 'one.two', tasks: ['three']} 122 | ]); 123 | }); 124 | 125 | it('should detect an array of sub-generators the same generators with tasks separated by colon', function() { 126 | var res = tasks.parse(app, ['foo.bar:baz', 'foo.bar:qux']); 127 | assert.deepEqual(res, [ 128 | {name: 'foo.bar', tasks: ['baz', 'qux']} 129 | ]); 130 | }); 131 | 132 | it('should not merge sub-generators that do not directly follow on another', function() { 133 | var res = tasks.parse(app, ['foo.bar:baz', 'one.two:three', 'foo.bar:qux']); 134 | assert.deepEqual(res, [ 135 | {name: 'foo.bar', tasks: ['baz']}, 136 | {name: 'one.two', tasks: ['three']}, 137 | {name: 'foo.bar', tasks: ['qux']} 138 | ]); 139 | }); 140 | 141 | it('should detect sub-generator tasks separated by commas', function() { 142 | var res = tasks.parse(app, 'foo.bar:baz,qux'); 143 | assert.deepEqual(res, [{name: 'foo.bar', tasks: ['baz', 'qux']}]); 144 | }); 145 | 146 | it('should detect sub-generator tasks as separate args', function() { 147 | assert.deepEqual(tasks.parse(app, 'foo.bar', 'baz'), [{name: 'foo.bar', tasks: ['baz']}]); 148 | assert.deepEqual(tasks.parse(app, 'foo.bar', ['baz', 'qux']), [{name: 'foo.bar', tasks: ['baz', 'qux']}]); 149 | }); 150 | }); 151 | --------------------------------------------------------------------------------