├── .travis.yml ├── .gitignore ├── tasks ├── mocha.js └── jshint.js ├── .editorconfig ├── .jshintrc ├── test └── specs │ ├── util.js │ ├── util_options.js │ ├── util_config.js │ └── config.js ├── gulpfile.js ├── package.json ├── lib ├── util │ └── index.js └── index.js └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | temp/ 3 | _temp/ 4 | npm-debug.log 5 | .DS_Store 6 | .idea 7 | test/coverage/ 8 | -------------------------------------------------------------------------------- /tasks/mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mocha = require('gulp-mocha'); 4 | 5 | module.exports = function (gulp) { 6 | 7 | var options = this.options(), 8 | file = this.file; 9 | 10 | gulp.src(file.src) 11 | .pipe(mocha(options)) 12 | .on('error', gulp.util.log); 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 4 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true, 14 | "globals": { 15 | "describe" : false, 16 | "it" : false, 17 | "before" : false, 18 | "beforeEach" : false, 19 | "after" : false, 20 | "afterEach" : false 21 | }, 22 | "exported": { 23 | "should" : false 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/specs/util.js: -------------------------------------------------------------------------------- 1 | /* 2 | * gulp-config 3 | * http://github.com/indieisaconcept/gulp-config 4 | * 5 | * Copyright (c) 2014 Jonathan Barnett 6 | * Licensed under the ISC license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var expect = require('chai').expect, 12 | util = require('../../lib/util'); 13 | 14 | describe('util', function () { 15 | 16 | ['_', 'format', 'glob', 'config'].forEach(function (method) { 17 | it('has an "' + method + '" method', function () { 18 | expect(util[method]).to.be.a('function'); 19 | }) 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /tasks/jshint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * gulp-config 3 | * http://github.com/indieisaconcept/gulp-config 4 | * 5 | * Copyright (c) 2014 Jonathan Barnett 6 | * Licensed under the ISC license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var jshint = require('gulp-jshint'), 12 | stylish = require('jshint-stylish'); 13 | 14 | module.exports = function (gulp) { 15 | 16 | var options = this.options(), 17 | file = this.file; 18 | 19 | return gulp.src(file.src) 20 | .pipe(jshint(options)) 21 | .pipe(jshint.reporter(stylish)) 22 | .on('error', gulp.util.log); 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'), 4 | help = require('gulp-help')(gulp), 5 | config = require('./lib')(gulp, { help: true }); 6 | 7 | // =================== 8 | // CONFIG 9 | // =================== 10 | 11 | config({ 12 | 13 | paths: { 14 | source: ['./lib/**/*.js', './tasks/**/*.js'], 15 | tests : ['./test/**/*.js'] 16 | }, 17 | 18 | // tasks 19 | // ------------------------ 20 | 21 | jshint : { lint : '<%=paths.source%>' }, 22 | mocha : { specs: '<%=paths.tests%>' } 23 | 24 | }); 25 | 26 | gulp.task('test', ['jshint', 'mocha']); 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-config", 3 | "version": "0.3.0", 4 | "description": "Provides Grunt like config support to gulp", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/gulp test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "http://github.com/indieisaconcept/gulp-config" 12 | }, 13 | "keywords": [ 14 | "gulp", 15 | "grunt", 16 | "config", 17 | "gulpfriendly" 18 | ], 19 | "author": "Jonathan Barnett ", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/indieisaconcept/gulp-config/issues" 23 | }, 24 | "homepage": "https://github.com/indieisaconcept/gulp-config", 25 | "devDependencies": { 26 | "chai": "^1.9.1", 27 | "gulp": "^3.8.7", 28 | "gulp-help": "^0.1.11", 29 | "gulp-jshint": "^1.8.4", 30 | "gulp-mocha": "^0.5.2", 31 | "jshint-stylish": "^0.4.0", 32 | "mock-fs": "^2.3.1", 33 | "run-sequence": "^0.3.6", 34 | "sinon": "^1.10.3" 35 | }, 36 | "dependencies": { 37 | "configfiles": "^0.3.4", 38 | "expander": "^0.3.3", 39 | "glob": "^4.0.5", 40 | "gulp-util": "^3.0.0", 41 | "lodash": "^3.3.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/specs/util_options.js: -------------------------------------------------------------------------------- 1 | /* 2 | * gulp-config 3 | * http://github.com/indieisaconcept/gulp-config 4 | * 5 | * Copyright (c) 2014 Jonathan Barnett 6 | * Licensed under the ISC license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var expect = require('chai').expect, 12 | options = require('../../lib/util').options, 13 | 14 | current = { 15 | level: 'one' 16 | }; 17 | 18 | describe('util options', function () { 19 | 20 | it('is a function', function () { 21 | expect(options).to.be.a('function'); 22 | }); 23 | 24 | it('returns an object', function () { 25 | var result = options.call(current, {}); 26 | expect(result).to.eql(current); 27 | }); 28 | 29 | it('does not override options if key already exists', function () { 30 | 31 | var result = options.call(current, { 32 | level: 'two' 33 | }); 34 | 35 | expect(result.level).to.eql('one'); 36 | 37 | }); 38 | 39 | it('adds additional defaults if not set', function () { 40 | 41 | var result = options.call(current, { 42 | additional: 'level' 43 | }); 44 | 45 | expect(result.additional).to.eql('level'); 46 | 47 | }); 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /lib/util/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * gulp-config 3 | * http://github.com/indieisaconcept/gulp-config 4 | * 5 | * Copyright (c) 2014 Jonathan Barnett 6 | * Licensed under the ISC license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var _ = require('lodash'), 12 | expander = require('expander'), 13 | format = require('util').format, 14 | options, 15 | config; 16 | 17 | /** 18 | * @function options 19 | * Returns an object with defaults applied 20 | * 21 | * @param {object} override object to merge 22 | * 23 | * @returns {object} 24 | */ 25 | 26 | options = function (/* Object */ override) { 27 | var current = this || {}; 28 | return _.defaults(current, override || {}); 29 | }; 30 | 31 | /** 32 | * @function config 33 | * Normalise a config object. Setting correct values via 34 | * property interpolation and resolving files 35 | * 36 | * @param {object} source object detailing whole config 37 | * 38 | * @returns {object} 39 | */ 40 | 41 | config = function (/* Object */ source) { 42 | if (!_.isPlainObject(source)) { 43 | throw new Error('An valid config { Object } is required.'); 44 | } 45 | return expander.interface(source); 46 | }; 47 | 48 | module.exports = { 49 | _ : _, 50 | format : format, 51 | glob : require('glob'), 52 | config : config, 53 | options : options 54 | }; 55 | -------------------------------------------------------------------------------- /test/specs/util_config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * gulp-config 3 | * http://github.com/indieisaconcept/gulp-config 4 | * 5 | * Copyright (c) 2014 Jonathan Barnett 6 | * Licensed under the ISC license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var expect = require('chai').expect, 12 | config = require('../../lib/util').config, 13 | expander = require('expander'), 14 | 15 | fixture = { 16 | source: { 17 | paths: { 18 | test: [1, 2, 3] 19 | }, 20 | foo: { 21 | bar: 'hello', 22 | buzz: 'world' 23 | }, 24 | interpolation: '<%=foo.bar%> <%=foo.buzz%>', 25 | bar: '<%=foo%>', 26 | buzz: '<%=paths.test%>' 27 | }, 28 | expected: { 29 | paths: { 30 | test: [1, 2, 3] 31 | }, 32 | foo: { 33 | bar: 'hello', 34 | buzz: 'world' 35 | }, 36 | interpolation: 'hello world', 37 | bar: { 38 | bar: 'hello', 39 | buzz: 'world' 40 | }, 41 | buzz: [1, 2, 3] 42 | } 43 | }; 44 | 45 | describe('util config', function () { 46 | 47 | it('returns a resolved config object', function () { 48 | var result = config(fixture.source); 49 | expect(result).to.be.a('function'); 50 | expect(result()).to.eql(fixture.expected); 51 | }); 52 | 53 | it('throws an error if a non-object is passed', function () { 54 | expect(config).to.throw; 55 | expect(config.bind(null, [])).to.throw; 56 | }); 57 | 58 | }); 59 | -------------------------------------------------------------------------------- /test/specs/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * gulp-config 3 | * http://github.com/indieisaconcept/gulp-config 4 | * 5 | * Copyright (c) 2014 Jonathan Barnett 6 | * Licensed under the ISC license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var fs = require('mock-fs'), 12 | config = require('../../lib'), 13 | sequence = require('run-sequence'), 14 | sinon = require('sinon'), 15 | expect = require('chai').expect, 16 | 17 | // mock for testing 18 | 19 | gulp = { 20 | stub: sinon.stub({ 21 | task: function () {}, 22 | tasks: {} 23 | }), 24 | orig: require('gulp') 25 | }, 26 | 27 | helper; 28 | 29 | describe('gulp-config', function () { 30 | 31 | before(function () { 32 | helper = config(gulp.stub); 33 | }); 34 | 35 | it('is defined', function () { 36 | expect(config).to.be.a('function'); 37 | }); 38 | 39 | it('creates a config helper', function () { 40 | expect(helper).to.be.a('function'); 41 | }); 42 | 43 | it('extends gulp with gulp-utils', function () { 44 | expect(gulp.stub.util).to.be.a('object'); 45 | }); 46 | 47 | describe('tasks', function () { 48 | 49 | var tasks = {}, 50 | fixture = {}; 51 | 52 | before(function (done) { 53 | 54 | // create file system mocks 55 | 56 | fs({ 57 | '/a/b': {}, 58 | '/e/f': {}, 59 | '/c/d': { 60 | 'test.js': '// test.js' 61 | }, 62 | '/f/h': { 63 | 'test.js': '// test.js' 64 | }, 65 | 'some/path': { 66 | 'test.js': '// test.js' 67 | } 68 | }); 69 | 70 | // create spys 71 | 72 | tasks.one = sinon.spy(); 73 | tasks.two = sinon.spy(); 74 | 75 | // setup config fixtures 76 | 77 | fixture.one = { options: { level: 'one' }, foo: ['some/path/**/.js'] }; 78 | fixture.two = { 79 | foo: { 80 | files: { 81 | '/a/b': '/c/d/*.js', 82 | '/e/f': '/f/h/*.js' 83 | } 84 | } 85 | }; 86 | 87 | // intialize 88 | 89 | config(gulp.orig, { tasks: tasks })(fixture); 90 | 91 | // tasks 92 | 93 | gulp.orig.task('three', function () { 94 | done(); 95 | }); 96 | 97 | gulp.orig.task('default', function (cb) { 98 | sequence('one:foo', 'two:foo', 'three', cb); 99 | }); 100 | 101 | gulp.orig.start(['default']); 102 | 103 | }); 104 | 105 | it('registers a task', function () { 106 | expect(tasks.one.called).to.be.true; 107 | expect(tasks.two.called).to.be.true; 108 | }); 109 | 110 | it('this.file exists', function () { 111 | 112 | ['one', 'two'].forEach(function (item) { 113 | var scope = tasks[item].thisValues[0]; 114 | expect(scope.file).to.be.a('object'); 115 | }); 116 | 117 | }); 118 | 119 | it('this.files exists', function () { 120 | 121 | ['one', 'two'].forEach(function (item) { 122 | 123 | var scope = tasks[item].thisValues[0]; 124 | expect(scope.files).to.be.a('array'); 125 | 126 | switch(item) { 127 | 128 | case 'one': 129 | expect(scope.files.length).to.eql(1); 130 | break; 131 | case 'two': 132 | expect(scope.files.length).to.eql(2); 133 | expect(scope.files[0].src[0]).to.eql('/c/d/test.js'); 134 | expect(scope.files[0].dest).to.eql('/a/b'); 135 | break; 136 | 137 | } 138 | 139 | }); 140 | 141 | }); 142 | 143 | it('this.options() exists', function () { 144 | 145 | ['one', 'two'].forEach(function (item) { 146 | var scope = tasks[item].thisValues[0]; 147 | expect(scope.options).to.be.a('function'); 148 | }); 149 | 150 | }); 151 | 152 | it('this.config() exists', function () { 153 | 154 | ['one', 'two'].forEach(function (item) { 155 | var scope = tasks[item].thisValues[0]; 156 | expect(scope.config).to.be.a('function'); 157 | }); 158 | 159 | }); 160 | 161 | it('this.options() applies defaults or sets a value', function () { 162 | 163 | ['one', 'two'].forEach(function (item) { 164 | var scope = tasks[item].thisValues[0], 165 | result = scope.options({ 166 | level: 'two' 167 | }); 168 | expect(result.level).to.eql(item); 169 | }); 170 | 171 | ['one', 'two'].forEach(function (item) { 172 | var scope = tasks[item].thisValues[0], 173 | result = scope.options({ 174 | additional: 'level' 175 | }); 176 | expect(Object.keys(result).length).to.equal(2); 177 | expect(result.additional).to.equal('level'); 178 | }); 179 | 180 | }); 181 | 182 | it('this.name is set correctly', function () { 183 | 184 | ['one', 'two'].forEach(function (item) { 185 | var scope = tasks[item].thisValues[0]; 186 | expect(scope.name).to.eql(item); 187 | }); 188 | 189 | }); 190 | 191 | it('this.nameArgs is set correctly', function () { 192 | 193 | ['one', 'two'].forEach(function (item) { 194 | var scope = tasks[item].thisValues[0]; 195 | expect(scope.nameArgs).to.eql(item + ':foo'); 196 | }); 197 | 198 | }); 199 | 200 | it('this.target is set correctly', function () { 201 | 202 | ['one', 'two'].forEach(function (item) { 203 | var scope = tasks[item].thisValues[0]; 204 | expect(scope.target).to.eql('foo'); 205 | }); 206 | 207 | }); 208 | 209 | }); 210 | 211 | }); 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gulp-config 2 | 3 | [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-url]][daviddm-image] 4 | 5 | **`gulp-config`** provides grunt like config management for gulp tasks. 6 | 7 | ## Why 8 | 9 | - Even code sometimes needs a little config 10 | - Keep gulpfile small and lean 11 | - Modular task management 12 | - Portability 13 | 14 | ### Caveates 15 | 16 | - only a partial implementation of grunt config management 17 | - more test coverage needed 18 | 19 | ## Install 20 | 21 | ```bash 22 | $ npm install --save-dev gulp-config 23 | ``` 24 | 25 | ## Usage 26 | 27 | ```javascript 28 | 'use strict'; 29 | 30 | var gulp = require('gulp'), 31 | config = require('./lib')(gulp); 32 | 33 | config({ 34 | 35 | paths: { 36 | source: ['./lib/**/*.js'], 37 | tests : ['./test/**/*.js'] 38 | }, 39 | 40 | jshint : { lint : '<%=paths.source%>' }, 41 | mocha : { specs: '<%=paths.tests%>' } 42 | 43 | }); 44 | ``` 45 | > Example gulpfile.js 46 | 47 | **`gulp-config`** will auto discover by default any tasks located in the nearest `tasks` directory. This directory can be changed by passing in options when first intializing `gulp-config` ( see options ) 48 | 49 | **Take a look at this projects gruntfile and tasks directory for a working example.** 50 | 51 | ## config 52 | 53 | When tasks are registered via `gulp-config`, all sub targets will be made available via the parent task name. So for example running `> gulp jshint` will run all `jshint` targets whilst `> gulp jshint:foo` will only run the foo target. 54 | 55 | Config files can also reference other config values in the same manner as grunt, using the `<%=key.name %>` pattern. 56 | 57 | ``` 58 | { 59 | 'plugin': { 60 | options : {}, // global options 61 | target_1: { 62 | options : {}, // target options ( merged with global ) 63 | src : ['some/path'], 64 | dest : 'some/des' 65 | }, 66 | target_2: ['some/path'], 67 | target_3: 'some/path', 68 | target_4: { 69 | files: { 70 | 'dest/path': 'source/path' 71 | } 72 | } 73 | } 74 | 75 | { 76 | ``` 77 | 78 | ### help 79 | 80 | **`gulp-config`** can support [gulp-help](gulp-help), when told to do so. 81 | 82 | ```javascript 83 | var gulp = require('gulp'), 84 | helper = require('gulp-help'), 85 | config = require('gulp-config')(gulp, { 86 | help: true 87 | }); 88 | ``` 89 | 90 | This allows more detail to be added to your config which will be exposed when you run `> gulp help`. 91 | 92 | ```javascript 93 | { 94 | aliases : ['foo'], // alias names for task 95 | description : '', // task description for help 96 | } 97 | ``` 98 | > Example help options 99 | 100 | These options can be added to plugin or target keys. Note description can be set to either a string to override the default or a boolean. If you wish to hide a description in help set the value to false. 101 | 102 | ## Options 103 | 104 | When first initilizing `gulp-config`, an options object can be passed which can be used to customize where tasks are located. 105 | 106 | ### tasks 107 | 108 | This is used to set where tasks can be found. Passing a single path is supported, in addition an array of paths can also be specified. All paths support glob style matching. 109 | 110 | Should you wish to not used auto lookup, tasks can be passed directly via an object literal. 111 | 112 | For convenience, gulp-util is available automatically via gulp.util within a task. 113 | 114 | #### Basic 115 | 116 | ```javascript 117 | var gulp = require('gulp'), 118 | config = require('gulp-config')(gulp, { 119 | tasks: ['some/path/*/*.js', 'some/other/path/**/*.js'] 120 | }); 121 | ``` 122 | 123 | #### Advanced 124 | 125 | ```javascript 126 | var gulp = require('gulp'), 127 | config = require('gulp-config')(gulp, { 128 | tasks: { 129 | jshint: function (gulp) { 130 | // my custom task 131 | } 132 | } 133 | }); 134 | ``` 135 | ### tasks 136 | 137 | Tasks registered via gulp-config should follow the pattern below; 138 | 139 | ```javascript 140 | module.exports = function (gulp /* , cb */) { 141 | 142 | var options = this.options({ 143 | level: 'two' 144 | }), 145 | file = this.file, // object 146 | files = this.files; // array 147 | 148 | // task code ...... 149 | 150 | gulp.src(file.src) 151 | .pipe(someplugin(options)) 152 | 153 | }; 154 | ``` 155 | Tasks registered in this manner will have access to a config object and a file object. 156 | 157 | - The config object, is the current targets options based upon a processed config. 158 | - The file object contains the current targets src and dest properties. 159 | 160 | ## Contributing 161 | 162 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [gulp](http://gulpjs.com/). 163 | 164 | ## Release History 165 | 166 | - **0.3.0** Fix incorrect behavior of this.options() to use _.defaults 167 | - **0.2.4** 168 | - tasks can access another tasks config via this.config() 169 | - added template interpolation via [expander](https://github.com/tkellen/node-expander) 170 | - added file.src expanding via [node-configfiles](https://github.com/tkellen/node-configfiles) 171 | - **0.2.3** 172 | - restore gulp async behaviour 173 | - **0.2.2** 174 | - removed task.help && target.help (task|target).description now toggles help display 175 | - **0.2.1** 176 | - task scope fixes 177 | - this.files support added 178 | - **0.2.0** 179 | - gulp-help is nolonger bundled, use options.help 180 | - this.config nolonger available 181 | - **0.1.5** 182 | - added this.options() 183 | - deprecated this.config 184 | - **0.1.4** file.src fix 185 | - **0.1.3** Lack of sleep 186 | - **0.1.2** Expose main ( silly mistake ) 187 | - **0.1.1** Revised documentation 188 | - **0.1.0** Initial release 189 | 190 | ## License 191 | 192 | Copyright (c) 2014 Jonathan Barnett. Licensed under the ISC license. 193 | 194 | [gulp-help]: https://github.com/chmontgomery/gulp-help 195 | [npm-url]: https://npmjs.org/package/gulp-config 196 | [npm-image]: https://badge.fury.io/js/gulp-config.svg 197 | [travis-url]: https://travis-ci.org/indieisaconcept/gulp-config 198 | [travis-image]: https://travis-ci.org/indieisaconcept/gulp-config.svg?branch=master 199 | [daviddm-url]: https://david-dm.org/indieisaconcept/gulp-config.svg?theme=shields.io 200 | [daviddm-image]: https://david-dm.org/indieisaconcept/gulp-config 201 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * gulp-config 3 | * http://github.com/indieisaconcept/gulp-config 4 | * 5 | * Copyright (c) 2014 Jonathan Barnett 6 | * Licensed under the ISC license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var npath = require('path'), 12 | util = require('./util'), 13 | resolve = require('configfiles'), 14 | 15 | _ = util._, 16 | gutil = require('gulp-util'), 17 | 18 | keyExc = ['options', 'deps', 'help', 'description', 'aliases'], 19 | plugin = 'gulp-config', 20 | initConfig; 21 | 22 | initConfig = function (config) { 23 | 24 | if (!_.isPlainObject(config)) { 25 | throw new gutil.PluginError({ 26 | plugin: plugin, 27 | message: 'An invalid config object has been passed.' 28 | }); 29 | } 30 | 31 | config = config || {}; 32 | 33 | try { 34 | config = util.config(config); // normalize config 35 | } 36 | catch(err) { 37 | throw new gutil.PluginError(plugin, err); 38 | } 39 | 40 | var self = this, 41 | keys = Object.keys(config()); 42 | 43 | keys.forEach(function (key) { 44 | 45 | var cfg = config(key), 46 | name = key, 47 | 48 | copts = cfg.options || {}, // common task options 49 | cdeps = cfg.deps || [], // common task dependencies 50 | 51 | task = self.tasks[key], 52 | 53 | args, 54 | targets; 55 | 56 | keyExc.unshift(Object.keys(cfg)); 57 | targets = _.without.apply(null, keyExc); 58 | 59 | if(task) { 60 | 61 | // all targets 62 | // ----------------------------------- 63 | 64 | args = [name, targets.map(function (target) { 65 | return name + ':' + target; 66 | })]; 67 | 68 | if (self.help) { 69 | 70 | // a) allow description to be hidden 71 | // b) allow description to be overriden 72 | // c) fallback to default 73 | 74 | cfg.help = _.isBoolean(cfg.description) && !cfg.description || 75 | _.isString(cfg.description) ? cfg.description : util.format('Run all targets for "%s"', name); 76 | 77 | args.splice(1, 0, cfg.help); 78 | 79 | // ensure task aliases are added, if 80 | // defined ( see gulp-help ) 81 | 82 | if (cfg.aliases) { 83 | args.push(null, { 84 | aliases: cfg.aliases 85 | }); 86 | } 87 | 88 | } 89 | 90 | self.gulp.task.apply(self.gulp, args); 91 | 92 | // sub targets 93 | // ----------------------------------- 94 | 95 | targets.forEach(function (target) { 96 | 97 | var tname = util.format('%s:%s', name, target), 98 | tgt = cfg[target], 99 | files, file, args, delegatedTask, wrappedTask; 100 | 101 | // normalize target 102 | 103 | tgt = _.isString(tgt) || _.isArray(tgt) ? { src: tgt } : tgt; 104 | tgt.options = _.merge({}, copts, tgt.options); // merge task default options with targets 105 | tgt.deps = _.merge([], cdeps, tgt.deps); // merge task default deps with targets 106 | 107 | // file & files 108 | // src : ['some/path/**/*.js'] 109 | // dest: 'buld/path/' 110 | 111 | files = resolve(tgt); 112 | file = files[0]; 113 | 114 | delegatedTask = function () { 115 | 116 | var args = [].slice.call(arguments), 117 | scope; 118 | 119 | scope = { 120 | 121 | // misc 122 | 123 | name : name, 124 | nameArgs : tname, 125 | target : target, 126 | 127 | // target & file options 128 | 129 | file : file, 130 | files : files, 131 | options : util.options.bind(tgt.options), 132 | config : config 133 | 134 | }; 135 | 136 | return task.call.apply(task, [scope, self.gulp].concat(args)); 137 | 138 | }; 139 | 140 | // async support 141 | // Wrap delegate to ensure callback can be passed 142 | // correctly to tasks 143 | 144 | wrappedTask = task.length > 1 ? function(cb) { /*jshint unused:false */ 145 | return delegatedTask.apply(null, arguments); 146 | } : function() { 147 | return delegatedTask.apply(null, arguments); 148 | }; 149 | 150 | // create task 151 | 152 | args = [tname, tgt.deps, wrappedTask]; 153 | 154 | if (self.help) { 155 | 156 | // a) allow description to be hidden 157 | // b) allow description to be overriden 158 | // c) fallback to default 159 | 160 | tgt.help = _.isBoolean(tgt.description) && !tgt.description || 161 | _.isString(tgt.description) ? tgt.description : util.format('Run the "%s" target for "%s"', target, name); 162 | 163 | args.splice(1, 0, tgt.help); 164 | 165 | // ensure task aliases are added, if 166 | // defined ( see gulp-help ) 167 | 168 | if (tgt.aliases) { 169 | args.push({ 170 | aliases: tgt.aliases 171 | }); 172 | } 173 | 174 | } 175 | 176 | self.gulp.task.apply(self.gulp, args); 177 | self.gulp.tasks[tname].options = tgt.options; 178 | 179 | }); 180 | 181 | } 182 | 183 | }); 184 | 185 | }; 186 | 187 | /** 188 | * @function config 189 | * Creates a config helper to initializing gulp tasks, 190 | * in a similar vein to grunt 191 | * 192 | * @param {function} gulp a gulp instance 193 | * @param {object} options config specific options 194 | * 195 | * @returns {object} 196 | */ 197 | 198 | module.exports = function (gulp, options) { 199 | 200 | var dir = process.cwd(); 201 | 202 | options = options || {}; 203 | options.gulp = gulp; 204 | options.gulp.util = gutil; // make gulp utils available 205 | 206 | // provide support for a help menu 207 | 208 | // tasks: 209 | // ------------------------------------- 210 | // 211 | // tasks can be passed as either an array of paths, or 212 | // as an object of tasks 213 | // 214 | // find all possible task files, in a specified directory 215 | // ensuring only files matching the pattern 216 | // 217 | // - dir/task.js 218 | // - dir/task/index,js 219 | 220 | options.tasks = options.tasks || ['./tasks/*/*.js', './tasks/*.js']; 221 | options.tasks = _.isArray(options.tasks) ? options.tasks : options.tasks; 222 | options.tasks = _.isString(options.tasks) ? [options.tasks] : options.tasks; 223 | 224 | // prefech tasks, for use later 225 | 226 | if (_.isArray(options.tasks)) { 227 | 228 | options.tasks = options.tasks.reduce(function (previous, current) { 229 | 230 | var tasks = util.glob.sync(current); 231 | 232 | tasks.forEach(function (task) { 233 | 234 | // normalize task name accoring to, directory 235 | // structure 236 | 237 | var filename = npath.basename(task).split('.')[0], 238 | directory = npath.dirname(task).split(npath.sep).pop(), 239 | name = filename !== 'index' ? filename : directory; 240 | 241 | previous[name] = require(npath.normalize(npath.join(dir, task))); 242 | 243 | }); 244 | 245 | return previous; 246 | 247 | }, {}); 248 | 249 | } 250 | 251 | return initConfig.bind(options); 252 | 253 | }; 254 | --------------------------------------------------------------------------------