├── .babelrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── package.json └── src ├── babelrc.json ├── bin └── index.js ├── index.js ├── taskCreators ├── buildTaskCreator.js ├── fixTaskCreator.js ├── index.js ├── lintTaskCreator.js └── testTaskCreator.js └── utilities ├── createBabelConfig.js ├── createPlumberConfig.js ├── debounceSequence.js ├── index.js ├── logEvents.js ├── patchGulpSrc.js ├── runSequence.js └── watch.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "stage-0" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | dist 4 | *.log 5 | .* 6 | !.gitignore 7 | !.npmignore 8 | !.babelrc 9 | !.travis.yml 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tests 3 | coverage 4 | .* 5 | *.log 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Gajus Kuizinas (http://gajus.com/) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the Gajus Kuizinas (http://gajus.com/) nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | This project is no longer actively maintained. 4 | 5 | I thought Pragmatist is going to save me a lot of time – a single build program for all of my open-source projects. The primary goals were to (1) standardize build tools (unit testing, linting, code coverage), (2) reduce the configuration boilerplate and to (3) enable simple updates of these changes across all projects. 6 | 7 | However, as the list of projects grew that depend on Pragmatist, so did the list of the dependencies and configurations that come with it. It got to the point where installing Pragmatist alone is taking more than 10 minutes. Furthermore, bundling together unit testing, linting JavaScript, linting CSS and other linters made this package increasingly susceptible to breaking changes. If proper semantic versioning were to have been followed, this package now would have a major version somewhere in hundreds. However, failing to follow semver resulted in CI failing simultaneously across all the projects that depend on Pragmatist on each new release. In the end, this required that after each update to Pragmatist all depending projects needed to be inspected and updated accordingly. 8 | 9 | I have gone back to using the respective build tools and maintaining the respective configurations (or shareable configurations, e.g. [eslint-config-canonical](https://github.com/gajus/eslint-config-canonical)) for each project. 10 | 11 | # Pragmatist 12 | 13 | [![NPM version](http://img.shields.io/npm/v/pragmatist.svg?style=flat-square)](https://www.npmjs.com/package/pragmatist) 14 | [![js-canonical-style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical) 15 | 16 | A collection of tasks to standardize builds. 17 | 18 | ## Tasks 19 | 20 | Tasks that are not documented (including dependencies of the documented tasks that are not documented) are considered private and can be changed/renamed or removed without a warning. 21 | 22 | #### `lint` 23 | 24 | * Uses [Canonical](https://github.com/gajus/canonical) to lint all `*.css`, `*.scss` and `*.js` files in `./src` and `./tests` directories. 25 | 26 | #### `fix` 27 | 28 | 29 | 30 | #### `build` 31 | 32 | * Copies all files from `./src` directory to `./dist`. 33 | * Uses [Babel](https://babeljs.io/) to compile files in `./src` directory. 34 | * Compiled files overwrite the existing files in `./dist` directory. 35 | * Source Maps are stored in the `./dist` directory`. 36 | * Uses [`babel-plugin-lodash`](https://github.com/megawac/babel-plugin-lodash). 37 | * Babel compiler is configured to use [stage 0](https://babeljs.io/docs/usage/options/) ES features. 38 | 39 | #### `test` 40 | 41 | * Uses [Babel](https://babeljs.io/) to compile files in `./tests` directory. 42 | * Uses [Istanbul](https://github.com/gotwarlost/istanbul) to generate test coverage. 43 | * Uses [Mocha](https://mochajs.org/) to execute tests in `./tests` directory. 44 | 45 | Istanbul assumes that tests are using `./src` files (as opposed to `./dist`). 46 | 47 | Istanbul coverage report is written to the `./coverage` directory. A coverage summary is included in the CLI output. 48 | 49 | #### `watch` 50 | 51 | Runs `lint`, `test` and `build` tasks every time `./src/**/*.js` or `./tests/**/*.js` changes. 52 | 53 | #### `watch-lint` 54 | 55 | Runs `lint` task every time `./src/**/*.js` or `./tests/**/*.js` changes. 56 | 57 | #### `watch-test` 58 | 59 | Runs `test` task every time `./src/**/*.js` or `./tests/**/*.js` changes. 60 | 61 | #### `watch-build` 62 | 63 | Runs `build` task every time `./src/**/*.js` or `./tests/**/*.js` changes. 64 | 65 | ## Gulp Tasks 66 | 67 | `pragmatist` can be used to extend your existing [gulp](https://github.com/gulpjs/gulp) tasks. 68 | 69 | ```js 70 | import gulp from 'gulp'; 71 | import pragmatist from 'pragmatist'; 72 | 73 | /** 74 | * @param {Object} gulp 75 | * @param {string} prefix Used to prefix all pragmatist tasks. 76 | * @returns {undefined} 77 | */ 78 | pragmatist(gulp); 79 | ``` 80 | 81 | This will make all `pragmatist` tasks available under `pragmatist:` namespace, e.g. 82 | 83 | ```sh 84 | gulp pragmatist:test 85 | ``` 86 | 87 | ## CLI Program 88 | 89 | `pragmatist` can be used as a CLI program to run all the tasks. 90 | 91 | ```sh 92 | npm install pragmatist -g 93 | ``` 94 | 95 | Tasks can be executed by running: 96 | 97 | ```sh 98 | pragmatist 99 | ``` 100 | 101 | Just running `pragmatist` will execute the `test` task. 102 | 103 | Multiple tasks can be executed one after the other, e.g. 104 | 105 | ```sh 106 | pragmatist 107 | ``` 108 | 109 | ### ES5 110 | 111 | The default behavior for `build` task is to compile code for [`node`](https://nodejs.org/). Specifically, for the latest version of `node`. 112 | 113 | To compile code down to ES5, you must add `--es5` flag to the command line, e.g. 114 | 115 | ```sh 116 | pragmatist build --es5 117 | ``` 118 | 119 | ### Notifications 120 | 121 | Use `--notifications` flag to enable OS level notifications about errors that occur during the build. 122 | 123 | ```sh 124 | pragmatist build --notifications 125 | ``` 126 | 127 | ### Types 128 | 129 | Use `--type-assertions` flag to enable [runtime type assertions](https://github.com/codemix/babel-plugin-typecheck). 130 | 131 | ```sh 132 | pragmatist build --type-assertions 133 | ``` 134 | 135 | ## NPM 136 | 137 | A typical project using `pragmatist` will define the following NPM scripts: 138 | 139 | ```json 140 | "scripts": { 141 | "lint": "pragmatist lint", 142 | "watch-lint": "pragmatist watch-lint", 143 | "test": "pragmatist --type-assertions test", 144 | "watch-test": "pragmatist --type-assertions test", 145 | "build": "pragmatist --es5 build", 146 | "watch-build": "pragmatist --es5 watch-build" 147 | }, 148 | ``` 149 | 150 | ## Ignore Unnecessary Files 151 | 152 | This is just a reminder. Pragmatist will produce several files that you do not want to commit to the repository or include in the npm bundle. 153 | 154 | Add to `.gitignore`: 155 | 156 | ``` 157 | node_modules 158 | coverage 159 | dist 160 | *.log 161 | .* 162 | !.gitignore 163 | !.npmignore 164 | !.babelrc 165 | !.travis.yml 166 | ``` 167 | 168 | Add to `.npmignore` 169 | 170 | ``` 171 | src 172 | tests 173 | coverage 174 | .* 175 | *.log 176 | ``` 177 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "email": "gajus@gajus.com", 4 | "name": "Gajus Kuizinas", 5 | "url": "http://gajus.com" 6 | }, 7 | "bin": "./dist/bin/index.js", 8 | "bundledDependencies": [ 9 | "babel-plugin-add-module-exports", 10 | "babel-plugin-check-es2015-constants", 11 | "babel-plugin-lodash-modularize", 12 | "babel-plugin-transform-class-properties", 13 | "babel-plugin-transform-es2015-arrow-functions", 14 | "babel-plugin-transform-es2015-block-scoped-functions", 15 | "babel-plugin-transform-es2015-block-scoping", 16 | "babel-plugin-transform-es2015-classes", 17 | "babel-plugin-transform-es2015-computed-properties", 18 | "babel-plugin-transform-es2015-destructuring", 19 | "babel-plugin-transform-es2015-for-of", 20 | "babel-plugin-transform-es2015-function-name", 21 | "babel-plugin-transform-es2015-literals", 22 | "babel-plugin-transform-es2015-modules-commonjs", 23 | "babel-plugin-transform-es2015-object-super", 24 | "babel-plugin-transform-es2015-parameters", 25 | "babel-plugin-transform-es2015-shorthand-properties", 26 | "babel-plugin-transform-es2015-spread", 27 | "babel-plugin-transform-es2015-sticky-regex", 28 | "babel-plugin-transform-es2015-template-literals", 29 | "babel-plugin-transform-es2015-typeof-symbol", 30 | "babel-plugin-transform-es2015-unicode-regex", 31 | "babel-plugin-transform-object-set-prototype-of-to-assign", 32 | "babel-plugin-transform-proto-to-assign", 33 | "babel-plugin-transform-regenerator", 34 | "babel-plugin-transform-strict-mode", 35 | "babel-plugin-typecheck", 36 | "babel-preset-react", 37 | "babel-preset-stage-0", 38 | "bluebird", 39 | "chalk", 40 | "csscomb", 41 | "del", 42 | "fancy-log", 43 | "globby", 44 | "gulp", 45 | "gulp-babel", 46 | "gulp-babel2", 47 | "gulp-mocha", 48 | "gulp-plumber", 49 | "gulp-sourcemaps", 50 | "lodash", 51 | "pretty-hrtime", 52 | "prettyjson", 53 | "run-sequence", 54 | "source-map-support", 55 | "stack-trace", 56 | "yargs" 57 | ], 58 | "dependencies": { 59 | "babel-plugin-add-module-exports": "^0.2.1", 60 | "babel-plugin-check-es2015-constants": "^6.8.0", 61 | "babel-plugin-lodash-modularize": "^0.3.2", 62 | "babel-plugin-transform-class-properties": "^6.8.0", 63 | "babel-plugin-transform-es2015-arrow-functions": "^6.8.0", 64 | "babel-plugin-transform-es2015-block-scoped-functions": "^6.8.0", 65 | "babel-plugin-transform-es2015-block-scoping": "^6.8.0", 66 | "babel-plugin-transform-es2015-classes": "^6.8.0", 67 | "babel-plugin-transform-es2015-computed-properties": "^6.8.0", 68 | "babel-plugin-transform-es2015-destructuring": "^6.8.0", 69 | "babel-plugin-transform-es2015-for-of": "^6.8.0", 70 | "babel-plugin-transform-es2015-function-name": "^6.8.0", 71 | "babel-plugin-transform-es2015-literals": "^6.8.0", 72 | "babel-plugin-transform-es2015-modules-commonjs": "^6.8.0", 73 | "babel-plugin-transform-es2015-object-super": "^6.8.0", 74 | "babel-plugin-transform-es2015-parameters": "^6.8.0", 75 | "babel-plugin-transform-es2015-shorthand-properties": "^6.8.0", 76 | "babel-plugin-transform-es2015-spread": "^6.8.0", 77 | "babel-plugin-transform-es2015-sticky-regex": "^6.8.0", 78 | "babel-plugin-transform-es2015-template-literals": "^6.8.0", 79 | "babel-plugin-transform-es2015-typeof-symbol": "^6.8.0", 80 | "babel-plugin-transform-es2015-unicode-regex": "^6.8.0", 81 | "babel-plugin-transform-object-set-prototype-of-to-assign": "^6.8.0", 82 | "babel-plugin-transform-proto-to-assign": "^6.8.0", 83 | "babel-plugin-transform-regenerator": "^6.8.0", 84 | "babel-plugin-transform-strict-mode": "^6.8.0", 85 | "babel-plugin-typecheck": "^3.9.0", 86 | "babel-preset-react": "^6.5.0", 87 | "babel-preset-stage-0": "^6.5.0", 88 | "bluebird": "^3.3.5", 89 | "canonical": "^3.2.1", 90 | "chalk": "^1.1.3", 91 | "chokidar": "^1.5.0", 92 | "csscomb": "^3.1.8", 93 | "del": "^2.2.0", 94 | "fancy-log": "^1.2.0", 95 | "globby": "^4.0.0", 96 | "gulp": "^3.9.1", 97 | "gulp-babel": "^6.1.2", 98 | "gulp-babel2": "^6.1.5", 99 | "gulp-mocha": "^2.2.0", 100 | "gulp-plumber": "^1.1.0", 101 | "gulp-sourcemaps": "^2.0.0-alpha", 102 | "lodash": "^4.12.0", 103 | "node-notifier": "^4.5.0", 104 | "pretty-hrtime": "^1.0.2", 105 | "prettyjson": "^1.1.3", 106 | "run-sequence": "^1.1.5", 107 | "source-map-support": "^0.4.0", 108 | "stack-trace": "^0.0.9", 109 | "yargs": "^4.7.0" 110 | }, 111 | "description": "A collection of tasks to standardize builds.", 112 | "devDependencies": { 113 | "babel-cli": "^6.8.0", 114 | "babel-preset-es2015": "^6.6.0", 115 | "babel-preset-stage-0": "^6.5.0", 116 | "bundle-dependencies": "^1.0.2", 117 | "canonical": "^3.2.1", 118 | "create-index": "^0.1.3", 119 | "jsonlint": "^1.6.2" 120 | }, 121 | "keywords": [ 122 | "gulp", 123 | "linter", 124 | "test", 125 | "javascript", 126 | "css", 127 | "scss" 128 | ], 129 | "license": "BSD-3-Clause", 130 | "main": "./dist", 131 | "name": "pragmatist", 132 | "repository": { 133 | "type": "git", 134 | "url": "https://github.com/gajus/pragmatist" 135 | }, 136 | "scripts": { 137 | "build": "rm -fr ./dist; cp -r ./src ./dist; babel --presets es2015,stage-0 ./src --out-dir ./dist --source-maps", 138 | "bundle-dependencies": "bundle-dependencies", 139 | "bundle-publish": "bundle-dependencies update --exclude canonical chokidar node-notifier; git commit -m 'Bundled dependencies.' ./package.json; git push; BUNDLED_DEPENDENCIES=$(bundle-dependencies list-bundled-dependencies); rm -fr ./node_modules; npm install --silent --production $BUNDLED_DEPENDENCIES; npm dedupe; npm prune; npm publish; npm install --silent;", 140 | "create-index": "create-index ./src --update-index", 141 | "format-json": "jsonlint --sort-keys --in-place --indent ' '", 142 | "format-json-config": "npm run format-json ./package.json; npm run format-json ./src/babelrc.json", 143 | "lint": "canonical lint ./src/", 144 | "watch-build": "npm run build; babel --presets es2015,stage-0 --watch ./src --out-dir ./dist --source-maps" 145 | }, 146 | "version": "3.0.24" 147 | } -------------------------------------------------------------------------------- /src/babelrc.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /src/bin/index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | import _ from 'lodash'; 4 | import Promise from 'bluebird'; 5 | import gulp from 'gulp'; 6 | import yargs from 'yargs'; 7 | import pragmatist from './..'; 8 | 9 | let argv, 10 | executeTaskNames, 11 | knownTaskNames; 12 | 13 | argv = yargs 14 | .demand(1) 15 | .options({ 16 | es5: { 17 | description: 'Uses es2015 Babel preset for the build.', 18 | type: 'boolean' 19 | }, 20 | notifications: { 21 | description: 'Sends a notification to the OS if an error occurs.', 22 | type: 'boolean' 23 | }, 24 | 'type-assertions': { 25 | description: 'Inlines runtime type assertions for the type annotations.', 26 | type: 'boolean' 27 | } 28 | }) 29 | .argv; 30 | 31 | pragmatist(gulp, { 32 | es5: argv.es5, 33 | forceLogging: true, 34 | notifications: argv.notifications, 35 | prefix: 'pragmatist:', 36 | typeAssertions: argv.typeAssertions 37 | }); 38 | 39 | knownTaskNames = _.keys(gulp.tasks); 40 | executeTaskNames = argv._; 41 | 42 | Promise 43 | .resolve(executeTaskNames) 44 | /* eslint-disable lodash3/prefer-lodash-method */ 45 | .map((taskName) => { 46 | /* eslint-enable lodash3/prefer-lodash-method */ 47 | let executeTaskName; 48 | 49 | executeTaskName = 'pragmatist:' + taskName; 50 | 51 | if (_.indexOf(knownTaskNames, executeTaskName) === -1) { 52 | throw new Error('"' + executeTaskName + '" task does not exist.'); 53 | } 54 | 55 | return new Promise((resolve) => { 56 | gulp 57 | .start(executeTaskName) 58 | .on('task_stop', () => { 59 | resolve(); 60 | }); 61 | }); 62 | }, { 63 | concurrency: 1 64 | }); 65 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { 3 | testTaskCreator, 4 | lintTaskCreator, 5 | buildTaskCreator, 6 | fixTaskCreator 7 | } from './taskCreators'; 8 | import { 9 | watch, 10 | logEvents, 11 | createBabelConfig, 12 | createPlumberConfig, 13 | runSequence, 14 | patchGulpSrc 15 | } from './utilities'; 16 | 17 | 18 | /** 19 | * @typedef {Object} options 20 | * @property {string} prefix Used to prefix all pragmatist tasks. 21 | * @property {boolean} forceLogging Forces gulp logs for task start time and completion time. 22 | */ 23 | 24 | /** 25 | * @param {Object} gulp 26 | * @param {options} options 27 | * @returns {undefined} 28 | */ 29 | export default (gulp, options = {}) => { 30 | let babelConfig, 31 | config, 32 | plumberConfig; 33 | 34 | config = _.assign({}, { 35 | forceLogging: false, 36 | notifications: false, 37 | prefix: 'pragmatist:', 38 | typeAssertions: false 39 | }, options); 40 | 41 | babelConfig = createBabelConfig(config); 42 | plumberConfig = createPlumberConfig(config); 43 | 44 | gulp.src = patchGulpSrc(gulp, plumberConfig); 45 | 46 | if (config.forceLogging) { 47 | logEvents(gulp); 48 | } 49 | 50 | testTaskCreator(config, gulp, babelConfig); 51 | lintTaskCreator(config, gulp); 52 | buildTaskCreator(config, gulp, babelConfig); 53 | fixTaskCreator(config, gulp); 54 | 55 | gulp.task(config.prefix + 'watch', () => { 56 | watch([ 57 | './src/**/*', 58 | './tests/**/*' 59 | ], () => { 60 | return runSequence(gulp, [ 61 | config.prefix + 'lint', 62 | config.prefix + 'test', 63 | config.prefix + 'build' 64 | ]); 65 | }); 66 | }); 67 | 68 | gulp.task(config.prefix + 'watch-lint', () => { 69 | watch([ 70 | './src/**/*', 71 | './tests/**/*' 72 | ], () => { 73 | return runSequence(gulp, [ 74 | config.prefix + 'lint' 75 | ]); 76 | }); 77 | }); 78 | 79 | gulp.task(config.prefix + 'watch-test', () => { 80 | watch([ 81 | './src/**/*', 82 | './tests/**/*' 83 | ], () => { 84 | return runSequence(gulp, [ 85 | config.prefix + 'test' 86 | ]); 87 | }); 88 | }); 89 | 90 | gulp.task(config.prefix + 'watch-build', () => { 91 | watch([ 92 | './src/**/*', 93 | './tests/**/*' 94 | ], () => { 95 | return runSequence(gulp, [ 96 | config.prefix + 'build' 97 | ]); 98 | }); 99 | }); 100 | }; 101 | -------------------------------------------------------------------------------- /src/taskCreators/buildTaskCreator.js: -------------------------------------------------------------------------------- 1 | import babel from 'gulp-babel'; 2 | import del from 'del'; 3 | import sourcemaps from 'gulp-sourcemaps'; 4 | import chalk from 'chalk'; 5 | import { 6 | runSequence 7 | } from './../utilities'; 8 | 9 | export default (config, gulp, babelConfig) => { 10 | gulp.task(config.prefix + 'build:clean', () => { 11 | return del('./dist'); 12 | }); 13 | 14 | gulp.task(config.prefix + 'build:copy', () => { 15 | return gulp 16 | .src('./src/**/*') 17 | .pipe(gulp.dest('./dist')); 18 | }); 19 | 20 | gulp.task(config.prefix + 'build:compile', () => { 21 | if (!config.es5) { 22 | /* eslint-disable no-console */ 23 | console.log('Making ' + chalk.red('ES5 incompatible build') + '. Use "es5" option to compile code down to ES5.'); 24 | /* eslint-enable no-console */ 25 | } 26 | 27 | return gulp 28 | .src('./src/**/*.js') 29 | .pipe(sourcemaps.init()) 30 | .pipe(babel(babelConfig)) 31 | .pipe(sourcemaps.write('.')) 32 | .pipe(gulp.dest('./dist')); 33 | }); 34 | 35 | gulp.task(config.prefix + 'build', () => { 36 | return runSequence(gulp, [ 37 | config.prefix + 'build:clean', 38 | config.prefix + 'build:copy', 39 | config.prefix + 'build:compile' 40 | ]); 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /src/taskCreators/fixTaskCreator.js: -------------------------------------------------------------------------------- 1 | import glob from 'globby'; 2 | import { 3 | fixFiles 4 | } from 'canonical'; 5 | 6 | export default (config, gulp) => { 7 | gulp.task(config.prefix + 'fix', () => { 8 | return glob([ 9 | './src/**/*.js', 10 | './tests/**/*.js', 11 | './src/**/*.css', 12 | './src/**/*.scss' 13 | ]) 14 | .then((paths) => { 15 | let report; 16 | 17 | report = fixFiles(paths); 18 | 19 | /* eslint-disable no-console */ 20 | console.log(report); 21 | /* eslint-enable no-console */ 22 | }); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /src/taskCreators/index.js: -------------------------------------------------------------------------------- 1 | 'create index'; 2 | 3 | export buildTaskCreator from './buildTaskCreator.js'; 4 | export fixTaskCreator from './fixTaskCreator.js'; 5 | export lintTaskCreator from './lintTaskCreator.js'; 6 | export testTaskCreator from './testTaskCreator.js'; 7 | 8 | -------------------------------------------------------------------------------- /src/taskCreators/lintTaskCreator.js: -------------------------------------------------------------------------------- 1 | import glob from 'globby'; 2 | import { 3 | lintFiles, 4 | getFormatter 5 | } from 'canonical'; 6 | 7 | export default (config, gulp) => { 8 | gulp.task(config.prefix + 'lint', () => { 9 | return glob([ 10 | './src/**/*.js', 11 | './tests/**/*.js', 12 | './src/**/*.css', 13 | './src/**/*.scss' 14 | ]) 15 | .then((paths) => { 16 | const formatter = getFormatter(); 17 | const report = lintFiles(paths); 18 | 19 | /* eslint-disable no-console */ 20 | console.log(formatter(report)); 21 | /* eslint-enable no-console */ 22 | }); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /src/taskCreators/testTaskCreator.js: -------------------------------------------------------------------------------- 1 | import babel from 'gulp-babel'; 2 | import del from 'del'; 3 | import sourcemaps from 'gulp-sourcemaps'; 4 | import mocha from 'gulp-mocha'; 5 | import { 6 | runSequence 7 | } from './../utilities'; 8 | 9 | export default (config, gulp, babelConfig) => { 10 | gulp.task(config.prefix + 'test:pre-copy-clean', () => { 11 | return del('./.test-build'); 12 | }); 13 | 14 | gulp.task(config.prefix + 'test:copy', () => { 15 | return gulp 16 | .src([ 17 | './tests/**/*', 18 | './src/**/*' 19 | ], { 20 | base: './' 21 | }) 22 | .pipe(gulp.dest('./.test-build')); 23 | }); 24 | 25 | gulp.task(config.prefix + 'test:build', () => { 26 | return gulp 27 | .src('./.test-build/**/*.js') 28 | .pipe(sourcemaps.init()) 29 | .pipe(babel(babelConfig)) 30 | .pipe(sourcemaps.write('.', { 31 | sourceRoot: process.cwd() 32 | })) 33 | .pipe(gulp.dest('./.test-build')); 34 | }); 35 | 36 | gulp.task(config.prefix + 'test:run', () => { 37 | return gulp 38 | .src(['./.test-build/tests/**/*.js'], { 39 | read: false 40 | }) 41 | .pipe(mocha({ 42 | require: [ 43 | require.resolve('source-map-support/register') 44 | ] 45 | })); 46 | }); 47 | 48 | gulp.task(config.prefix + 'test:clean', () => { 49 | return del('./.test-build'); 50 | }); 51 | 52 | gulp.task(config.prefix + 'test', () => { 53 | return runSequence(gulp, [ 54 | config.prefix + 'test:pre-copy-clean', 55 | config.prefix + 'test:copy', 56 | config.prefix + 'test:build', 57 | config.prefix + 'test:run', 58 | config.prefix + 'test:clean' 59 | ]); 60 | }); 61 | }; 62 | -------------------------------------------------------------------------------- /src/utilities/createBabelConfig.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | export default (config) => { 4 | let babelConfig; 5 | 6 | babelConfig = { 7 | babelrc: false, 8 | extends: path.resolve(__dirname, './../babelrc.json'), 9 | plugins: [ 10 | [ 11 | require.resolve('babel-plugin-lodash-modularize'), 12 | { 13 | lodashVersion: '4.0.0' 14 | } 15 | ], 16 | require.resolve('babel-plugin-add-module-exports') 17 | ], 18 | presets: [ 19 | require.resolve('babel-preset-stage-0'), 20 | require.resolve('babel-preset-react') 21 | ] 22 | }; 23 | 24 | if (config.typeAssertions) { 25 | babelConfig.plugins.unshift(require.resolve('babel-plugin-typecheck')); 26 | } 27 | 28 | if (config.es5) { 29 | // babelConfig.presets.unshift(require.resolve('babel-preset-es2015')); 30 | babelConfig.presets.unshift({ 31 | plugins: [ 32 | require('babel-plugin-transform-es2015-template-literals'), 33 | require('babel-plugin-transform-es2015-literals'), 34 | require('babel-plugin-transform-es2015-function-name'), 35 | require('babel-plugin-transform-es2015-arrow-functions'), 36 | require('babel-plugin-transform-es2015-block-scoped-functions'), 37 | [ 38 | require('babel-plugin-transform-es2015-classes'), 39 | { 40 | loose: true 41 | } 42 | ], 43 | require('babel-plugin-transform-es2015-object-super'), 44 | require('babel-plugin-transform-es2015-shorthand-properties'), 45 | require('babel-plugin-transform-es2015-computed-properties'), 46 | require('babel-plugin-transform-es2015-for-of'), 47 | require('babel-plugin-transform-es2015-sticky-regex'), 48 | require('babel-plugin-transform-es2015-unicode-regex'), 49 | require('babel-plugin-check-es2015-constants'), 50 | require('babel-plugin-transform-es2015-spread'), 51 | require('babel-plugin-transform-es2015-parameters'), 52 | require('babel-plugin-transform-es2015-destructuring'), 53 | require('babel-plugin-transform-es2015-block-scoping'), 54 | require('babel-plugin-transform-es2015-typeof-symbol'), 55 | require('babel-plugin-transform-es2015-modules-commonjs'), 56 | [ 57 | require('babel-plugin-transform-regenerator'), 58 | { 59 | async: false, 60 | asyncGenerators: false 61 | } 62 | ] 63 | ] 64 | }); 65 | 66 | babelConfig.plugins.push(require.resolve('babel-plugin-transform-proto-to-assign')); 67 | babelConfig.plugins.push(require.resolve('babel-plugin-transform-object-set-prototype-of-to-assign')); 68 | } else { 69 | babelConfig.plugins.push(require.resolve('babel-plugin-transform-es2015-modules-commonjs')); 70 | babelConfig.plugins.push(require.resolve('babel-plugin-transform-es2015-parameters')); 71 | } 72 | 73 | return babelConfig; 74 | }; 75 | -------------------------------------------------------------------------------- /src/utilities/createPlumberConfig.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import notifier from 'node-notifier'; 3 | import stackTrace from 'stack-trace'; 4 | import log from 'fancy-log'; 5 | import prettyjson from 'prettyjson'; 6 | 7 | export default (config) => { 8 | let errorHandler; 9 | 10 | errorHandler = function (error) { 11 | let errorPrint; 12 | 13 | errorPrint = error; 14 | 15 | if (error.message) { 16 | if (config.notifications) { 17 | notifier.notify({ 18 | message: error.message, 19 | title: error.name 20 | }); 21 | } 22 | 23 | errorPrint = { 24 | message: error.message, 25 | name: error.name, 26 | plugin: error.plugin 27 | }; 28 | 29 | if (error.stack) { 30 | errorPrint.stack = _.map(stackTrace.parse(error), (crumb) => { 31 | return crumb.fileName + ':' + crumb.lineNumber + ':' + crumb.columnNumber; 32 | }); 33 | } 34 | 35 | /* eslint-disable no-underscore-dangle */ 36 | if (error._babel && error.codeFrame) { 37 | /* eslint-enable no-underscore-dangle */ 38 | errorPrint.code = { 39 | file: error.fileName + ':' + error.loc.line + ':' + error.loc.column, 40 | frame: error.codeFrame 41 | }; 42 | 43 | if (errorPrint.message.indexOf(error.fileName + ': ') === 0) { 44 | errorPrint.message = errorPrint.message.substr(error.fileName.length + 2); 45 | } 46 | } 47 | } 48 | 49 | log('\n\n' + prettyjson.render(errorPrint) + '\n'); 50 | 51 | this.emit('end'); 52 | }; 53 | 54 | return { 55 | errorHandler 56 | }; 57 | }; 58 | -------------------------------------------------------------------------------- /src/utilities/debounceSequence.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | /** 4 | * Debounces execution of 'task' and queues 'task' to run again 5 | * if an outside attempt to call 'task' was done before the 6 | * previous execution have ended. 7 | */ 8 | 9 | export default (task) => { 10 | let runTask, 11 | taskIsRunning; 12 | 13 | taskIsRunning = false; 14 | 15 | runTask = () => { 16 | // console.log('TASK REQUEST'); 17 | 18 | if (taskIsRunning) { 19 | runTask(); 20 | 21 | return; 22 | } 23 | 24 | taskIsRunning = true; 25 | 26 | // console.log('TASK START'); 27 | 28 | task(() => { 29 | taskIsRunning = false; 30 | 31 | // console.log('TASK DONE'); 32 | }); 33 | }; 34 | 35 | runTask = _.debounce(runTask, 100); 36 | 37 | return runTask; 38 | }; 39 | -------------------------------------------------------------------------------- /src/utilities/index.js: -------------------------------------------------------------------------------- 1 | 'create index'; 2 | 3 | export createBabelConfig from './createBabelConfig.js'; 4 | export createPlumberConfig from './createPlumberConfig.js'; 5 | export debounceSequence from './debounceSequence.js'; 6 | export logEvents from './logEvents.js'; 7 | export patchGulpSrc from './patchGulpSrc.js'; 8 | export runSequence from './runSequence.js'; 9 | export watch from './watch.js'; 10 | 11 | -------------------------------------------------------------------------------- /src/utilities/logEvents.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | import log from 'fancy-log'; 4 | import chalk from 'chalk'; 5 | import prettyHrtime from 'pretty-hrtime'; 6 | 7 | let formatError; 8 | 9 | // Format orchestrator errors 10 | formatError = (event) => { 11 | if (!event.err) { 12 | return event.message; 13 | } 14 | 15 | // PluginError 16 | if (typeof event.err.showStack === 'boolean') { 17 | return event.err.toString(); 18 | } 19 | 20 | // Normal error 21 | if (event.err.stack) { 22 | return event.err.stack; 23 | } 24 | 25 | // Unknown (string, number, etc.) 26 | return new Error(String(event.err)).stack; 27 | } 28 | 29 | /** 30 | * @see https://github.com/gulpjs/gulp/blob/a54996c6a98acc000ebb310f89d7ca4bbacb9371/bin/gulp.js 31 | */ 32 | export default (gulpInst) => { 33 | gulpInst.on('task_start', (event) => { 34 | // TODO: batch these 35 | // so when 5 tasks start at once it only logs one time with all 5 36 | log('Starting', '\'' + chalk.cyan(event.task) + '\'...'); 37 | }); 38 | 39 | gulpInst.on('task_stop', (event) => { 40 | let time; 41 | 42 | time = prettyHrtime(event.hrDuration); 43 | 44 | log('Finished', '\'' + chalk.cyan(event.task) + '\'', 'after', chalk.magenta(time)); 45 | }); 46 | 47 | gulpInst.on('task_err', (event) => { 48 | let message, 49 | time; 50 | 51 | message = formatError(event); 52 | time = prettyHrtime(event.hrDuration); 53 | 54 | log( 55 | '\'' + chalk.cyan(event.task) + '\'', 56 | chalk.red('errored after'), 57 | chalk.magenta(time) 58 | ); 59 | 60 | log(message); 61 | }); 62 | }; 63 | -------------------------------------------------------------------------------- /src/utilities/patchGulpSrc.js: -------------------------------------------------------------------------------- 1 | import plumber from 'gulp-plumber'; 2 | 3 | export default (gulp, plumberOptions = {}) => { 4 | let gulpSrc; 5 | 6 | gulpSrc = gulp.src; 7 | 8 | return (...args) => { 9 | return gulpSrc 10 | .apply(gulp, args) 11 | .pipe(plumber(plumberOptions)); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /src/utilities/runSequence.js: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | import runSequenceUnpaired from 'run-sequence'; 3 | 4 | export default (gulp, tasks) => { 5 | let runSequence; 6 | 7 | runSequence = runSequenceUnpaired.use(gulp); 8 | 9 | return new Promise((resolve, reject) => { 10 | let doneCallback; 11 | 12 | doneCallback = (error) => { 13 | if (error) { 14 | reject(error); 15 | } else { 16 | resolve(); 17 | } 18 | }; 19 | 20 | runSequence.apply(null, tasks.concat(doneCallback)); 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /src/utilities/watch.js: -------------------------------------------------------------------------------- 1 | import chokidar from 'chokidar'; 2 | import debounceSequence from './debounceSequence'; 3 | 4 | export default (paths, task) => { 5 | chokidar 6 | .watch(paths) 7 | .on('all', debounceSequence((done) => { 8 | task().then(done); 9 | })); 10 | }; 11 | --------------------------------------------------------------------------------