├── .editorconfig ├── .gitignore ├── .travis.yml ├── appveyor.yml ├── lerna.json ├── license ├── logo.png ├── package.json ├── packages ├── babel │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ └── a.js │ │ └── index.js ├── browserify │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── foo.js │ │ └── sub │ │ │ ├── bar.js │ │ │ ├── baz.js │ │ │ └── index.js │ │ └── index.js ├── buble │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ └── foo.js │ │ └── index.js ├── clear │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ └── index.js ├── coffee │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── bar.coffee │ │ ├── foo.coffee │ │ └── foo.js │ │ └── index.js ├── concat │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── a.js │ │ ├── b.js │ │ ├── c.js │ │ └── sub │ │ │ └── sub │ │ │ ├── a.js │ │ │ └── b.js │ │ └── index.js ├── esnext │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── bar.js │ │ ├── foo.js │ │ └── taskfile.js │ │ └── index.js ├── flatten │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── base.js │ │ └── foo │ │ │ ├── bar │ │ │ ├── bar1.js │ │ │ ├── bar2.js │ │ │ └── baz │ │ │ │ ├── baz1.js │ │ │ │ ├── baz2.js │ │ │ │ └── baz3.js │ │ │ └── foo1.js │ │ └── index.js ├── gzip │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── a.txt │ │ └── index.js ├── htmlmin │ ├── config.js │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ └── foo.html │ │ └── index.js ├── jest │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ └── index.js ├── less │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── expect.css │ │ ├── foo.less │ │ ├── style.less │ │ └── sub │ │ │ ├── bar.less │ │ │ └── baz.less │ │ └── index.js ├── postcss │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── bar.scss │ │ ├── foo.css │ │ ├── sub1 │ │ │ └── .postcssrc │ │ ├── sub2 │ │ │ └── package.json │ │ ├── sub3 │ │ │ └── postcss.config.js │ │ ├── sub4 │ │ │ └── .postcssrc.js │ │ └── sub5 │ │ │ └── .postcssrc │ │ └── index.js ├── prettier │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ └── foo.js │ │ └── index.js ├── rev │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── a.js │ │ ├── b.svg │ │ └── sub │ │ │ └── c.js │ │ └── index.js ├── sass │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── _a.sass │ │ ├── style.sass │ │ └── sub │ │ │ ├── _b.scss │ │ │ └── _c.scss │ │ └── index.js ├── shell │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── bar.js │ │ ├── baz.js │ │ └── foo.js │ │ └── index.js ├── stylus │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── expect.css │ │ ├── foo.styl │ │ ├── style.styl │ │ └── sub │ │ │ ├── bar.styl │ │ │ └── baz.styl │ │ └── index.js ├── taskr │ ├── cli.js │ ├── lib │ │ ├── boot.js │ │ ├── cli │ │ │ ├── help.js │ │ │ ├── index.js │ │ │ ├── list.js │ │ │ ├── options.js │ │ │ └── spawn.js │ │ ├── fmt.js │ │ ├── fn.js │ │ ├── plugins.js │ │ ├── reporter.js │ │ ├── task.js │ │ ├── taskr.js │ │ ├── utils │ │ │ ├── expand.js │ │ │ ├── find.js │ │ │ ├── index.js │ │ │ ├── logging.js │ │ │ ├── read.js │ │ │ ├── trace.js │ │ │ └── write.js │ │ └── wrapp.js │ ├── package.json │ ├── readme.md │ ├── taskr.d.ts │ └── test │ │ ├── cli.js │ │ ├── fixtures │ │ ├── alt │ │ │ ├── .gitignore │ │ │ ├── local-plugin.js │ │ │ ├── node_modules │ │ │ │ ├── fly-plugin1 │ │ │ │ │ └── index.js │ │ │ │ └── taskr-plugin-2 │ │ │ │ │ └── index.js │ │ │ ├── package.json │ │ │ ├── sub │ │ │ │ └── package.json │ │ │ └── taskfile.js │ │ ├── bar.txt │ │ ├── foo.txt │ │ ├── foo.txt.map │ │ ├── one │ │ │ ├── one.md │ │ │ └── two │ │ │ │ ├── two-1.md │ │ │ │ └── two-2.md │ │ ├── taskfile.js │ │ └── utils │ │ │ ├── a.js │ │ │ ├── b.js │ │ │ ├── sample.babel.js │ │ │ ├── sub │ │ │ └── .gitkeep │ │ │ ├── taskfile.js │ │ │ └── z.html │ │ ├── fly.js │ │ ├── fn.js │ │ ├── helpers │ │ └── index.js │ │ ├── plugins.js │ │ ├── reporter.js │ │ ├── task.js │ │ ├── utils.js │ │ └── wrapp.js ├── typescript │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ └── app.ts │ │ └── index.js ├── uglify │ ├── index.js │ ├── next.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── a.js │ │ └── sub │ │ │ └── b.js │ │ ├── index.js │ │ └── next.js ├── unflow │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ ├── bar.js │ │ └── foo.js │ │ └── index.js ├── watch │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ │ ├── fixtures │ │ └── foo.js │ │ └── index.js └── zip │ ├── index.js │ ├── package.json │ ├── readme.md │ └── test │ ├── fixtures │ ├── bat.baz │ └── foo.baz │ └── index.js └── readme.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.{json,yml,md}] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | coverage 4 | *.lock 5 | *.log 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 7 5 | - 6 6 | - 4 7 | 8 | git: 9 | depth: 1 10 | 11 | branches: 12 | only: 13 | - master 14 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: "7" 4 | - nodejs_version: "6" 5 | - nodejs_version: "4" 6 | 7 | max_jobs: 4 8 | clone_depth: 1 9 | branches: 10 | only: 11 | - master 12 | 13 | version: "{build}" 14 | 15 | install: 16 | - ps: Install-Product node $env:nodejs_version 17 | - IF %nodejs_version% LSS 4 npm -g install npm@2 18 | - set PATH=%APPDATA%\npm;%PATH% 19 | - npm install 20 | 21 | platform: 22 | - x86 23 | - x64 24 | 25 | matrix: 26 | fast_finish: true 27 | 28 | build: off 29 | 30 | test_script: 31 | - node --version 32 | - npm --version 33 | - npm test 34 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.1.2", 3 | "lerna": "2.0.0-rc.5", 4 | "packages": [ 5 | "packages/*" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jorge Bucaran (https://github.com/JorgeBucaran) 4 | Copyright (c) 2016 Luke Edwards (https://github.com/lukeed) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "repository": "lukeed/taskr", 4 | "homepage": "https://github.com/lukeed/taskr", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Luke Edwards", 8 | "email": "luke@lukeed.com", 9 | "url": "https://lukeed.com" 10 | }, 11 | "scripts": { 12 | "pretest": "lerna bootstrap", 13 | "test": "lerna run test" 14 | }, 15 | "devDependencies": { 16 | "lerna": "^2.0.0-rc.5", 17 | "tap-spec": "^4.1.1", 18 | "tape": "^4.6.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/babel/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const transform = require('babel-core').transform; 4 | const readPkg = require('read-pkg-up'); 5 | const flatten = require('flatten'); 6 | 7 | const BABEL_REGEX = /(^babel-)(preset|plugin)-(.*)/i; 8 | 9 | function getBabels() { 10 | const pkg = readPkg.sync().pkg; 11 | return flatten( 12 | ['devDependencies', 'dependencies'].map(s => Object.keys(pkg[s] || {})) 13 | ).filter(s => BABEL_REGEX.test(s)); 14 | } 15 | 16 | module.exports = function (task) { 17 | let cache; 18 | 19 | task.plugin('babel', {}, function * (file, opts) { 20 | if (opts.preload) { 21 | delete opts.preload; 22 | // get dependencies 23 | cache = cache || getBabels(); 24 | 25 | // attach any deps to babel's `opts` 26 | cache.forEach(dep => { 27 | const segs = BABEL_REGEX.exec(dep); 28 | const type = `${segs[2]}s`; 29 | const name = segs[3]; 30 | 31 | opts[type] = opts[type] || []; 32 | 33 | // flatten all (advanced entries are arrays) 34 | if (flatten(opts[type]).indexOf(name) === -1) { 35 | opts[type] = opts[type].concat(name); 36 | } 37 | }); 38 | } 39 | 40 | // attach file's name 41 | opts.filename = file.base; 42 | 43 | const output = transform(file.data, opts); 44 | 45 | if (output.map) { 46 | const map = `${file.base}.map`; 47 | 48 | // append `sourceMappingURL` to original file 49 | if (opts.sourceMaps !== 'both') { 50 | output.code += new Buffer(`\n//# sourceMappingURL=${map}`); 51 | } 52 | 53 | // add sourcemap to `files` array 54 | this._.files.push({ 55 | base: map, 56 | dir: file.dir, 57 | data: new Buffer(JSON.stringify(output.map)) 58 | }); 59 | } 60 | 61 | // update file's data 62 | file.data = new Buffer(output.code); 63 | }); 64 | }; 65 | -------------------------------------------------------------------------------- /packages/babel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/babel", 3 | "version": "1.1.0", 4 | "description": "Babel plugin for Taskr", 5 | "repository": "lukeed/taskr", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "scripts": { 12 | "test": "tape test/*.js | tap-spec" 13 | }, 14 | "author": { 15 | "name": "Luke Edwards", 16 | "email": "luke@lukeed.com", 17 | "url": "https://lukeed.com" 18 | }, 19 | "contributors": [ 20 | { 21 | "name": "Oleh Kuchuk", 22 | "email": "kuchuklehjs@gmail.com", 23 | "url": "https://github.com/hzlmn" 24 | } 25 | ], 26 | "dependencies": { 27 | "babel-core": "^6.3.0", 28 | "flatten": "^1.0.2", 29 | "read-pkg-up": "^2.0.0" 30 | }, 31 | "devDependencies": { 32 | "@taskr/clear": "^1.1.0", 33 | "babel-preset-es2015": "^6.3.0", 34 | "taskr": "^1.1.0" 35 | }, 36 | "engines": { 37 | "node": ">= 4.6" 38 | }, 39 | "keywords": [ 40 | "taskr", 41 | "taskr-plugin", 42 | "babel", 43 | "es6", 44 | "compile", 45 | "esnext", 46 | "transpile", 47 | "6to5", 48 | "harmony", 49 | "ES.next", 50 | "ecmascript" 51 | ], 52 | "publishConfig": { 53 | "access": "public" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/babel/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/babel [![npm](https://img.shields.io/npm/v/@taskr/babel.svg)](https://npmjs.org/package/@taskr/babel) 2 | 3 | > Babel plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/babel 9 | ``` 10 | 11 | ## API 12 | 13 | ### .babel(options) 14 | 15 | All Babel options can be found [here](http://babeljs.io/docs/usage/options/). 16 | 17 | > **Note:** For most cases, you only to think about `presets`, `plugins`, `sourceMaps`, `minified`, `comments`, and/or `babelrc`. 18 | 19 | #### options.preload 20 | 21 | Type: `boolean`
22 | Default: `false` 23 | 24 | Automatically loads all babel-related plugins & presets from `package.json`. Will also auto-configure Babel to use these packages. See the [example](#preloading) for more. 25 | 26 | ## Usage 27 | 28 | #### Basic 29 | 30 | ```js 31 | exports.scripts = function * (task) { 32 | yield task.source('src/**/*.js') 33 | .babel({ 34 | presets: ['es2015'] 35 | }) 36 | .target('dist/js') 37 | } 38 | ``` 39 | 40 | #### Source Maps 41 | 42 | You can create source maps for each file. 43 | 44 | Passing `true` will create an _external_ `.map` file. You may also use `'inline'` or `'both'`. Please see the [Babel options](http://babeljs.io/docs/usage/options/) for more information. 45 | 46 | ```js 47 | exports.scripts = function * (task) { 48 | yield task.source('src/**/*.js') 49 | .babel({ 50 | presets: ['es2015'], 51 | sourceMaps: true //=> external; also 'inline' or 'both' 52 | }) 53 | .target('dist/js') 54 | } 55 | ``` 56 | 57 | #### Preloading 58 | 59 | For the especially lazy, you may "preload" all babel-related presets **and** plugins defined within your `package.json`. This spares you the need to define your `presets` and `plugins` values manually. 60 | 61 | > **Note:** If you require a [complex configuration](http://babeljs.io/docs/plugins/#pluginpresets-options), you need to define that manually. While other plugins & presets will continue to "preload", your manual definitions will not be lost. 62 | 63 | ```js 64 | exports.scripts = function * (task) { 65 | yield task.source('src/**/*.js') 66 | .babel({ 67 | preload: true, 68 | plugins: [ 69 | // complex plugin definition: 70 | ['transform-async-to-module-method', { 71 | 'module': 'bluebird', 72 | 'method': 'coroutine' 73 | }] 74 | ] 75 | }) 76 | .target('dist'); 77 | //=> after preloading: 78 | //=> { 79 | //=> presets: ['es2015'], 80 | //=> plugins: [ 81 | //=> 'transform-class-properties', 82 | //=> ['transform-async-to-module-method', {...}] 83 | //=> ] 84 | //=> } 85 | } 86 | ``` 87 | 88 | ## Support 89 | 90 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 91 | 92 | Please be sure to specify that you are using `@taskr/babel`. 93 | 94 | ## License 95 | 96 | MIT © [Luke Edwards](https://lukeed.com) 97 | -------------------------------------------------------------------------------- /packages/babel/test/fixtures/a.js: -------------------------------------------------------------------------------- 1 | export let a = 0 2 | -------------------------------------------------------------------------------- /packages/babel/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const dir = join(__dirname, 'fixtures'); 8 | const tmp = join(__dirname, '.tmp'); 9 | 10 | test('@taskr/babel', t => { 11 | t.plan(16); 12 | 13 | const src = `${dir}/a.js`; 14 | const want = '"use strict";\n\nObject.defineProperty(exports, "__esModule"'; 15 | 16 | const taskr = new Taskr({ 17 | plugins: [ 18 | require('../'), 19 | require('@taskr/clear') 20 | ], 21 | tasks: { 22 | * a(f) { 23 | t.ok('babel' in taskr.plugins, 'add the `babel` plugin'); 24 | 25 | yield f.source(src).babel({presets: ['es2015']}).target(tmp); 26 | 27 | const arr = yield f.$.expand(`${tmp}/*`); 28 | const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 29 | t.ok(str.length, 'via `presets`: write new file'); 30 | t.equal(arr.length, 1, 'via `presets`: exclude sourcemaps by default'); 31 | t.true(str.includes(want), 'via `presets`: transpile to es5 code'); 32 | 33 | yield f.clear(tmp); 34 | }, 35 | * b(f) { 36 | yield f.source(src).babel({preload: true}).target(tmp); 37 | 38 | const arr = yield f.$.expand(`${tmp}/*`); 39 | const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 40 | t.equal(arr.length, 1, 'via `preload`: exclude sourcemaps by default'); 41 | t.true(str.includes(want), 'via `preload`: transpile to es5 code'); 42 | 43 | yield f.clear(tmp); 44 | }, 45 | * c(f) { 46 | yield f.source(`${dir}/*.js`).babel({presets: ['es2015'], sourceMaps: true}).target(tmp); 47 | 48 | const arr = yield f.$.expand(`${tmp}/*`); 49 | const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 50 | t.equal(arr.length, 2, 'via `sourceMaps: true`; create file & external sourcemap'); 51 | t.true(/var a/.test(str), 'via `sourceMaps: true`; transpile to es5 code'); 52 | t.true(/sourceMappingURL/.test(str), 'via `sourceMaps: true`; append `sourceMappingURL` link'); 53 | 54 | yield f.clear(tmp); 55 | }, 56 | * d(f) { 57 | yield f.source(`${dir}/*.js`).babel({presets: ['es2015'], sourceMaps: 'inline'}).target(tmp); 58 | 59 | const arr = yield f.$.expand(`${tmp}/*`); 60 | const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 61 | t.ok(/var a/.test(str), 'via `sourceMaps: "inline"`; transpile to es5 code'); 62 | t.equal(arr.length, 1, 'via `sourceMaps: "inline"`; do not create external sourcemap file'); 63 | t.ok(/sourceMappingURL/.test(str), 'via `sourceMaps: "inline"`; embed `sourceMappingURL` content'); 64 | 65 | yield f.clear(tmp); 66 | }, 67 | * e(f) { 68 | yield f.source(`${dir}/*.js`).babel({presets: ['es2015'], sourceMaps: 'both'}).target(tmp); 69 | 70 | const arr = yield f.$.expand(`${tmp}/*`); 71 | const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 72 | t.ok(/var a/.test(str), 'via `sourceMaps: "both"`; transpile to es5 code'); 73 | t.equal(arr.length, 2, 'via `sourceMaps: "both"`; create external sourcemap file'); 74 | t.ok(/sourceMappingURL/.test(str), 'via `sourceMaps: "both"`; embed `sourceMappingURL` content'); 75 | 76 | yield f.clear(tmp); 77 | }, 78 | * f(f) { 79 | yield f.source(`${dir}/*.js`).babel({ 80 | preload: true, 81 | presets: [['es2015', {modules: 'systemjs'}]] 82 | }).target(tmp); 83 | 84 | const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 85 | t.true(str.includes('System.register'), 'via `preload` + `presets`; keep detailed `presets` entry'); 86 | 87 | yield f.clear(tmp); 88 | } 89 | } 90 | }); 91 | 92 | taskr.serial(['a', 'b', 'c', 'd', 'e', 'f']); 93 | }); 94 | -------------------------------------------------------------------------------- /packages/browserify/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const browserify = require('browserify'); 5 | 6 | const NAME = '@taskr/browserify'; 7 | const toArr = val => Array.isArray(val) ? val : (val == null) ? [] : [val]; 8 | 9 | function setError(ctx, msg) { 10 | const error = msg.replace(ctx.root, '') 11 | .replace(': ', ': \n\n ') 12 | .replace(' while parsing', '\n\nwhile parsing').concat('\n'); 13 | 14 | ctx.emit('plugin_error', { plugin:NAME, error }); 15 | return new Buffer(`console.error('${NAME}: Bundle error! Check CLI output.');`); 16 | } 17 | 18 | module.exports = function (task) { 19 | task.plugin('browserify', { every:false }, function * (files, opts) { 20 | opts = opts || {}; 21 | 22 | if (opts.entries) { 23 | files = toArr(opts.entries).map(p.parse); 24 | delete opts.entries; 25 | } 26 | 27 | // init bundler 28 | const b = browserify(); 29 | 30 | // apply transforms 31 | for (const t of opts.transform || []) { 32 | b.transform.apply(b, toArr(t)); 33 | } 34 | 35 | delete opts.transform; 36 | 37 | const bundle = obj => new Promise((res, rej) => { 38 | b.add(p.format(obj), opts); 39 | b.bundle((err, buf) => err ? rej(err) : res(buf)); 40 | }); 41 | 42 | // @todo: check for source maps? 43 | for (const file of files) { 44 | try { 45 | file.data = yield bundle(file); 46 | } catch (err) { 47 | file.data = setError(task, err.message); 48 | } 49 | 50 | b.reset(); 51 | } 52 | 53 | // replace `task._.files` 54 | this._.files = files; 55 | }); 56 | }; 57 | -------------------------------------------------------------------------------- /packages/browserify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/browserify", 3 | "version": "1.1.0", 4 | "description": "Browserify plugin for Taskr.", 5 | "repository": "lukeed/taskr", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "browserify" 15 | ], 16 | "scripts": { 17 | "test": "tape test/*.js | tap-spec" 18 | }, 19 | "author": { 20 | "name": "Luke Edwards", 21 | "email": "luke.edwards05@gmail.com", 22 | "url": "https://lukeed.com" 23 | }, 24 | "dependencies": { 25 | "browserify": "^14.4.0" 26 | }, 27 | "devDependencies": { 28 | "@taskr/clear": "^1.1.0", 29 | "babel-preset-es2015": "^6.18.0", 30 | "babelify": "^7.3.0", 31 | "taskr": "^1.1.0" 32 | }, 33 | "engines": { 34 | "node": ">= 4.6.0" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/browserify/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/browserify [![npm](https://img.shields.io/npm/v/@taskr/browserify.svg)](https://npmjs.org/package/@taskr/browserify) 2 | 3 | > [Browserify](http://browserify.org/) plugin for [Taskr](https://github.com/lukeed/taskr) 4 | 5 | ## Install 6 | 7 | ```sh 8 | $ npm install --save-dev @taskr/browserify 9 | ``` 10 | 11 | ## API 12 | 13 | ### .browserify(options) 14 | 15 | Please see [Browserify's documentation](https://github.com/substack/node-browserify#browserifyfiles--opts) for a full list of available options. 16 | 17 | #### options.entries 18 | 19 | Type: `string` or `array`
20 | Default: `''` 21 | 22 | Define "entry" files, which represent new bundles. _Optional._ See an [example usage](#direct-paths-via-optsentries). 23 | 24 | > **Note:** If not specified, `@taskr/browserify` will assumes **all** files within `task.source()` are new bundle entries. 25 | 26 | > **Important:** This plugin (`@taskr/browserify`) enforces **new a bundle per entry** unlike `browserify`. 27 | 28 | Using this option is particularly handy when your task (eg, `scripts`) contains plugin methods whose source files should be more than your entry files. 29 | 30 | ```js 31 | exports.scripts = function * (task) { 32 | yield task.source('src/scripts/app.js') 33 | .xo() // ONLY lints one file 34 | .browserify() // make 'app.js' bundle 35 | .target('dist/js'); //=> dist/js/app.js 36 | 37 | /* VS */ 38 | 39 | yield task.source('src/**/*.js') 40 | .xo() // lints ALL files 41 | .browserify({ 42 | entries: 'src/scripts/app.js' 43 | }) // make 'app.js' bundle 44 | .target('dist/js'); //=> dist/js/app.js 45 | } 46 | ``` 47 | 48 | ## Usage 49 | 50 | ### Basic 51 | 52 | ```js 53 | exports.default = function * (task) { 54 | yield task.source('src/scripts/app.js') 55 | .browserify() 56 | .target('dist'); 57 | }; 58 | ``` 59 | 60 | ### Transforms 61 | 62 | There's a huge list of [browserify transforms](https://github.com/substack/node-browserify/wiki/list-of-transforms) available to you. You may `require()` any of them & include their functionalities in your bundles. 63 | 64 | ```js 65 | exports.default = function * (task) { 66 | yield task.source('src/scripts/app.js') 67 | .browserify({ 68 | transform: [require('reactify')] 69 | }) 70 | .target('dist'); 71 | }; 72 | ``` 73 | 74 | ### Multiple Bundles 75 | 76 | There are a handful of ways you can create multiple `browserify` "bundles" without the need to repeat your task. 77 | 78 | #### Direct Paths via `task.source()` 79 | 80 | ```js 81 | exports.default = function * (task) { 82 | yield task.source([ 83 | 'src/scripts/app.js', 84 | 'src/scripts/admin.js' 85 | ]) 86 | .browserify() 87 | .target('dist'); 88 | } 89 | ``` 90 | 91 | #### Glob Patterns via `task.source()` 92 | 93 | ```js 94 | exports.default = function * (task) { 95 | yield task.source('src/entries/*.js') 96 | .browserify() 97 | .target('dist'); 98 | } 99 | ``` 100 | 101 | #### Direct Paths via `opts.entries` 102 | 103 | ```js 104 | exports.default = function * (task) { 105 | yield task.source('src/**/*.js') 106 | .browserify({ 107 | entries: [ 108 | 'src/scripts/app.js', 109 | 'src/scripts/admin.js' 110 | ] 111 | }) 112 | .target('dist'); 113 | } 114 | ``` 115 | 116 | ## Support 117 | 118 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 119 | 120 | Please be sure to specify that you are using `@taskr/browserify`. 121 | 122 | ## License 123 | 124 | MIT © [Luke Edwards](https://lukeed.com) 125 | -------------------------------------------------------------------------------- /packages/browserify/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | var sub = require('./sub'); 2 | 3 | console.log('this is foo.js'); 4 | 5 | sub(); 6 | -------------------------------------------------------------------------------- /packages/browserify/test/fixtures/sub/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = 14; 2 | -------------------------------------------------------------------------------- /packages/browserify/test/fixtures/sub/baz.js: -------------------------------------------------------------------------------- 1 | const obj = {hello: 'world'}; 2 | const {hello} = obj; 3 | let it = 'work'; 4 | -------------------------------------------------------------------------------- /packages/browserify/test/fixtures/sub/index.js: -------------------------------------------------------------------------------- 1 | var bar = require('./bar'); 2 | 3 | module.exports = function () { 4 | console.log('hello, this is sub-index', bar); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/browserify/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const dir = join(__dirname, 'fixtures'); 8 | const tmp = join(__dirname, 'tmp'); 9 | 10 | test('@taskr/browserify', t => { 11 | t.plan(13); 12 | 13 | const taskr = new Taskr({ 14 | plugins: [ 15 | require('../'), 16 | require('@taskr/clear') 17 | ], 18 | tasks: { 19 | a: function * (f) { 20 | const all = `${dir}/**/*.js`; 21 | const chk = '(function e(t,n,r){'; 22 | 23 | const read = a => f.$.read(`${tmp}/${a}`, 'utf8'); 24 | const open = () => f.$.expand(`${tmp}/**/*.js`); 25 | 26 | t.true('browserify' in taskr.plugins, 'attach `browserify()` plugin to taskr'); 27 | 28 | yield f.source(all).browserify().target(tmp); 29 | const arr1 = yield open(); 30 | const str1 = yield read('foo.js'); 31 | t.equal(arr1.length, 4, 'loop thru all `source` files by default'); 32 | t.true(str1.indexOf(chk) !== -1, 'bundle each file by default'); 33 | yield f.clear(tmp); 34 | 35 | yield f.source(`${dir}/foo.js`).browserify().target(tmp); 36 | const arr2 = yield open(); 37 | const str2 = yield read('foo.js'); 38 | t.equal(arr2.length, 1, 'use `source` files by default'); 39 | t.true(str2.indexOf(chk) !== -1, 'bundle file contents by default'); 40 | yield f.clear(tmp); 41 | 42 | yield f.source(`${dir}/*.js`).browserify().target(tmp); 43 | const arr3 = yield open(); 44 | const str3 = yield read('foo.js'); 45 | t.equal(arr3.length, 1, 'accept `source` globs'); 46 | t.true(str3.indexOf(chk) !== -1, 'bundle file conents'); 47 | yield f.clear(tmp); 48 | 49 | yield f.source(all).browserify({entries: `${dir}/sub/index.js`}).target(tmp); 50 | const arr4 = yield open(); 51 | const str4 = yield read('sub/index.js'); 52 | t.equal(arr4.length, 1, 'prefer `opts.entries` over `source` value; single (string)'); 53 | t.true(str4.indexOf(chk) !== -1, 'bundle file contents'); 54 | yield f.clear(tmp); 55 | 56 | yield f.source(all).browserify({ 57 | entries: [`${dir}/foo.js`, `${dir}/sub/index.js`] 58 | }).target(tmp); 59 | const arr5 = yield open(); 60 | const str5 = yield read('foo.js'); 61 | t.equal(arr5.length, 2, 'prefer `opts.entries` over `source` value; multiple (array)'); 62 | t.true(str5.indexOf(chk) !== -1, 'bundle each file'); 63 | yield f.clear(tmp); 64 | 65 | const opt = {presets: ['es2015']}; 66 | const es5 = `var obj = { hello: 'world' };`; 67 | 68 | yield f.source(`${dir}/sub/baz.js`).browserify({ 69 | transform: [require('babelify').configure(opt)] 70 | }).target(tmp); 71 | const str6 = yield read('baz.js'); 72 | t.true(str6.indexOf(es5) !== -1, 'apply `opts.transform` using `require()`'); 73 | yield f.clear(tmp); 74 | 75 | yield f.source(`${dir}/sub/baz.js`).browserify({ 76 | transform: [['babelify', opt]] 77 | }).target(tmp); 78 | const str7 = yield read('baz.js'); 79 | t.true(str7.indexOf(es5) !== -1, 'apply `opts.transform` using `array`'); 80 | yield f.clear(tmp); 81 | } 82 | } 83 | }); 84 | 85 | taskr.start('a'); 86 | }); 87 | -------------------------------------------------------------------------------- /packages/buble/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const transform = require('buble').transform; 5 | 6 | const relPath = obj => p.relative(obj.dir, p.format(obj)); 7 | 8 | module.exports = function (task) { 9 | task.plugin('buble', {}, function * (file, opts) { 10 | opts = Object.assign({ 11 | inline: false, 12 | sourceMap: true, 13 | file: file.base, 14 | source: relPath(file) 15 | }, opts); 16 | 17 | // Transform data 18 | const output = transform(file.data.toString(), opts); 19 | 20 | // Handle sourcemaps 21 | if (opts.sourceMap) { 22 | if (opts.inline) { 23 | // Append inline sourcemap 24 | output.code += `\n//# sourceMappingURL=${output.map.toUrl()}`; 25 | } else { 26 | output.code += `\n//# sourceMappingURL=${opts.file}.map`; 27 | // Create new file 28 | this._.files.push({ 29 | base: `${opts.file}.map`, 30 | data: output.map.toString(), 31 | dir: file.dir 32 | }); 33 | } 34 | } 35 | 36 | // doc: Return contents as Buffer! 37 | file.data = new Buffer(output.code); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /packages/buble/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/buble", 3 | "version": "1.1.0", 4 | "description": "Bublé plugin for Taskr.", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "buble" 15 | ], 16 | "scripts": { 17 | "test": "tape test/*.js | tap-spec" 18 | }, 19 | "author": { 20 | "name": "Luke Edwards", 21 | "email": "luke@lukeed.com", 22 | "url": "https://lukeed.com" 23 | }, 24 | "dependencies": { 25 | "buble": "^0.15.2" 26 | }, 27 | "devDependencies": { 28 | "@taskr/clear": "^1.1.0", 29 | "taskr": "^1.1.0" 30 | }, 31 | "engines": { 32 | "node": ">= 4.6" 33 | }, 34 | "publishConfig": { 35 | "access": "public" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/buble/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/buble [![npm](https://img.shields.io/npm/v/@taskr/buble.svg)](https://npmjs.org/package/@taskr/buble) 2 | 3 | > [Bublé](https://buble.surge.sh/guide/) plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/buble 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | exports.scripts = function * (task) { 15 | yield task.source('test/**/*.js').buble({ 16 | inline: true, 17 | transforms: { 18 | arrow: true, 19 | modules: false, 20 | dangerousForOf: true 21 | } 22 | }).target('dist/js'); 23 | } 24 | ``` 25 | 26 | ## API 27 | 28 | ### .buble(options) 29 | 30 | To view all Bublé options, visit its [documentation](https://buble.surge.sh/guide/#using-the-javascript-api). 31 | 32 | This plugin includes two additional options: 33 | 34 | #### options.inline 35 | Type: `Boolean`
36 | Default: `false`
37 | If `true`, will append an internal sourcemap (data URI) to the file's contents **instead of** an external link (default). Also will not create a new `*.js.map` file. Requires that `options.sourceMap` to remain `true`. 38 | 39 | #### options.sourceMap 40 | Type: `Boolean`
41 | Default: `true`
42 | Creates an external sourcemap by default. Disable _all_ mapping behavior by setting this to `false`. 43 | 44 | 45 | ## Support 46 | 47 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 48 | 49 | Please be sure to specify that you are using `@taskr/buble`. 50 | 51 | ## License 52 | 53 | MIT © [Luke Edwards](https://lukeed.com) 54 | -------------------------------------------------------------------------------- /packages/buble/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | let a = 0 2 | -------------------------------------------------------------------------------- /packages/buble/test/index.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const Taskr = require('taskr'); 3 | const test = require('tape'); 4 | 5 | const plugins = [require('../'), require('@taskr/clear')]; 6 | const dir = join(__dirname, 'fixtures'); 7 | 8 | const tmpDir = str => join(__dirname, str); 9 | const create = tasks => new Taskr({ tasks, plugins }); 10 | 11 | test('@taskr/buble (defaults)', t => { 12 | t.plan(10); 13 | 14 | const taskr = create({ 15 | * foo(f) { 16 | const tmp = tmpDir('tmp-1'); 17 | t.true('buble' in f, 'access to `buble()` plugin within task'); 18 | yield f.source(`${dir}/foo.js`).buble().target(tmp); 19 | 20 | const arr = yield f.$.expand(`${tmp}/*`); 21 | t.equal(arr.length, 2, 'creates two files'); 22 | 23 | const out = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 24 | t.ok(out, 'retains the output filename'); 25 | t.true(out.indexOf('sourceMappingURL=foo.js.map') !== -1, 'appends sourceMappingURL to file'); 26 | t.true(/var a/.test(out), 'compiles to ES5 code'); 27 | 28 | const map = yield f.$.read(`${tmp}/foo.js.map`, 'utf8'); 29 | t.ok(map, 'creates an external sourcemap file'); 30 | t.true(/"version":3/.test(map), 'stringifies V3 map'); 31 | t.true(/"file":"foo.js"/.test(map), 'points to original filename'); 32 | t.deepEqual(JSON.parse(map).sources, ['foo.js'], 'keeps a sources array'); 33 | 34 | yield f.clear(tmp); 35 | } 36 | }); 37 | 38 | t.true('buble' in taskr.plugins, 'mounts as taskr plugin'); 39 | 40 | taskr.start('foo'); 41 | }); 42 | 43 | test('@taskr/buble (sourcemap options)', t => { 44 | t.plan(5); 45 | create({ 46 | * foo(f) { 47 | const tmp = tmpDir('tmp-2'); 48 | yield f.source(`${dir}/foo.js`).buble({file: 'bar.js', source: 'foo/bar.js'}).target(tmp); 49 | 50 | const arr = yield f.$.expand(`${tmp}/*`); 51 | t.equal(arr.length, 2, 'creates two files'); 52 | 53 | const out = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 54 | t.ok(out.indexOf('sourceMappingURL=bar.js.map') !== -1, 'points to custom `options.file` name'); 55 | 56 | const map = yield f.$.read(`${tmp}/bar.js.map`, 'utf8'); 57 | t.ok(map, 'creates a file with custom `options.file` name'); 58 | const obj = JSON.parse(map); 59 | t.equal(obj.file, 'bar.js', 'keeps custom `options.file` name'); 60 | t.equal(obj.sources[0], 'foo/bar.js', 'keeps custom `options.source` value'); 61 | 62 | yield f.clear(tmp); 63 | } 64 | }).start('foo'); 65 | }); 66 | 67 | test('@taskr/buble (no sourcemap)', t => { 68 | t.plan(2); 69 | create({ 70 | * foo(f) { 71 | const tmp = tmpDir('tmp-3'); 72 | yield f.source(`${dir}/foo.js`).buble({sourceMap: false}).target(tmp); 73 | 74 | const arr = yield f.$.expand(tmp); 75 | t.equal(arr.length, 1, 'creates only one file'); 76 | 77 | const out = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 78 | t.equal(out.indexOf('sourceMappingURL=foo.js.map'), -1, 'does not append a sourceMappingURL'); 79 | 80 | yield f.clear(tmp); 81 | } 82 | }).start('foo'); 83 | }); 84 | 85 | test('@taskr/buble (inline)', t => { 86 | t.plan(3); 87 | create({ 88 | * foo(f) { 89 | const tmp = tmpDir('tmp-4'); 90 | yield f.source(`${dir}/foo.js`).buble({inline: true}).target(tmp); 91 | 92 | const arr = yield f.$.expand(tmp); 93 | t.equal(arr.length, 1, 'creates only one file'); 94 | 95 | const out = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 96 | t.equal(out.indexOf('sourceMappingURL=foo.js.map'), -1, 'does not append external sourceMappingURL'); 97 | t.ok(out.indexOf('sourceMappingURL=data:application/json;charset=utf-8;base64'), 'appends data URI instead'); 98 | 99 | yield f.clear(tmp); 100 | } 101 | }).start('foo'); 102 | }); 103 | -------------------------------------------------------------------------------- /packages/clear/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Promise = require('bluebird'); 4 | const del = Promise.promisify(require('rimraf')); 5 | 6 | const toArr = val => Array.isArray(val) ? val : (val == null) ? [] : [val]; 7 | 8 | module.exports = function (task) { 9 | task.plugin('clear', { every:false, files:false }, function * (_, globs, opts) { 10 | opts = opts || {}; 11 | yield Promise.all(toArr(globs).map(g => del(g, opts))); 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/clear/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/clear", 3 | "version": "1.1.0", 4 | "description": "Remove one or multiple directories", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Luke Edwards", 9 | "email": "luke.edwards05@gmail.com", 10 | "url": "https://lukeed.com" 11 | }, 12 | "engines": { 13 | "node": ">=4.6" 14 | }, 15 | "scripts": { 16 | "test": "tape test/*.js | tap-spec" 17 | }, 18 | "files": [ 19 | "index.js" 20 | ], 21 | "keywords": [ 22 | "taskr", 23 | "taskr-plugin", 24 | "clear", 25 | "del", 26 | "delete", 27 | "rimraf", 28 | "remove" 29 | ], 30 | "dependencies": { 31 | "bluebird": "^3.5.0", 32 | "rimraf": "^2.5.4" 33 | }, 34 | "devDependencies": { 35 | "taskr": "^1.1.0" 36 | }, 37 | "publishConfig": { 38 | "access": "public" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/clear/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/clear [![npm](https://img.shields.io/npm/v/@taskr/clear.svg)](https://npmjs.org/package/@taskr/clear) 2 | 3 | > Remove one or multiple directories 4 | 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install --save-dev @taskr/clear 10 | ``` 11 | 12 | 13 | ## Usage 14 | 15 | ```js 16 | exports.cleanup = function * (task) { 17 | // single file 18 | yield task.clear('foo.js'); 19 | 20 | // single directory 21 | yield task.clear('dist'); 22 | 23 | // multiple directories 24 | yield task.clear(['dist', 'build']); 25 | 26 | // glob pattern(s) 27 | yield task.clear(['dist/*.css', 'dist/js/*']); 28 | 29 | // mixed 30 | yield task.clear(['foo.js', 'build', 'dist/*.css']); 31 | 32 | // with options 33 | yield task.clear('dist', {maxBusyTries: 5}); 34 | } 35 | ``` 36 | 37 | 38 | ## API 39 | 40 | ### task.clear(files, [options]) 41 | 42 | #### files 43 | 44 | Type: `string` or `array` 45 | 46 | A filepath, directory path, or glob pattern. For multiple paths, use an `array`. 47 | 48 | 49 | #### options 50 | 51 | Type: `object`
52 | Default: `{}` 53 | 54 | All options are passed directly to `rimraf`. Please see its [documentation on options](https://github.com/isaacs/rimraf#options). 55 | 56 | 57 | ## Support 58 | 59 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 60 | 61 | Please be sure to specify that you are using `@taskr/clear`. 62 | 63 | ## License 64 | 65 | MIT © [Luke Edwards](https://lukeed.com) 66 | -------------------------------------------------------------------------------- /packages/clear/test/index.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const exists = require('fs').existsSync; 3 | const co = require('bluebird').coroutine; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | const fn = require('../'); 7 | 8 | const dir1 = join(__dirname, 'tmp1'); 9 | const dir2 = join(__dirname, 'tmp2'); 10 | const plugins = [require('../')]; 11 | 12 | const create = tasks => new Taskr({ tasks, plugins }); 13 | 14 | test('@taskr/clear: filepath (task)', co(function * (t) { 15 | t.plan(2); 16 | yield create({ 17 | * a(f) { 18 | const src = `${dir1}/foo`; 19 | yield f.$.write(src); 20 | t.true('clear' in f, 'attach `clear` to task instance'); 21 | yield f.clear(src); 22 | t.false(exists(src), 'file was deleted'); 23 | } 24 | }).start('a'); 25 | })); 26 | 27 | test('@taskr/clear: directory', co(function * (t) { 28 | t.plan(1); 29 | yield create({ 30 | * a(f) { 31 | const src = `${dir1}/foo`; 32 | yield f.$.write(src); 33 | yield f.clear(dir1); 34 | t.false(exists(src), 'directory was deleted'); 35 | } 36 | }).start('a'); 37 | })); 38 | 39 | test('@taskr/clear: filepath array', co(function * (t) { 40 | t.plan(2); 41 | yield create({ 42 | * a(f) { 43 | const src1 = `${dir1}/foo`; 44 | const src2 = `${dir1}/bar`; 45 | yield f.$.write(src1); 46 | yield f.$.write(src2); 47 | yield f.clear([src1, src2]); 48 | t.false(exists(src1), 'file1 was deleted'); 49 | t.false(exists(src2), 'file2 was deleted'); 50 | } 51 | }).start('a'); 52 | })); 53 | 54 | test('@taskr/clear: directory array', co(function * (t) { 55 | t.plan(2); 56 | yield create({ 57 | * a(f) { 58 | const src1 = `${dir1}/foo`; 59 | const src2 = `${dir2}/bar`; 60 | yield f.$.write(src1); 61 | yield f.$.write(src2); 62 | yield f.clear([dir1, dir2]); 63 | t.false(exists(src1), 'dir1 was deleted'); 64 | t.false(exists(src2), 'dir2 was deleted'); 65 | } 66 | }).start('a'); 67 | })); 68 | 69 | test('@taskr/clear: directory glob', co(function * (t) { 70 | t.plan(4); 71 | yield create({ 72 | * a(f) { 73 | const src1 = `${dir1}/foo`; 74 | const src2 = `${dir2}/bar/baz`; 75 | const src3 = `${dir2}/bar/bat`; 76 | yield f.$.write(src1); 77 | yield f.$.write(src2); 78 | yield f.$.write(src3); 79 | yield f.clear([dir1, `${dir2}/bar/*`]); 80 | t.false(exists(src1), 'dir1 was deleted'); 81 | t.false(exists(src2), 'dir2/file1 was deleted'); 82 | t.false(exists(src3), 'dir2/file2 was deleted'); 83 | t.true(exists(`${dir2}/bar`), 'dir2/bar still exists'); 84 | yield f.clear(dir2); 85 | } 86 | }).start('a'); 87 | })); 88 | 89 | test('@taskr/clear: with `rimraf` options', co(function * (t) { 90 | t.plan(2); 91 | yield create({ 92 | * a(f) { 93 | const src1 = `${dir1}/bar/baz`; 94 | const src2 = `${dir1}/bar/bat`; 95 | yield f.$.write(src1); 96 | yield f.$.write(src2); 97 | yield f.clear(`${dir1}/bar/*`, {glob: false}); 98 | t.true(exists(src1), 'file1 still exists'); 99 | t.true(exists(src2), 'file2 still exists'); 100 | yield f.clear(dir1); 101 | } 102 | }).start('a'); 103 | })); 104 | -------------------------------------------------------------------------------- /packages/coffee/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const extname = require('path').extname; 4 | const compile = require('coffee-script').compile; 5 | 6 | module.exports = function (task) { 7 | task.plugin('coffee', { every:true }, function * (file, opts) { 8 | opts = opts || {}; 9 | 10 | // modify extension 11 | const ext = extname(file.base); 12 | file.base = file.base.replace(new RegExp(ext, 'i'), '.js'); 13 | 14 | // compile output 15 | const out = compile(file.data.toString(), opts); 16 | 17 | if (opts.sourceMap && out.sourceMap) { 18 | const map = `${file.base}.map`; 19 | // add sourceMapping to file contents 20 | out.js += `//# sourceMappingURL=${map}`; 21 | // add sourcemap to `files` array 22 | this._.files.push({ 23 | base: map, 24 | dir: file.dir, 25 | data: new Buffer(out.v3SourceMap) // <-- already stringified 26 | }); 27 | } 28 | 29 | // update file's data 30 | file.data = new Buffer(out.js || out); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /packages/coffee/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/coffee", 3 | "version": "1.1.0", 4 | "description": "CoffeeScript plugin for Taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "scripts": { 9 | "test": "tape test/*.js | tap-spec" 10 | }, 11 | "author": { 12 | "name": "Luke Edwards", 13 | "email": "luke@lukeed.com", 14 | "url": "https://lukeed.com" 15 | }, 16 | "dependencies": { 17 | "coffee-script": "^1.12.0" 18 | }, 19 | "devDependencies": { 20 | "@taskr/clear": "^1.1.0", 21 | "taskr": "^1.1.0" 22 | }, 23 | "engines": { 24 | "node": ">= 4.6" 25 | }, 26 | "keywords": [ 27 | "taskr", 28 | "taskr-plugin", 29 | "coffee-script", 30 | "coffeescript", 31 | "coffee" 32 | ], 33 | "publishConfig": { 34 | "access": "public" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/coffee/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/coffee [![npm](https://img.shields.io/npm/v/@taskr/coffee.svg)](https://npmjs.org/package/@taskr/coffee) 2 | 3 | > [CoffeeScript](http://coffeescript.org/) plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install --save-dev @taskr/coffee 10 | ``` 11 | 12 | ## Usage 13 | 14 | Check out the [documentation](http://coffeescript.org/#usage) to see the available options. 15 | 16 | ```js 17 | exports.coffee = function * (task) { 18 | yield task.source('src/**/*.coffee').coffee({ 19 | sourceMap: true 20 | }).target('dist/js') 21 | } 22 | ``` 23 | 24 | ## Support 25 | 26 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 27 | 28 | Please be sure to specify that you are using `@taskr/coffee`. 29 | 30 | ## License 31 | 32 | MIT © [Luke Edwards](https://lukeed.com) 33 | -------------------------------------------------------------------------------- /packages/coffee/test/fixtures/bar.coffee: -------------------------------------------------------------------------------- 1 | kids = 2 | brother: 3 | name: "Max" 4 | age: 11 5 | sister: 6 | name: "Ida" 7 | age: 9 8 | -------------------------------------------------------------------------------- /packages/coffee/test/fixtures/foo.coffee: -------------------------------------------------------------------------------- 1 | list = [ 2 | "foo" 3 | "bar" 4 | ] 5 | 6 | foods = ["broccoli", "spinach", "chocolate"] 7 | eat food for food in foods when food isnt "chocolate" 8 | -------------------------------------------------------------------------------- /packages/coffee/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var food, foods, i, len, list; 3 | 4 | list = ["foo", "bar"]; 5 | 6 | foods = ["broccoli", "spinach", "chocolate"]; 7 | 8 | for (i = 0, len = foods.length; i < len; i++) { 9 | food = foods[i]; 10 | if (food !== "chocolate") { 11 | eat(food); 12 | } 13 | } 14 | 15 | }).call(this); 16 | -------------------------------------------------------------------------------- /packages/coffee/test/index.js: -------------------------------------------------------------------------------- 1 | const join = require("path").join; 2 | const Taskr = require("taskr"); 3 | const test = require("tape"); 4 | 5 | const dir = join(__dirname, 'fixtures'); 6 | const tmp = join(__dirname, 'tmp'); 7 | 8 | test('@taskr/coffee', (t) => { 9 | t.plan(6); 10 | 11 | const taskr = new Taskr({ 12 | plugins: [ 13 | require('../'), 14 | require('@taskr/clear') 15 | ], 16 | tasks: { 17 | *foo(f) { 18 | t.ok('coffee' in taskr.plugins, 'attach the `coffee()` plugin to taskr'); 19 | 20 | yield f.source(`${dir}/foo.coffee`).coffee().target(tmp); 21 | 22 | const want = yield f.$.read(`${dir}/foo.js`, 'utf8'); 23 | const sent = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 24 | 25 | t.ok(sent, 'creates a `.js` file'); 26 | t.equal(sent, want, 'compile the `.coffee` contents correctly'); 27 | 28 | yield f.clear(tmp); 29 | }, 30 | *bar(f) { 31 | yield f.source(`${dir}/bar.coffee`).coffee({ sourceMap:true }).target(tmp); 32 | 33 | const map = yield f.$.read(`${tmp}/bar.js.map`); 34 | t.ok(map, 'compiler receives options/config'); 35 | 36 | const arr = yield f.$.expand(`${tmp}/*`); 37 | t.equal(arr.length, 2, 'creates a file and external sourcemap'); 38 | 39 | const str = yield f.$.read(`${tmp}/bar.js`, 'utf8'); 40 | t.ok(/sourceMappingURL/.test(str), 'via `sourceMap`; attach `sourceMappingURL` comment'); 41 | 42 | yield f.clear(tmp); 43 | } 44 | } 45 | }); 46 | 47 | taskr.serial(['foo', 'bar']); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/concat/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const resolve = require('path').resolve; 4 | const Concat = require('concat-with-sourcemaps'); 5 | 6 | const defs = { 7 | sep: '', 8 | map: false, 9 | base: '', 10 | output: null 11 | }; 12 | 13 | module.exports = function (task) { 14 | const notify = (str, obj) => task.emit(`plugin_${str}`, Object.assign(obj, { plugin:'@taskr/concat' })); 15 | const warning = str => notify('warning', { warning:str }); 16 | const error = str => notify('error', { error:str }); 17 | 18 | task.plugin('concat', { every:false }, function * (arr, o) { 19 | if (typeof o === 'string') { 20 | o = { output:o }; 21 | } 22 | 23 | o = Object.assign({}, defs, o); 24 | 25 | if (!o.output) { 26 | return error('Must receive an `output` filename.'); 27 | } 28 | 29 | if (!arr.length) { 30 | return warning('No source files to concatenate!'); 31 | } 32 | 33 | const bundle = new Concat(o.map, o.output, o.sep); 34 | 35 | for (const file of arr) { 36 | bundle.add(file.base, file.data, file.map || file.sourceMap); 37 | } 38 | 39 | // if did not specify a `base`, assume first file's location 40 | const dir = o.base ? resolve(task.root, o.base) : arr[0].dir; 41 | // concat'd content 42 | let data = bundle.content; 43 | 44 | // reset 45 | this._.files = []; 46 | 47 | if (o.map && bundle.sourceMap) { 48 | const mapFile = o.output.concat('.map'); 49 | // add link to sourcemap file 50 | data += new Buffer(`\n//# sourceMappingURL=${mapFile}`); 51 | // add sourcemap file definition 52 | this._.files.push({ 53 | dir: dir, 54 | base: mapFile, 55 | data: bundle.sourceMap 56 | }); 57 | } 58 | 59 | // always add the concat'd file 60 | this._.files.push({ 61 | dir: dir, 62 | base: o.output, 63 | data: data 64 | }); 65 | }); 66 | }; 67 | -------------------------------------------------------------------------------- /packages/concat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/concat", 3 | "version": "1.1.0", 4 | "description": "Concatenate files with optional source maps.", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Luke Edwards", 9 | "email": "luke.edwards05@gmail.com", 10 | "url": "lukeed.com" 11 | }, 12 | "engines": { 13 | "node": ">=4.6" 14 | }, 15 | "scripts": { 16 | "test": "tape test/*.js | tap-spec" 17 | }, 18 | "files": [ 19 | "index.js" 20 | ], 21 | "keywords": [ 22 | "taskr", 23 | "taskr-plugin", 24 | "sourcemap", 25 | "concat" 26 | ], 27 | "dependencies": { 28 | "concat-with-sourcemaps": "^1.0.4" 29 | }, 30 | "devDependencies": { 31 | "@taskr/clear": "^1.1.0", 32 | "taskr": "^1.1.0" 33 | }, 34 | "publishConfig": { 35 | "access": "public" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/concat/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/concat [![npm](https://img.shields.io/npm/v/@taskr/concat.svg)](https://npmjs.org/package/@taskr/concat) 2 | 3 | > Concatenate files with optional source maps. 4 | 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install --save-dev @taskr/concat 10 | ``` 11 | 12 | 13 | ## Usage 14 | 15 | ```js 16 | exports.default = function * (task) { 17 | // concat only; no sourcemap 18 | yield task.source('src/*.js') 19 | .concat('all.js') 20 | .target('dist'); //=> 'dist/all.js' 21 | 22 | // concat with sourcemap 23 | yield task.source('src/*.js') 24 | .concat({ output:'all.js', map:true }) 25 | .target('dist'); //=> 'dist/all.js', 'dist/all.js.map' 26 | 27 | // concat nested source 28 | yield task.source('src/js/*.js') 29 | .concat({ output:'all.js', base:'src' }) 30 | .target('dist'); //=> 'dist/all.js' vs 'dist/js/all.js' 31 | }; 32 | ``` 33 | 34 | 35 | ## API 36 | 37 | ### .concat(options) 38 | 39 | Passing `options` as a `String` is a shortcut for `{output: }`. Only concatenation will occur with this configuration. 40 | 41 | #### options.base 42 | 43 | Type: `string`
44 | Default: `''` 45 | 46 | Adjust the concatenated file's base directory. This is useful when your `source()` is nested deeper than your `target()`. 47 | 48 | ```js 49 | // without \`base\` 50 | yield task.source('src/js/**/*.js') 51 | .concat('all.js').target('dist/js'); 52 | //=> dist/js/client/all.js 53 | 54 | // with \`base\` 55 | yield task.source('src/js/**/*.js') 56 | .concat({ output:'all.js', base:'src/js' }).target('dist/js'); 57 | //=> dist/js/all.js 58 | ``` 59 | 60 | #### options.map 61 | 62 | Type: `boolean`
63 | Default: `false` 64 | 65 | Should a sourcemap be generated? If `true`, its name will be `{options.output}.map` and it will be a sibling of the concatenated file. 66 | 67 | ``` 68 | dist\ 69 | |- all.js 70 | |- all.js.map 71 | ``` 72 | 73 | #### options.output 74 | 75 | Type: `string`
76 | Default: `''` 77 | 78 | The name of your concatenated file. 79 | 80 | #### options.sep 81 | 82 | Type: `string`
83 | Default: `''` 84 | 85 | 86 | ## Support 87 | 88 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 89 | 90 | Please be sure to specify that you are using `@taskr/concat`. 91 | 92 | ## License 93 | 94 | MIT © [Luke Edwards](https://lukeed.com) 95 | -------------------------------------------------------------------------------- /packages/concat/test/fixtures/a.js: -------------------------------------------------------------------------------- 1 | console.log('this is file `a.js`'); 2 | -------------------------------------------------------------------------------- /packages/concat/test/fixtures/b.js: -------------------------------------------------------------------------------- 1 | console.log('this is file `b.js`'); 2 | -------------------------------------------------------------------------------- /packages/concat/test/fixtures/c.js: -------------------------------------------------------------------------------- 1 | console.log('this is file `c.js`'); 2 | -------------------------------------------------------------------------------- /packages/concat/test/fixtures/sub/sub/a.js: -------------------------------------------------------------------------------- 1 | console.log('this is file `sub/sub/a.js'); 2 | -------------------------------------------------------------------------------- /packages/concat/test/fixtures/sub/sub/b.js: -------------------------------------------------------------------------------- 1 | console.log('this is file `sub/sub/b.js'); 2 | -------------------------------------------------------------------------------- /packages/concat/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const bun = 'out.js'; 8 | const dir = join(__dirname, 'fixtures'); 9 | const tmp = join(__dirname, '.tmp'); 10 | const tar = join(tmp, bun); 11 | 12 | test('@taskr/concat', t => { 13 | t.plan(8); 14 | 15 | const taskr = new Taskr({ 16 | plugins: [ 17 | require('@taskr/clear'), 18 | require('../') 19 | ], 20 | tasks: { 21 | *a(f) { 22 | // test #1: str 23 | yield f.source(`${dir}/*.js`).concat(bun).target(tmp); 24 | const arr1 = yield f.$.expand(`${tmp}/*`); 25 | const out1 = yield f.$.find(bun, tmp); 26 | t.equal(out1, tar, 'via str; create `output` file'); 27 | t.equal(arr1.length, 1, 'via str; do not create a sourcemap'); 28 | yield f.clear(tmp); 29 | yield f.start('b'); 30 | }, 31 | *b(f) { 32 | // test #2: obj w/ `map` 33 | yield f.source(`${dir}/*.js`).concat({ output:bun, map:true }).target(tmp); 34 | const arr1 = yield f.$.expand(`${tmp}/*`); 35 | const out1 = yield f.$.find(bun, tmp); 36 | const out2 = yield f.$.find(`${bun}.map`, tmp); 37 | t.equal(out1, tar, 'via obj w/ `map`; create `output` file'); 38 | t.ok(arr1.length === 2 && out2.length, 'via obj w/ `map`; create a sourcemap'); 39 | yield f.clear(tmp); 40 | yield f.start('c'); 41 | }, 42 | *c(f) { 43 | // test #3: obj w/ `map` and `base` 44 | yield f.source(`${dir}/*.js`).concat({ output:bun, map:true, base:tmp }).target(tmp); 45 | const arr1 = yield f.$.expand(`${tmp}/*`); 46 | const out1 = yield f.$.find(bun, tmp); 47 | const out2 = yield f.$.find(`${bun}.map`, tmp); 48 | t.equal(out1, tar, 'via obj w/ `map` & `base`; create `output` file'); 49 | t.ok(arr1.length === 2 && out2.length, 'via obj w/ `map` & `base`; create a sourcemap'); 50 | yield f.clear(tmp); 51 | yield f.start('d'); 52 | }, 53 | *d(f) { 54 | // test #4: obj w/ `map` & `base` (nested) 55 | yield f.source(`${dir}/sub/**/*.js`).concat({ output:bun, map:true, base:tmp }).target(tmp); 56 | const arr1 = yield f.$.expand(`${tmp}/*`); 57 | const out1 = yield f.$.find(bun, tmp); 58 | const out2 = yield f.$.find(`${bun}.map`, tmp); 59 | t.equal(out1, tar, 'via obj w/ `map` & `base` (nested); create `output` file'); 60 | t.ok(arr1.length === 2 && out2.length, 'via obj w/ `map` & `base` (nested); create a sourcemap'); 61 | yield f.clear(tmp); 62 | } 63 | } 64 | }); 65 | 66 | taskr.start('a'); 67 | }); 68 | -------------------------------------------------------------------------------- /packages/esnext/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Script = require('vm').Script; 4 | const dirname = require('path').dirname; 5 | const rImports = require('rewrite-imports'); 6 | const req = require('require-like'); 7 | 8 | const fn = 'function*'; 9 | const box = {}; 10 | 11 | module.exports = function (file, data) { 12 | // setup mock env 13 | Object.assign(box, global); 14 | box.module = { exports }; 15 | box.exports = exports; 16 | box.require = req(file); 17 | 18 | box.__dirname = dirname(file); 19 | box.__filename = file; 20 | 21 | const scr = new Script( 22 | rImports(data) 23 | .replace(/await/gi, 'yield') 24 | .replace(/export /gi, 'exports.') 25 | .replace(/default async function/gi, `default = ${fn}`) 26 | .replace(/async function(\s)?.+?(?=\()/gi, str => str.trim().split(' ').pop().concat(` = ${fn} `)) 27 | ); 28 | // `eval()` new content 29 | scr.runInNewContext(box); 30 | // return new `tasks` object 31 | return box.module.exports; 32 | }; 33 | -------------------------------------------------------------------------------- /packages/esnext/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/esnext", 3 | "version": "1.1.0", 4 | "description": "Allows taskfiles to be written with ES6 or ES7 syntax.", 5 | "repository": "lukeed/taskr", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "scripts": { 9 | "test": "tape test/*.js | tap-spec" 10 | }, 11 | "author": { 12 | "name": "Luke Edwards", 13 | "email": "luke.edwards05@gmail.com", 14 | "url": "https://lukeed.com" 15 | }, 16 | "dependencies": { 17 | "require-like": "^0.1.2", 18 | "rewrite-imports": "^1.0.0" 19 | }, 20 | "devDependencies": { 21 | "bluebird": "^3.5.0" 22 | }, 23 | "publishConfig": { 24 | "access": "public" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/esnext/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/esnext [![npm](https://img.shields.io/npm/v/@taskr/esnext.svg)](https://npmjs.org/package/@taskr/esnext) 2 | 3 | > Allows a `taskfile.js` to be written with ES6 or ES7 syntax. 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/esnext 9 | ``` 10 | 11 | **That's it!** :tada: You've now enabled `async`/`await` and `import` syntax for your `taskfile.js`! 12 | 13 | > **Note:** This will NOT compile your ES6 files into ES5. You must download and setup [`@taskr/babel`](https://npmjs.com/package/@taskr/babel) or [`@taskr/buble`](https://npmjs.com/package/@taskr/buble) for that. 14 | 15 | ## Usage 16 | 17 | A `taskfile.js` may also include `require()` statements (not shown). 18 | 19 | ```js 20 | // taskfile.js 21 | import { foo, bar as baz } from './bat'; 22 | 23 | export default async function (task) { 24 | await task.source('src/*.js') // etc... 25 | } 26 | 27 | export async function lint(task) { 28 | await task.source('src/*.js') // etc... 29 | } 30 | 31 | export async function styles(task, obj) { 32 | await task.source(obj.src || 'src/*.sass') // etc... 33 | } 34 | ``` 35 | 36 | ## Support 37 | 38 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 39 | 40 | Please be sure to specify that you are using `@taskr/esnext`. 41 | 42 | ## License 43 | 44 | MIT © [Luke Edwards](https://lukeed.com) 45 | -------------------------------------------------------------------------------- /packages/esnext/test/fixtures/bar.js: -------------------------------------------------------------------------------- 1 | exports.bar = 'hello'; 2 | 3 | exports.baz = 'world'; 4 | -------------------------------------------------------------------------------- /packages/esnext/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | return 'hello'; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/esnext/test/fixtures/taskfile.js: -------------------------------------------------------------------------------- 1 | const aaa = 42; 2 | import foo from './foo'; 3 | import { bar as quz, baz as qut } from './bar'; 4 | 5 | export default async function () { 6 | await this.source('src/*.js').target('dist'); 7 | }; 8 | 9 | export async function foo () { 10 | await this.clear('dist'); 11 | return await this.start('bar', { val:aaa }); 12 | } 13 | 14 | export async function bar(o) { 15 | return `${foo()}: ${o ? o.val : aaa}`; 16 | } 17 | 18 | export async function baz(one, two) { 19 | return { one, two }; 20 | } 21 | 22 | export async function bat (one, two) { 23 | return `${quz} ${qut}`; 24 | } 25 | -------------------------------------------------------------------------------- /packages/esnext/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const read = require('fs').readFileSync; 5 | const co = require('bluebird').coroutine; 6 | const test = require('tape'); 7 | const fn = require('../'); 8 | 9 | const file = join(__dirname, 'fixtures', 'taskfile.js'); 10 | const data = read(file, 'utf8'); 11 | 12 | const hasYield = f => /yield/i.test(f.toString()); 13 | const isGenerator = f => f.constructor.name === 'GeneratorFunction'; 14 | 15 | test('@taskr/esnext', co(function * (t) { 16 | t.plan(26); 17 | 18 | t.equal(typeof fn, 'function', 'export a function'); 19 | 20 | const out = fn(file, data); 21 | 22 | t.equal(typeof out, 'object', 'return an object'); 23 | t.equal(Object.keys(out).length, 5, 'exports all tasks'); 24 | 25 | let func; 26 | ['default', 'foo', 'bar', 'baz', 'bat'].forEach(k => { 27 | func = out[k]; 28 | t.true(func !== void 0, `exports.${k} is defined`); 29 | t.equal(typeof func, 'function', `exports.${k} is a function`); 30 | t.true(isGenerator(func), `rewrite exports.${k} as a generator function`); 31 | }); 32 | 33 | // specifics 34 | t.true(hasYield(out.foo), '`foo` task has `yield`'); 35 | t.true(hasYield(out.default), '`default` task has `yield`'); 36 | t.true(/function\* \(o\)/.test(out.bar.toString()), 'keeps one parameter'); 37 | t.true(/function\* \(one, two\)/.test(out.baz.toString()), 'keeps two parameters (xo)'); 38 | t.true(/function\* \(one, two\)/.test(out.bat.toString()), 'keeps two parameters (standard)'); 39 | 40 | const val1 = yield co(out.bar)(); 41 | t.equal(val1, 'hello: 42', 'handle `require()` & embedded values'); 42 | 43 | const val2 = yield co(out.baz)('foo', 'bar'); 44 | t.deepEqual(val2, {one: 'foo', two: 'bar'}, 'accepts & handles multiple parameters'); 45 | 46 | const val3 = yield co(out.bat)(); 47 | t.equal(val3, 'hello world', 'handles aliased import partials correctly'); 48 | })); 49 | -------------------------------------------------------------------------------- /packages/flatten/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const normalize = path.normalize; 5 | const sep = path.sep; 6 | 7 | module.exports = function (task) { 8 | task.plugin('flatten', { every:false }, function * (files, opts) { 9 | if (!files.length) { 10 | return task.emit('plugin_warning', { 11 | plugin: '@taskr/flatten', 12 | warning: 'No source files to flatten!' 13 | }); 14 | } 15 | 16 | const levels = opts.levels || 0; 17 | 18 | // find shortest `dir` path; glob originated here 19 | const globBaseDir = files.map(o => o.dir).sort()[0]; 20 | 21 | for (let file of files) { 22 | file.dir = trimmer(globBaseDir, file.dir, levels); 23 | } 24 | }); 25 | }; 26 | 27 | function trimmer(baseDir, fileDir, levels) { 28 | if (levels === 0) { 29 | return baseDir; 30 | } 31 | 32 | let dirs = fileDir.replace(baseDir, ''); 33 | const arr = dirs.split(sep); 34 | const len = arr.length; 35 | 36 | if (levels < len) { 37 | dirs = arr.splice(len - levels).join(sep); 38 | } 39 | 40 | return normalize(baseDir + sep + dirs); 41 | } 42 | -------------------------------------------------------------------------------- /packages/flatten/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/flatten", 3 | "version": "1.1.0", 4 | "description": "Flatten all source files to a specified maximum of sub-directories.", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "files": [ 8 | "index.js" 9 | ], 10 | "keywords": [ 11 | "taskr", 12 | "taskr-plugin", 13 | "directories", 14 | "flatten", 15 | "glob" 16 | ], 17 | "scripts": { 18 | "test": "tape test/*.js | tap-spec" 19 | }, 20 | "author": { 21 | "name": "Luke Edwards", 22 | "email": "luke.edwards05@gmail.com", 23 | "url": "https://lukeed.com" 24 | }, 25 | "devDependencies": { 26 | "@taskr/clear": "^1.1.0", 27 | "taskr": "^1.1.0" 28 | }, 29 | "engines": { 30 | "node": ">= 4.6" 31 | }, 32 | "publishConfig": { 33 | "access": "public" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/flatten/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/flatten [![npm](https://img.shields.io/npm/v/@taskr/flatten.svg)](https://npmjs.org/package/@taskr/flatten) 2 | 3 | > Flatten all source files to a specified maximum of sub-directories. 4 | 5 | A source's directory structure isn't always desirable in the output. With `@taskr/flatten`, you may dictate how many _parent directories_ of a file to keep. 6 | 7 | ## Install 8 | 9 | ``` 10 | $ npm install --save-dev @taskr/flatten 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```sh 16 | src 17 | ├── images 18 | │ ├── img.jpg 19 | │ ├── foo 20 | │ ├── foo.jpg 21 | │ ├── bar 22 | │ ├── bar.jpg 23 | ``` 24 | 25 | ```js 26 | exports.images = function * (task) { 27 | yield task.source('src/images/**/*.jpg').flatten({ levels: 1 }).target('dist/img'); 28 | } 29 | ``` 30 | 31 | ```sh 32 | # output 33 | dist 34 | ├── img 35 | │ ├── img.jpg 36 | │ ├── foo 37 | │ ├── foo.jpg 38 | │ ├── bar 39 | │ ├── bar.jpg 40 | ``` 41 | 42 | ## API 43 | 44 | ### .flatten(options) 45 | 46 | #### options.levels 47 | 48 | Type: `Number`
49 | Default: `0` 50 | 51 | The number of sub-directories allowed **in relation to** your glob root. 52 | 53 | 54 | ## Examples 55 | 56 | All examples use the [demo file tree](#usage) listed above. 57 | 58 | ### Level: 0 59 | 60 | No parent directories are kept. 61 | 62 | > **Note:** The `img` directory is kept because we've used `.target('dist/img')`. 63 | 64 | ``` 65 | dist 66 | ├── img 67 | │ ├── img.jpg 68 | │ ├── foo.jpg 69 | │ ├── bar.jpg 70 | ``` 71 | 72 | ### Level: 1 73 | 74 | Each file is allowed to keep 1 parent directory. 75 | 76 | ``` 77 | dist 78 | ├── img 79 | │ ├── img.jpg 80 | │ ├── foo 81 | │ ├── foo.jpg 82 | │ ├── bar 83 | │ ├── bar.jpg 84 | ``` 85 | 86 | ### Level: 5 87 | 88 | Our file tree is **only** 2 levels deep (`images [0]/foo [1]/bar [2]/bar.jpg`). Because our "allowed levels" exceeds our tree depth, `@taskr/flatten` won't do anthing and so the entire structure will be copied. 89 | 90 | ```sh 91 | dist 92 | ├── img 93 | │ ├── img.jpg 94 | │ ├── foo 95 | │ ├── foo.jpg 96 | │ ├── bar 97 | │ ├── bar.jpg 98 | ``` 99 | 100 | 101 | ## Support 102 | 103 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 104 | 105 | Please be sure to specify that you are using `@taskr/flatten`. 106 | 107 | ## License 108 | 109 | MIT © [Luke Edwards](https://lukeed.com) 110 | -------------------------------------------------------------------------------- /packages/flatten/test/fixtures/base.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/flatten/test/fixtures/base.js -------------------------------------------------------------------------------- /packages/flatten/test/fixtures/foo/bar/bar1.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/flatten/test/fixtures/foo/bar/bar1.js -------------------------------------------------------------------------------- /packages/flatten/test/fixtures/foo/bar/bar2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/flatten/test/fixtures/foo/bar/bar2.js -------------------------------------------------------------------------------- /packages/flatten/test/fixtures/foo/bar/baz/baz1.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/flatten/test/fixtures/foo/bar/baz/baz1.js -------------------------------------------------------------------------------- /packages/flatten/test/fixtures/foo/bar/baz/baz2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/flatten/test/fixtures/foo/bar/baz/baz2.js -------------------------------------------------------------------------------- /packages/flatten/test/fixtures/foo/bar/baz/baz3.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/flatten/test/fixtures/foo/bar/baz/baz3.js -------------------------------------------------------------------------------- /packages/flatten/test/fixtures/foo/foo1.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/flatten/test/fixtures/foo/foo1.js -------------------------------------------------------------------------------- /packages/flatten/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const dir = join(__dirname, 'fixtures'); 8 | const tmp = join(__dirname, '.tmp'); 9 | 10 | test('@taskr/flatten', t => { 11 | t.plan(10); 12 | 13 | const src = `${dir}/**/*.js`; 14 | 15 | const taskr = new Taskr({ 16 | plugins: [ 17 | require('@taskr/clear'), 18 | require('../') 19 | ], 20 | tasks: { 21 | *a(f) { 22 | yield f.source(`${dir}/*.foo`).flatten().target(tmp); 23 | }, 24 | *b(f) { 25 | // default (level: 0) 26 | yield f.source(src).flatten().target(tmp); 27 | const arr = yield f.$.expand(`${tmp}/*`); 28 | t.equal(arr.length, 7, '(level:0) flatten all files to same directory'); 29 | yield f.clear(tmp); 30 | }, 31 | *c(f) { 32 | yield f.source(src).flatten({ levels: 1 }).target(tmp); 33 | const arr1 = yield f.$.expand(`${tmp}/*`); 34 | const arr2 = yield f.$.expand(`${tmp}/*.js`); 35 | t.equal(arr1.length - arr2.length, 3, '(level:1) creates 1 file and 3 subdirs'); 36 | const arr3 = yield f.$.expand(`${tmp}/bar/*`); 37 | t.equal(arr3.length, 2, '(level:1) deeply-nested subdirs are moved'); 38 | yield f.clear(tmp); 39 | }, 40 | *d(f) { 41 | yield f.source(`${dir}/foo/**/*.js`).flatten({ levels: 2 }).target(tmp); 42 | const arr1 = yield f.$.expand(`${tmp}/*`); 43 | const arr2 = yield f.$.expand(`${tmp}/*.js`); 44 | t.equal(arr1.length - arr2.length, 1, '(level:2) creates 1 file and 1 subdir'); 45 | const arr3 = yield f.$.expand(`${tmp}/bar/*`); 46 | const arr4 = yield f.$.expand(`${tmp}/bar/*.js`); 47 | t.equal(arr3.length - arr4.length, 1, '(level:2) creates 2 files and 1 subdir within `baz`'); 48 | const arr5 = yield f.$.expand(`${tmp}/bar/baz/*`); 49 | t.equal(arr5.length, 3, '(level:2) creates all 3 files within 2nd subdir level'); 50 | yield f.clear(tmp); 51 | }, 52 | *e(f) { 53 | // allowed `levels` is deeper than source tree 54 | yield f.source(src).flatten({ levels: 5 }).target(tmp); 55 | const arr1 = yield f.$.expand(`${tmp}/*`); 56 | const arr2 = yield f.$.expand(`${tmp}/foo/bar/baz/*.js`); 57 | t.true(arr1.length === 2 && arr2.length === 3,'(level:5) copy folder structure'); 58 | yield f.clear(tmp); 59 | } 60 | } 61 | }); 62 | 63 | // for task `a` 64 | taskr.emit = (evt, obj) => { 65 | if (evt === 'plugin_warning') { 66 | t.pass('emits plugin warning if no source files'); 67 | t.ok(/source files/i.test(obj.warning), 'informs user with message'); 68 | } 69 | }; 70 | 71 | t.ok('flatten' in taskr.plugins, 'add the `flatten` plugin'); 72 | 73 | taskr.serial(['a', 'b', 'c', 'd', 'e']); 74 | }); 75 | -------------------------------------------------------------------------------- /packages/gzip/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gzip = require('zlib').gzip; 4 | 5 | const defaults = { 6 | threshold: false, 7 | options: {}, 8 | ext: 'gz' 9 | }; 10 | 11 | module.exports = function (task, utils) { 12 | const zipper = utils.promisify(gzip); 13 | 14 | task.plugin('gzip', {}, function * (file, opts) { 15 | opts = Object.assign({}, defaults, opts); 16 | 17 | // if there is a threshold && we don't meet it, exit 18 | if (typeof opts.threshold === 'number' && Buffer.byteLength(file.data) < opts.threshold) { 19 | return; 20 | } 21 | 22 | // clone the file object 23 | // @todo: `opts.replace` 24 | let clone = Object.assign({}, file); 25 | 26 | // modify the file extension 27 | clone.base += (opts.ext.charAt(0) === '.') ? opts.ext : `.${opts.ext}`; 28 | 29 | // compress & set data 30 | clone.data = yield zipper(clone.data, opts.options); 31 | 32 | // add to files array 33 | this._.files.push(clone); 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/gzip/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/gzip", 3 | "version": "1.1.0", 4 | "description": "Gzip plugin for Taskr.", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "compress", 15 | "deflate", 16 | "gzip" 17 | ], 18 | "scripts": { 19 | "test": "tape test/*.js | tap-spec" 20 | }, 21 | "author": { 22 | "name": "Luke Edwards", 23 | "email": "luke.edwards05@gmail.com", 24 | "url": "https://lukeed.com" 25 | }, 26 | "devDependencies": { 27 | "@taskr/clear": "^1.1.0", 28 | "taskr": "^1.1.0" 29 | }, 30 | "engines": { 31 | "node": ">= 4.6" 32 | }, 33 | "publishConfig": { 34 | "access": "public" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/gzip/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/gzip [![npm](https://img.shields.io/npm/v/@taskr/gzip.svg)](https://npmjs.org/package/@taskr/gzip) 2 | 3 | > Gzip plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/gzip 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | exports.gzip = function * (task) { 15 | yield task.source('dist/**/*.*') 16 | .gzip({ 17 | threshold: 1024, 18 | ext: 'gzip', 19 | options: { 20 | level: 9 21 | } 22 | }) 23 | .target('dist'); 24 | } 25 | ``` 26 | 27 | ## API 28 | 29 | ### .gip(opts) 30 | 31 | Any files passed through `.gzip()` will not be affected directly. Instead, a _cloned_ copy will be compressed & have its extension modified. This means your `target` directory will contain the orginal file **and** its gzipped copy. 32 | 33 | ``` 34 | \src 35 | |- bundle.js 36 | \dist 37 | |- bundle.js 38 | |- bundle.js.gz 39 | ``` 40 | 41 | #### opts.ext 42 | 43 | Type: `string`
44 | Default: `gz` 45 | 46 | The extension to append to the compressed file's type. 47 | 48 | ``` 49 | bundle.js --> bundle.js.gz 50 | ``` 51 | 52 | #### opts.threshold 53 | 54 | Type: `integer`
55 | Default: `false` 56 | 57 | The minimum size, in bytes, required to be compressed. If a file does not satisfy this requirement, it will not be gzipped. 58 | 59 | #### opts.options 60 | 61 | Type: `object`
62 | Default: `{}` 63 | 64 | The [`zlib` options](https://nodejs.org/api/zlib.html#zlib_class_options) to pass in. 65 | 66 | ## Support 67 | 68 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 69 | 70 | Please be sure to specify that you are using `@taskr/gzip`. 71 | 72 | ## License 73 | 74 | MIT © [Luke Edwards](https://lukeed.com) 75 | -------------------------------------------------------------------------------- /packages/gzip/test/a.txt: -------------------------------------------------------------------------------- 1 | Hello world! 2 | -------------------------------------------------------------------------------- /packages/gzip/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const unzip = require('zlib').gunzipSync; 4 | const join = require('path').join; 5 | const Taskr = require('taskr'); 6 | const test = require('tape'); 7 | 8 | const tmp = join(__dirname, 'tmp'); 9 | const file = join(__dirname, 'a.txt'); 10 | 11 | test('@taskr/gzip', t => { 12 | t.plan(6); 13 | 14 | const taskr = new Taskr({ 15 | plugins: [ 16 | require('../'), 17 | require('@taskr/clear') 18 | ], 19 | tasks: { 20 | * foo(f) { 21 | yield f.source(file).gzip().target(tmp); 22 | 23 | const arr = yield f.$.expand(`${tmp}/*.*`); 24 | const str = yield f.$.read(`${tmp}/a.txt.gz`); 25 | t.equal(arr.length, 2, 'create two files'); 26 | t.ok(str, 'use default `gz` extension'); 27 | t.equal(unzip(str).toString(), 'Hello world!\n', 'can decompress the file correctly'); 28 | 29 | yield f.clear(tmp); 30 | }, 31 | * bar(f) { 32 | yield f.source(file).gzip({threshold: 1024}).target(tmp); 33 | const arr = yield f.$.expand(`${tmp}/*.*`); 34 | t.equal(arr.length, 1, 'do not use `gzip` if file is too small'); 35 | yield f.clear(tmp); 36 | }, 37 | * baz(f) { 38 | yield f.source(file).gzip({ext: 'fake'}).target(tmp); 39 | const arr = yield f.$.expand(`${tmp}/*.fake`); 40 | t.equal(arr.length, 1, 'pass a custom extension'); 41 | yield f.clear(tmp); 42 | } 43 | } 44 | }); 45 | 46 | t.ok('gzip' in taskr.plugins, 'attach `gzip` function to Taskr'); 47 | 48 | taskr.serial(['foo', 'bar', 'baz']); 49 | }); 50 | -------------------------------------------------------------------------------- /packages/htmlmin/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Default HTML-minifier options 3 | * @see https://www.npmjs.com/package/html-minifier#options-quick-reference 4 | */ 5 | module.exports = { 6 | removeComments: 1, 7 | collapseWhitespace: 1, 8 | collapseBooleanAttributes: 1, 9 | removeAttributeQuotes: 1, 10 | removeRedundantAttributes: 1, 11 | removeEmptyAttributes: 1, 12 | removeScriptTypeAttributes: 1, 13 | removeStyleLinkTypeAttributes: 1 14 | }; 15 | -------------------------------------------------------------------------------- /packages/htmlmin/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const minify = require('html-minifier').minify; 4 | const defs = require('./config'); 5 | 6 | module.exports = { 7 | name: 'htmlmin', 8 | * func(file, opts) { 9 | opts = Object.assign({}, defs, opts); 10 | const min = minify(file.data.toString(), opts); 11 | file.data = new Buffer(min); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /packages/htmlmin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/htmlmin", 3 | "version": "1.1.0", 4 | "description": "Minify HTML with Taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "*.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "htmlmin", 15 | "htm", 16 | "html", 17 | "minifier", 18 | "minification", 19 | "minify" 20 | ], 21 | "scripts": { 22 | "test": "tape test/*.js | tap-spec" 23 | }, 24 | "author": { 25 | "name": "Luke Edwards", 26 | "email": "luke.edwards05@gmail.com", 27 | "url": "https://lukeed.com" 28 | }, 29 | "dependencies": { 30 | "html-minifier": "^3.5.0" 31 | }, 32 | "devDependencies": { 33 | "@taskr/clear": "^1.1.0", 34 | "taskr": "^1.1.0" 35 | }, 36 | "engines": { 37 | "node": ">= 4.6" 38 | }, 39 | "publishConfig": { 40 | "access": "public" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/htmlmin/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/htmlmin [![npm](https://img.shields.io/npm/v/@taskr/htmlmin.svg)](https://npmjs.org/package/@taskr/htmlmin) 2 | 3 | > Minify HTML with [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | npm install --save-dev @taskr/htmlmin 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | exports.minify = function * (task) { 15 | yield task.source('src/*.html') 16 | .htmlmin({ removeComments:false }) 17 | .target('dist'); 18 | } 19 | ``` 20 | 21 | ## API 22 | 23 | ### .htmlmin(options) 24 | 25 | This plugin offers no unique options. 26 | 27 | However, it has a number of [default settings](config.js) that you may override. 28 | 29 | Please see [HTML-Minifier's Options](https://github.com/kangax/html-minifier#options-quick-reference) for a full list of available options. 30 | 31 | ## Support 32 | 33 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 34 | 35 | Please be sure to specify that you are using `@taskr/htmlmin`. 36 | 37 | ## License 38 | 39 | MIT © [Luke Edwards](https://lukeed.com) 40 | -------------------------------------------------------------------------------- /packages/htmlmin/test/fixtures/foo.html: -------------------------------------------------------------------------------- 1 |

2 | foo 3 |

4 | -------------------------------------------------------------------------------- /packages/htmlmin/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const dir = join(__dirname, 'fixtures'); 8 | const tmp = join(__dirname, 'tmp'); 9 | 10 | test('@taskr/htmlmin', t => { 11 | t.plan(3); 12 | 13 | const taskr = new Taskr({ 14 | plugins: [ 15 | require('../'), 16 | require('@taskr/clear') 17 | ], 18 | tasks: { 19 | * foo(f) { 20 | // #1 21 | yield f.source(`${dir}/foo.html`).htmlmin().target(tmp); 22 | const str1 = yield f.$.read(`${tmp}/foo.html`, 'utf8'); 23 | t.equal(str1, '

foo

', 'via defaults; minify html'); 24 | 25 | // #2 26 | yield f.source(`${dir}/foo.html`).htmlmin({ removeAttributeQuotes:false }).target(tmp); 27 | const str2 = yield f.$.read(`${tmp}/foo.html`, 'utf8'); 28 | t.equal(str2, '

foo

', 'via config; minify html'); 29 | 30 | yield f.clear(tmp); 31 | } 32 | } 33 | }); 34 | 35 | t.ok('htmlmin' in taskr.plugins, 'attach `htmlmin()` plugin to taskr'); 36 | 37 | taskr.start('foo'); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/jest/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runCLI = require('jest-cli').runCLI; 4 | 5 | module.exports = function (task) { 6 | const rootDir = task.root; 7 | task.plugin('jest', { every:false }, function * (_, opts) { 8 | const config = Object.assign({ rootDir }, opts); 9 | runCLI({ config }, [rootDir]); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/jest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/jest", 3 | "version": "1.1.1", 4 | "description": "Jest plugin for Taskr", 5 | "repository": "lukeed/taskr", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "jest" 15 | ], 16 | "scripts": { 17 | "test": "tape test/*.js | tap-spec" 18 | }, 19 | "author": { 20 | "name": "Luke Edwards", 21 | "email": "luke.edwards05@gmail.com", 22 | "url": "https://lukeed.com" 23 | }, 24 | "dependencies": { 25 | "jest-cli": "^20.0.0" 26 | }, 27 | "devDependencies": { 28 | "taskr": "^1.1.0" 29 | }, 30 | "engines": { 31 | "node": ">= 4.6" 32 | }, 33 | "publishConfig": { 34 | "access": "public" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/jest/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/jest [![npm](https://img.shields.io/npm/v/@taskr/jest.svg)](https://npmjs.org/package/@taskr/jest) 2 | 3 | > [Jest](https://facebook.github.io/jest/) plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/jest 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | exports.test = function * (task) { 15 | yield task.source('test/**/*.js').jest({ bail:true, notify:true }); 16 | } 17 | ``` 18 | 19 | ## API 20 | 21 | ### .jest(options) 22 | 23 | See [Jest's Configuration Options](https://facebook.github.io/jest/docs/configuration.html#options) to see the available options. 24 | 25 | 26 | ## Support 27 | 28 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 29 | 30 | Please be sure to specify that you are using `@taskr/jest`. 31 | 32 | ## License 33 | 34 | MIT © [Luke Edwards](https://lukeed.com) 35 | -------------------------------------------------------------------------------- /packages/jest/test/index.js: -------------------------------------------------------------------------------- 1 | const Taskr = require('taskr'); 2 | const test = require('tape'); 3 | 4 | test('@taskr/jest', t => { 5 | t.plan(2); 6 | const taskr = new Taskr({ 7 | plugins: [require('../')], 8 | tasks: { 9 | *foo(f) { 10 | t.true('jest' in f, 'attach `jest` to Task instance'); 11 | t.true('jest' in taskr.plugins, 'attach `jest` plugin to instance'); 12 | } 13 | } 14 | }); 15 | taskr.start('foo'); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/less/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const less = require('less'); 4 | 5 | module.exports = function (task) { 6 | task.plugin('less', {}, function * (file, opts) { 7 | opts = Object.assign({ paths:[file.dir] }, opts, { filename:file.base }); 8 | const mOpts = opts.sourceMap; 9 | // render each file's contents 10 | const str = file.data.toString(); 11 | const out = yield less.render(str, opts); 12 | // rename extensions 13 | file.base = file.base.replace(/\.less$/i, '.css'); 14 | // `less` will include inline sourcemap if config'd 15 | file.data = Buffer.from(out.css); 16 | // handle external sourcemaps 17 | if (out.map !== void 0 && mOpts !== void 0 && !mOpts.sourceMapFileInline) { 18 | const base = mOpts.sourceMapURL || `${file.base}.map`; 19 | // add map link comment 20 | if (mOpts === true || mOpts.sourceMapURL === void 0) { 21 | file.data += Buffer.from(`\n/*# sourceMappingURL=${base}*/`); 22 | } 23 | // Create new file 24 | this._.files.push({ base, dir:file.dir, data:Buffer.from(out.map) }); 25 | } 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /packages/less/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/less", 3 | "version": "1.1.0", 4 | "description": "Compile LESS to CSS with Taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "scripts": { 12 | "test": "tape test/*.js | tap-spec" 13 | }, 14 | "keywords": [ 15 | "taskr", 16 | "taskr-plugin", 17 | "compile", 18 | "less", 19 | "css" 20 | ], 21 | "author": { 22 | "name": "Luke Edwards", 23 | "email": "luke@lukeed.com", 24 | "url": "https://lukeed.com" 25 | }, 26 | "dependencies": { 27 | "less": "^2.7.0" 28 | }, 29 | "devDependencies": { 30 | "@taskr/clear": "^1.1.0", 31 | "taskr": "^1.1.0" 32 | }, 33 | "engines": { 34 | "node": ">= 4.6" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/less/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/less [![npm](https://img.shields.io/npm/v/@taskr/less.svg)](https://npmjs.org/package/@taskr/less) 2 | 3 | > Compile LESS to CSS with [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/less 9 | ``` 10 | 11 | ## Usage 12 | 13 | The paths within `task.source()` should always point to files that you want transformed into `.css` files. 14 | 15 | #### Basic 16 | 17 | ```js 18 | exports.styles = function * (task) { 19 | yield task.source('src/pages/*.less').less({ 20 | sourceMap: { sourceMapFileInline:true } 21 | }).target('dist/css'); 22 | } 23 | ``` 24 | 25 | #### Multiple Bundles 26 | 27 | Simply create an array of individual file paths. 28 | 29 | ```js 30 | exports.styles = function * (task) { 31 | yield task.source([ 32 | 'src/styles/client.less', 33 | 'src/styles/admin.less' 34 | ]).less().target('dist'); 35 | } 36 | ``` 37 | 38 | ## API 39 | 40 | ### .less(options) 41 | 42 | This plugin does not have any custom options. Please visit LESSCSS.org's [Configuration](http://lesscss.org/#using-less-configuration) and [Programmatic Usage](http://lesscss.org/usage/#programmatic-usage) docs for available options. 43 | 44 | > **Note:** You will _not_ be able to set the `filename` option. This is done for you & cannot be changed. 45 | 46 | ## Support 47 | 48 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 49 | 50 | Please be sure to specify that you are using `@taskr/less`. 51 | 52 | ## License 53 | 54 | MIT © [Luke Edwards](https://lukeed.com) 55 | -------------------------------------------------------------------------------- /packages/less/test/fixtures/expect.css: -------------------------------------------------------------------------------- 1 | .box { 2 | color: #fe33ac; 3 | border-color: #fdcdea; 4 | } 5 | .box div { 6 | -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 7 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 8 | } 9 | .bar { 10 | display: table; 11 | } 12 | .foo { 13 | display: none; 14 | } 15 | .main { 16 | display: block; 17 | } 18 | -------------------------------------------------------------------------------- /packages/less/test/fixtures/foo.less: -------------------------------------------------------------------------------- 1 | .foo { 2 | display: none; 3 | } 4 | -------------------------------------------------------------------------------- /packages/less/test/fixtures/style.less: -------------------------------------------------------------------------------- 1 | @import 'sub/bar'; 2 | @import 'foo'; 3 | 4 | .main { 5 | display: block; 6 | } 7 | -------------------------------------------------------------------------------- /packages/less/test/fixtures/sub/bar.less: -------------------------------------------------------------------------------- 1 | @import "baz"; 2 | 3 | .bar { 4 | display: table; 5 | } 6 | -------------------------------------------------------------------------------- /packages/less/test/fixtures/sub/baz.less: -------------------------------------------------------------------------------- 1 | @base: #f938ab; 2 | 3 | .box-shadow(@style, @c) when (iscolor(@c)) { 4 | -webkit-box-shadow: @style @c; 5 | box-shadow: @style @c; 6 | } 7 | .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) { 8 | .box-shadow(@style, rgba(0, 0, 0, @alpha)); 9 | } 10 | .box { 11 | color: saturate(@base, 5%); 12 | border-color: lighten(@base, 30%); 13 | div { .box-shadow(0 0 5px, 30%) } 14 | } 15 | -------------------------------------------------------------------------------- /packages/less/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const plugins = [require('../'), require('@taskr/clear')]; 8 | const dir = join(__dirname, 'fixtures'); 9 | const src = `${dir}/style.less`; 10 | 11 | const tmpDir = str => join(__dirname, str); 12 | const create = tasks => new Taskr({ tasks, plugins }); 13 | 14 | test('@taskr/less', t => { 15 | t.plan(1); 16 | const taskr = create({ 17 | *foo(f) { 18 | t.true('less' in taskr.plugins, 'attach `less()` plugin to taskr'); 19 | } 20 | }); 21 | taskr.start('foo'); 22 | }); 23 | 24 | test('@taskr/less (default)', t => { 25 | t.plan(2); 26 | create({ 27 | *foo(f) { 28 | const tmp = tmpDir('tmp-1'); 29 | const tar = `${tmp}/style.css`; 30 | 31 | const expect = yield f.$.read(`${dir}/expect.css`, 'utf8'); 32 | yield f.source(src).less().target(tmp); 33 | 34 | t.ok(yield f.$.find(tar), 'create a `.css` file correctly'); 35 | t.equal(yield f.$.read(tar, 'utf8'), expect, 'compile multi-tiered imports'); 36 | yield f.clear(tmp); 37 | } 38 | }).start('foo'); 39 | }); 40 | 41 | test('@taskr/less (inline)', t => { 42 | t.plan(2); 43 | create({ 44 | *foo(f) { 45 | const tmp = tmpDir('tmp-2'); 46 | yield f.source(src).less({ sourceMap:{sourceMapFileInline:true} }).target(tmp); 47 | 48 | const arr1 = yield f.$.expand(`${tmp}/*`); 49 | const str1 = yield f.$.read(`${tmp}/style.css`, 'utf8'); 50 | 51 | t.equal(arr1.length, 1, 'creates only one file'); 52 | t.true(str1.indexOf('sourceMappingURL=data:application/json') !== -1, 'appends inline sourcemap'); 53 | yield f.clear(tmp); 54 | } 55 | }).start('foo'); 56 | }); 57 | 58 | test('@taskr/less (external)', t => { 59 | t.plan(2); 60 | create({ 61 | *foo(f) { 62 | const tmp = tmpDir('tmp-3'); 63 | yield f.source(src).less({ sourceMap:{} }).target(tmp); 64 | 65 | const arr2 = yield f.$.expand(`${tmp}/*`); 66 | const str2 = yield f.$.read(`${tmp}/style.css`, 'utf8'); 67 | 68 | t.equal(arr2.length, 2, 'creates an external sourcemap file'); 69 | t.true(str2.indexOf('sourceMappingURL=style.css.map') !== -1, 'appends external sourcemap link'); 70 | yield f.clear(tmp); 71 | } 72 | }).start('foo'); 73 | }); 74 | 75 | test('@taskr/less (external=true)', t => { 76 | t.plan(2); 77 | create({ 78 | *foo(f) { 79 | const tmp = tmpDir('tmp-4'); 80 | yield f.source(src).less({ sourceMap:true }).target(tmp); 81 | 82 | const arr2 = yield f.$.expand(`${tmp}/*`); 83 | const str2 = yield f.$.read(`${tmp}/style.css`, 'utf8'); 84 | 85 | t.equal(arr2.length, 2, 'creates an external sourcemap file'); 86 | t.true(str2.indexOf('sourceMappingURL=style.css.map') !== -1, 'appends external sourcemap link'); 87 | yield f.clear(tmp); 88 | } 89 | }).start('foo'); 90 | }); 91 | 92 | test('@taskr/less (custom)', t => { 93 | t.plan(3); 94 | create({ 95 | *foo(f) { 96 | const map = 'out.css.map'; 97 | const tmp = tmpDir('tmp-5'); 98 | yield f.source(src).less({sourceMap:{ sourceMapURL:map }}).target(tmp); 99 | 100 | const arr3 = yield f.$.expand(`${tmp}/*`); 101 | const str3 = yield f.$.read(`${tmp}/style.css`, 'utf8'); 102 | 103 | t.equal(arr3.length, 2, 'creates an external sourcemap file'); 104 | t.ok(yield f.$.find(`${tmp}/${map}`), 'creates an external sourcemap with custom name'); 105 | t.true(str3.indexOf(`sourceMappingURL=${map}`) !== -1, 'appends link to custom sourcemap name'); 106 | yield f.clear(tmp); 107 | } 108 | }).start('foo'); 109 | }); 110 | -------------------------------------------------------------------------------- /packages/postcss/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const res = require('path').resolve; 4 | const postcss = require('postcss'); 5 | 6 | const base = { plugins:[], options:{} }; 7 | const filenames = ['.postcssrc', '.postcssrc.js', 'postcss.config.js', 'package.json']; 8 | 9 | const isString = any => typeof any === 'string'; 10 | const isObject = any => !!any && typeof any === 'object' && !Array.isArray(any); 11 | const isEmptyObj = any => isObject(any) && Object.keys(any).length === 0; 12 | 13 | module.exports = function (task, utils) { 14 | const rootDir = str => res(task.root, str); 15 | const setError = msg => task.emit('plugin_error', { plugin:'@taskr/postcss', error:msg }); 16 | const getConfig = arr => Promise.all(arr.map(utils.find)).then(res => res.filter(Boolean)).then(res => res[0]); 17 | 18 | task.plugin('postcss', { every:false }, function * (files, opts) { 19 | let config, isJSON = false; 20 | 21 | if (isEmptyObj(opts)) { 22 | // autoload a file 23 | const fileConfig = yield getConfig(filenames.map(rootDir)); 24 | // process if found one! 25 | if (fileConfig !== void 0) { 26 | try { 27 | config = require(fileConfig); 28 | } catch (err) { 29 | try { 30 | isJSON = true; // .rc file 31 | config = JSON.parse(yield utils.read(fileConfig, 'utf8')); 32 | } catch (_) { 33 | return setError(err.message); 34 | } 35 | } 36 | // handle config types 37 | if (typeof config === 'function') { 38 | config = config(base); // send default values 39 | } else if (isObject(config)) { 40 | // grab "postcss" key (package.json) 41 | if (config.postcss !== void 0) { 42 | config = config.postcss; 43 | isJSON = true; 44 | } 45 | 46 | // reconstruct plugins? 47 | if (isObject(config.plugins)) { 48 | let k, plugins=[]; 49 | for (k in config.plugins) { 50 | try { 51 | plugins.push(require(k)(config.plugins[k])); 52 | } catch (err) { 53 | return setError(`Loading PostCSS plugin (${k}) failed with: ${err.message}`); 54 | } 55 | } 56 | config.plugins = plugins; // update config 57 | } else if (isJSON && Array.isArray(config.plugins)) { 58 | const truthy = config.plugins.filter(Boolean); 59 | let i=0, len=truthy.length, plugins=[]; 60 | for (; i= 4.6" 37 | }, 38 | "publishConfig": { 39 | "access": "public" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/postcss/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/postcss [![npm](https://img.shields.io/npm/v/@taskr/postcss.svg)](https://npmjs.org/package/@taskr/postcss) 2 | 3 | > [PostCSS](https://github.com/postcss/postcss) plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/postcss 9 | ``` 10 | 11 | ## API 12 | 13 | ### .postcss([options]) 14 | 15 | Check out PostCSS's [Options](https://github.com/postcss/postcss#options) documentation to see the available options. 16 | 17 | > **Note:** There should be no need to set `options.to` and `options.from`. 18 | 19 | If you would like to [autoload external PostCSS config](#autoloaded-options), you must not define any `options` directly. 20 | 21 | 22 | ## Usage 23 | 24 | #### Embedded Options 25 | 26 | > Declare your PostCSS options directly within your `taskfile.js`: 27 | 28 | ```js 29 | exports.styles = function * (task) { 30 | yield task.source('src/**/*.scss').postcss({ 31 | plugins: [ 32 | require('precss'), 33 | require('autoprefixer')({ 34 | browsers: ['last 2 versions'] 35 | }) 36 | ], 37 | options: { 38 | parser: require('postcss-scss') 39 | } 40 | }).target('dist/css'); 41 | } 42 | ``` 43 | 44 | #### Autoloaded Options 45 | 46 | > Automatically detect & connect to existing PostCSS configurations 47 | 48 | If no [`options`](#api) were defined, `@taskr/postcss` will look for existing `.postcssrc`, `postcss.config.js`, and `.postcssrc.js` root-directory files. Similarly, it will honor a `"postcss"` key within your `package.json` file. 49 | 50 | * `.postcssrc` -- must be JSON; see [example](/test/fixtures/sub1/.postcssrc) 51 | * `.postcssrc.js` -- can be JSON or `module.exports` a Function or Object; see [example](/test/fixtures/sub4/.postcssrc.js) 52 | * `postcss.config.js` -- can be JSON or `module.exports` a Function or Object; see [example](/test/fixtures/sub3/postcss.config.js) 53 | * `package.json` -- must use `"postcss"` key & must be JSON; see [example](/test/fixtures/sub2/package.json) 54 | 55 | > **Important:** If you take this route, you only need _one_ of the files mentioned! 56 | 57 | ```js 58 | // taskfile.js 59 | exports.styles = function * (task) { 60 | yield task.source('src/**/*.scss').postcss().target('dist/css'); 61 | } 62 | ``` 63 | 64 | ```js 65 | // .postcssrc 66 | { 67 | "plugins": { 68 | "precss": {}, 69 | "autoprefixer": { 70 | "browsers": ["last 2 versions"] 71 | } 72 | }, 73 | "options": { 74 | "parser": "postcss-scss" 75 | } 76 | } 77 | ``` 78 | 79 | 80 | ## Support 81 | 82 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 83 | 84 | Please be sure to specify that you are using `@taskr/postcss`. 85 | 86 | ## License 87 | 88 | MIT © [Luke Edwards](https://lukeed.com) 89 | -------------------------------------------------------------------------------- /packages/postcss/test/fixtures/bar.scss: -------------------------------------------------------------------------------- 1 | @mixin flex(val) { 2 | flex: val; 3 | } 4 | 5 | .box { 6 | @include flex(1); 7 | display: flex; 8 | color: white; 9 | } 10 | -------------------------------------------------------------------------------- /packages/postcss/test/fixtures/foo.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | } 4 | -------------------------------------------------------------------------------- /packages/postcss/test/fixtures/sub1/.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/postcss/test/fixtures/sub2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "postcss": { 4 | "plugins": { 5 | "autoprefixer": {} 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/postcss/test/fixtures/sub3/postcss.config.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | 3 | module.exports = conf => ({ 4 | plugins: conf.plugins.concat(autoprefixer) 5 | }); 6 | -------------------------------------------------------------------------------- /packages/postcss/test/fixtures/sub4/.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('autoprefixer') 4 | ] 5 | }; 6 | -------------------------------------------------------------------------------- /packages/postcss/test/fixtures/sub5/.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "autoprefixer" 4 | ], 5 | "options": { 6 | "parser": "postcss-scss" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/prettier/index.js: -------------------------------------------------------------------------------- 1 | const format = require('prettier').format; 2 | 3 | module.exports = function (task) { 4 | task.plugin('prettier', {}, function * (file, opts) { 5 | const out = format(file.data.toString(), opts); 6 | file.data = Buffer.from(out); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/prettier/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/prettier", 3 | "version": "1.1.0", 4 | "description": "Prettier plugin for Taskr", 5 | "repository": "lukeed/taskr", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "prettier", 15 | "eslint" 16 | ], 17 | "scripts": { 18 | "test": "tape test/*.js | tap-spec" 19 | }, 20 | "author": { 21 | "name": "Luke Edwards", 22 | "email": "luke.edwards05@gmail.com", 23 | "url": "https://lukeed.com" 24 | }, 25 | "dependencies": { 26 | "prettier": "^1.4.0" 27 | }, 28 | "devDependencies": { 29 | "@taskr/clear": "^1.1.0", 30 | "taskr": "^1.1.0" 31 | }, 32 | "engines": { 33 | "node": ">= 4.6" 34 | }, 35 | "publishConfig": { 36 | "access": "public" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/prettier/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/prettier [![npm](https://img.shields.io/npm/v/@taskr/prettier.svg)](https://npmjs.org/package/@taskr/prettier) 2 | 3 | > [Prettier](https://github.com/prettier/prettier) plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/prettier 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | exports.lint = function * (task) { 15 | yield task.source('src/**/*.js').prettier({ 16 | semi: false, 17 | useTabs: true, 18 | trailingComma: 'es5' 19 | }).target('dist/js'); 20 | } 21 | ``` 22 | 23 | ## API 24 | 25 | ### .prettier(options) 26 | 27 | All configuration options can be found in [Prettier's API documentation](https://github.com/prettier/prettier#api). 28 | 29 | 30 | ## Support 31 | 32 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 33 | 34 | Please be sure to specify that you are using `@taskr/prettier`. 35 | 36 | ## License 37 | 38 | MIT © [Luke Edwards](https://lukeed.com) 39 | -------------------------------------------------------------------------------- /packages/prettier/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | console.log('Foo Bar') // hello 2 | -------------------------------------------------------------------------------- /packages/prettier/test/index.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const Taskr = require('taskr'); 3 | const test = require('tape'); 4 | 5 | const dir = join(__dirname, 'fixtures'); 6 | const plugins = [require('@taskr/clear'), require('../')]; 7 | 8 | const tmpDir = str => join(__dirname, str); 9 | const create = tasks => new Taskr({ tasks, plugins }); 10 | 11 | test('@taskr/prettier', t => { 12 | t.plan(2); 13 | const taskr = create({ 14 | *foo(f) { 15 | t.true('prettier' in f, 'attach `prettier` to Task instance'); 16 | t.true('prettier' in taskr.plugins, 'attach `prettier` plugin to instance'); 17 | } 18 | }); 19 | taskr.start('foo'); 20 | }); 21 | 22 | test('@taskr/prettier (defaults)', t => { 23 | t.plan(3); 24 | create({ 25 | *foo(f) { 26 | const tmp = tmpDir('tmp-1'); 27 | yield f.source(`${dir}/*.js`).prettier().target(tmp); 28 | 29 | const str = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 30 | t.false(/\s\s/.test(str), 'truncated extra spaces'); 31 | t.false(/'/.test(str), 'converted single quotes'); 32 | t.true(/;/.test(str), 'added semicolons'); 33 | yield f.clear(tmp); 34 | } 35 | }).start('foo'); 36 | }); 37 | 38 | test('@taskr/prettier (options)', t => { 39 | t.plan(3); 40 | create({ 41 | *foo(f) { 42 | const tmp = tmpDir('tmp-2'); 43 | yield f.source(`${dir}/*.js`).prettier({ 44 | singleQuote: true, 45 | semi: false 46 | }).target(tmp); 47 | 48 | const str = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 49 | t.false(/\s\s/.test(str), 'truncated extra spaces'); 50 | t.false(/;/.test(str), 'turned off semicolons'); 51 | t.true(/'/.test(str), 'kept single quotes'); 52 | yield f.clear(tmp); 53 | } 54 | }).start('foo'); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/rev/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const revHash = require('rev-hash'); 5 | const sortKeys = require('sort-keys'); 6 | 7 | const SEP = '/'; 8 | let MANIFEST, FILEPATH; 9 | const IGNORE = ['.png', '.jpg', '.jpeg', '.svg', '.gif', '.woff', '.ttf', '.eot', '.ico']; 10 | 11 | function fixPath(str) { 12 | return str.replace(/\\+/g, SEP); 13 | } 14 | 15 | module.exports = function (task, utils) { 16 | /** 17 | * Create new hashed file names based on contents 18 | */ 19 | task.plugin('rev', {}, function * (file, opts) { 20 | // overwrite default opt values 21 | opts = Object.assign({ ignores:IGNORE.concat('.html', '.json') }, opts); 22 | 23 | // bypass dirs or empty files 24 | if (!file.data) { 25 | return; 26 | } 27 | 28 | const ext = p.extname(file.base); 29 | // if this file's extension matches `ignores`, exit early 30 | if (!ext || opts.ignores.indexOf(ext) !== -1) { 31 | return; 32 | } 33 | 34 | file.orig = file.base; 35 | file.hash = revHash(file.data); 36 | 37 | // find first occurence of '.', NOT including first char 38 | const idx = file.base.indexOf('.', 1); 39 | 40 | // change filename; append hash to base name 41 | file.base = file.base.substr(0, idx).concat('-', file.hash, file.base.substr(idx)); 42 | }); 43 | 44 | /** 45 | * Write the manifest file 46 | */ 47 | task.plugin('revManifest', { every:false }, function * (files, opts) { 48 | MANIFEST = {}; // reset 49 | 50 | opts = Object.assign({ 51 | sort: true, 52 | dest: task.root, // place file 53 | trim: '', // path to trim 54 | file: 'rev-manifest.json' 55 | }, opts); 56 | 57 | // update known values 58 | FILEPATH = fixPath(p.resolve(opts.dest, opts.file)); 59 | 60 | // content to replace 61 | if (!opts.trim || typeof opts.trim === 'string') { 62 | const t = opts.trim; 63 | // create `replace` function 64 | opts.trim = str => str.replace(new RegExp(t, 'i'), '/'); 65 | } 66 | 67 | let dir, old; 68 | for (const f of files) { 69 | // only if was revv'd 70 | if (!f.orig) continue; 71 | // strip a string from the `file.dir` path 72 | dir = fixPath(p.relative(task.root, f.dir)); 73 | // apply `opts.trim` func 74 | dir = fixPath(p.normalize(opts.trim(dir))); 75 | // ensure no leading '/' 76 | dir = dir.charAt(0) === '/' ? dir.substr(1) : dir; 77 | // reconstruct old path 78 | old = fixPath(p.join(dir, f.orig)); 79 | // construct new; add pairing to manifest 80 | MANIFEST[old] = fixPath(p.join(dir, f.base)); 81 | } 82 | 83 | // alphabetically sort 84 | if (opts.sort) { 85 | MANIFEST = sortKeys(MANIFEST); 86 | } 87 | 88 | // write the file 89 | yield utils.write(FILEPATH, JSON.stringify(MANIFEST, false, ' ')); 90 | }); 91 | 92 | /** 93 | * Read all files within a `dir` & Update to latest filenames 94 | */ 95 | task.plugin('revReplace', { every:false }, function * (files, opts) { 96 | opts = Object.assign({ ignores:IGNORE }, opts); 97 | 98 | // get original manifest paths; escape safe characters 99 | const keys = Object.keys(MANIFEST).map(k => k.replace(/([[^$.|?*+(){}\\])/g, '\\$1')).join('|'); 100 | const rgx = new RegExp(keys, 'gi'); 101 | 102 | for (const f of files) { 103 | const ext = p.extname(f.base); 104 | // only if not in `ignores` 105 | if (!ext || opts.ignores.indexOf(ext) !== -1) continue; 106 | // replace orig with rev'd && write it 107 | const d = f.data.toString().replace(rgx, k => MANIFEST[k]); 108 | f.data = Buffer.from(d); 109 | } 110 | }); 111 | }; 112 | -------------------------------------------------------------------------------- /packages/rev/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/rev", 3 | "version": "1.1.0", 4 | "description": "Append a unique hash to filename. Optionally create a manifest mapping. Optionally rewrite references to updated filenames.", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "rev", 15 | "revving", 16 | "revision", 17 | "version", 18 | "replace", 19 | "hash", 20 | "optimize", 21 | "version", 22 | "versioning", 23 | "manifest", 24 | "manifest.json", 25 | "cache", 26 | "expire", 27 | "static", 28 | "asset", 29 | "assets" 30 | ], 31 | "scripts": { 32 | "test": "tape test/*.js | tap-spec" 33 | }, 34 | "author": { 35 | "name": "Luke Edwards", 36 | "email": "luke@lukeed.com", 37 | "url": "https://lukeed.com" 38 | }, 39 | "dependencies": { 40 | "rev-hash": "^2.0.0", 41 | "sort-keys": "^2.0.0" 42 | }, 43 | "devDependencies": { 44 | "@taskr/clear": "^1.1.0", 45 | "taskr": "^1.1.0" 46 | }, 47 | "engines": { 48 | "node": ">= 4.6" 49 | }, 50 | "publishConfig": { 51 | "access": "public" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/rev/test/fixtures/a.js: -------------------------------------------------------------------------------- 1 | console.log('this is a'); 2 | -------------------------------------------------------------------------------- /packages/rev/test/fixtures/b.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/rev/test/fixtures/sub/c.js: -------------------------------------------------------------------------------- 1 | console.log('this is c'); 2 | -------------------------------------------------------------------------------- /packages/sass/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const sass = require('node-sass'); 5 | 6 | module.exports = function (task, utils) { 7 | const render = utils.promisify(sass.render); 8 | 9 | // requires that `source()` is specifying MAIN files directly! 10 | task.plugin('sass', {}, function * (file, opts) { 11 | // ensure `opts.file` & not `opts.data` 12 | opts = Object.assign({}, opts, { file:p.format(file), data:null }); 13 | 14 | // option checks for `sourceMap` 15 | if (opts.sourceMap && typeof opts.sourceMap === 'boolean' && !opts.outFile) { 16 | return this.emit('plugin_error', { 17 | plugin: '@taskr/sass', 18 | message: 'You must specify an `outFile` if using a `boolean` value for `sourceMap`.' 19 | }); 20 | } 21 | 22 | // update extn to 'css' 23 | file.base = file.base.replace(/(s[a|c]ss)/i, 'css'); 24 | 25 | const data = yield render(opts); 26 | 27 | // update the file's data 28 | file.data = data.css; 29 | 30 | // if has `map` & needed opts 31 | if (data.map) { 32 | const o = p.parse(opts.outFile || opts.sourceMap); 33 | // create new `file` entry 34 | this._.files.push({ 35 | dir: o.dir, 36 | base: o.base, 37 | data: data.map 38 | }); 39 | } 40 | }); 41 | }; 42 | -------------------------------------------------------------------------------- /packages/sass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/sass", 3 | "version": "1.1.0", 4 | "description": "Compile SASS with `node-sass` and Taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "scripts": { 12 | "test": "tape test/*.js | tap-spec" 13 | }, 14 | "keywords": [ 15 | "taskr", 16 | "taskr-plugin", 17 | "node-sass", 18 | "sass" 19 | ], 20 | "author": { 21 | "name": "Luke Edwards", 22 | "email": "luke@lukeed.com", 23 | "url": "https://lukeed.com" 24 | }, 25 | "dependencies": { 26 | "node-sass": "^4.5.0" 27 | }, 28 | "devDependencies": { 29 | "@taskr/clear": "^1.1.0", 30 | "taskr": "^1.1.0" 31 | }, 32 | "engines": { 33 | "node": ">= 4.6" 34 | }, 35 | "publishConfig": { 36 | "access": "public" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/sass/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/sass [![npm](https://img.shields.io/npm/v/@taskr/sass.svg)](https://npmjs.org/package/@taskr/sass) 2 | 3 | > Compile SASS with [`node-sass`](https://github.com/sass/node-sass) and [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/sass 9 | ``` 10 | 11 | ## Usage 12 | 13 | The paths within `task.source()` should always point to files that you want transformed into `.css` files. 14 | 15 | #### Basic 16 | 17 | ```js 18 | exports.styles = function * (task) { 19 | yield task.source('src/styles/style.scss').sass().target('dist'); 20 | } 21 | ``` 22 | 23 | #### Multiple Bundles 24 | 25 | Simply create an array of individual file paths. 26 | 27 | ```js 28 | exports.styles = function * (task) { 29 | yield task.source([ 30 | 'src/styles/client.scss', 31 | 'src/styles/admin.scss' 32 | ]).sass().target('dist'); 33 | } 34 | ``` 35 | 36 | #### SASS vs SCSS 37 | 38 | There is no need to set [`indentedSyntax`](https://github.com/sass/node-sass#indentedsyntax) -- the SASS parser will intelligently decipher if you are using the SASS syntax. 39 | 40 | ```js 41 | exports.styles = function * (task) { 42 | yield task.source([ 43 | 'src/styles/client.sass', // SASS 44 | 'src/styles/admin.scss' // SCSS 45 | ]).sass().target('dist'); 46 | } 47 | ``` 48 | 49 | #### Sourcemaps 50 | 51 | You may create source maps for your bundles. Simply provide the desired file path as `outFile` or `sourceMap`. 52 | 53 | > **Important:** It is _recommended_ that you provide `sourceMap` your desired path. However, if `sourceMap` is `true`, you **must** then provide `outFile` your file path string. 54 | 55 | ```js 56 | exports.styles = function * (task) { 57 | yield task.source('src/app.sass') 58 | .sass({ sourceMap:'dist/css/app.css.map' }) 59 | .target('dist'); 60 | } 61 | 62 | // OR 63 | 64 | exports.styles = function * (task) { 65 | yield task.source('src/app.sass') 66 | .sass({ sourceMap:true, outFile:'dist/css/app.css.map' }) 67 | .target('dist'); 68 | } 69 | ``` 70 | 71 | ## API 72 | 73 | ### .sass(options) 74 | 75 | This plugin does not have any custom options. Please visit [`node-sass` options](https://github.com/sass/node-sass#options) for a full list of available options. 76 | 77 | > **Note:** You will _not_ be able to set the `file` or `data` options. These are done for you & cannot be changed. 78 | 79 | ## Support 80 | 81 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 82 | 83 | Please be sure to specify that you are using `@taskr/sass`. 84 | 85 | ## License 86 | 87 | MIT © [Luke Edwards](https://lukeed.com) 88 | -------------------------------------------------------------------------------- /packages/sass/test/fixtures/_a.sass: -------------------------------------------------------------------------------- 1 | .file__a 2 | display: none 3 | -------------------------------------------------------------------------------- /packages/sass/test/fixtures/style.sass: -------------------------------------------------------------------------------- 1 | @import 'sub/b' 2 | @import 'a' 3 | 4 | .main 5 | display: block 6 | -------------------------------------------------------------------------------- /packages/sass/test/fixtures/sub/_b.scss: -------------------------------------------------------------------------------- 1 | @import 'c'; 2 | 3 | .file__b { 4 | display: block; 5 | } 6 | -------------------------------------------------------------------------------- /packages/sass/test/fixtures/sub/_c.scss: -------------------------------------------------------------------------------- 1 | .file__c { 2 | visibility: hidden; 3 | } 4 | -------------------------------------------------------------------------------- /packages/sass/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const dir = join(__dirname, 'fixtures'); 8 | const tmp = join(__dirname, 'tmp'); 9 | 10 | const expect = '.file__c{visibility:hidden}.file__b{display:block}.file__a{display:none}.main{display:block}\n'; 11 | 12 | test('@taskr/sass', t => { 13 | t.plan(7); 14 | 15 | const taskr = new Taskr({ 16 | plugins: [ 17 | require('../'), 18 | require('@taskr/clear') 19 | ], 20 | tasks: { 21 | a: function * (f) { 22 | const map = `${tmp}/out.css.map`; 23 | const src = `${dir}/style.sass`; 24 | const tar = `${tmp}/style.css`; 25 | 26 | yield f.source(src).sass().target(tmp); 27 | t.ok(yield f.$.find(tar), 'create a `.css` file correctly'); 28 | 29 | yield f.source(src).sass({ outputStyle:'compressed' }).target(tmp); 30 | t.equal(yield f.$.read(tar, 'utf8'), expect, 'resolve multi-level imports && types!'); 31 | 32 | yield f.source(src).sass({ sourceMap:map }).target(tmp); 33 | const arr1 = yield f.$.expand(`${tmp}/*`); 34 | t.equal(arr1.length, 2, 'via `sourceMap`; create a source map'); 35 | t.ok(yield f.$.find(map), 'via `sourceMap`; create a source map with custom name'); 36 | yield f.clear(tmp); 37 | 38 | yield f.source(src).sass({ sourceMap:true, outFile:map }).target(tmp); 39 | const arr2 = yield f.$.expand(`${tmp}/*`); 40 | t.equal(arr2.length, 2, 'via `sourceMap + outFile`; create a source map'); 41 | t.ok(yield f.$.find(map), 'via `sourceMap + outFile`; create a source map with custom name'); 42 | yield f.clear(tmp); 43 | } 44 | } 45 | }); 46 | 47 | t.ok('sass' in taskr.plugins, 'attach `sass` plugin to taskr'); 48 | 49 | taskr.start('a'); 50 | }); 51 | -------------------------------------------------------------------------------- /packages/shell/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const format = require('path').format; 4 | const execa = require('execa').shell; 5 | 6 | const NAME = '@taskr/shell'; 7 | 8 | module.exports = function (task, utils) { 9 | const setError = str => task.emit('plugin_error', { error:str, plugin:NAME }); 10 | 11 | task.plugin('shell', { every:false }, function * (files, cmd, opts) { 12 | opts = opts || {}; 13 | 14 | if (typeof cmd !== 'string') { 15 | opts = cmd; 16 | cmd = opts.cmd; 17 | } 18 | 19 | const args = opts.args || []; 20 | 21 | if (!cmd) { 22 | return setError('No command received!'); 23 | } 24 | 25 | const isGlob = opts.glob || false; 26 | 27 | // output header 28 | const head = `${NAME}:${isGlob ? '\n\t' : ' '}`; 29 | const tail = isGlob ? '\n\t' : '\n'; 30 | 31 | const runWith = str => { 32 | // use file or glob 33 | const c = cmd.replace(/\$(file|glob)/gi, str); 34 | // pass all args to execa 35 | return execa.apply(this, [c, args, opts]).then(res => { 36 | utils.log(head + res.stdout.replace(/\n/g, tail)); 37 | }).catch(err => { 38 | setError(err.message); 39 | }); 40 | }; 41 | 42 | const src = isGlob ? this._.globs : files.map(format); 43 | return yield Promise.all(src.map(runWith)); 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /packages/shell/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/shell", 3 | "version": "1.1.0", 4 | "description": "Execute shell commands with Taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "command", 15 | "shell", 16 | "exec" 17 | ], 18 | "scripts": { 19 | "test": "tape test/*.js | tap-spec" 20 | }, 21 | "author": { 22 | "name": "Luke Edwards", 23 | "email": "luke@lukeed.com", 24 | "url": "http://github.com/lukeed" 25 | }, 26 | "dependencies": { 27 | "execa": "^0.7.0" 28 | }, 29 | "devDependencies": { 30 | "@taskr/clear": "^1.1.0", 31 | "taskr": "^1.1.0" 32 | }, 33 | "engines": { 34 | "node": ">= 4.6" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/shell/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/shell [![npm](https://img.shields.io/npm/v/@taskr/shell.svg)](https://npmjs.org/package/@taskr/shell) 2 | 3 | > Execute shell commands with [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/shell 9 | ``` 10 | 11 | ## API 12 | 13 | ### .shell(command, [options]) 14 | 15 | Both parameters are optional, but at least one must be present. Additionally, a `command` **is** required 16 | 17 | #### command 18 | Type: `string`
19 | 20 | The shell command to run. You may also use [`options.cmd`](#optionscmd) 21 | 22 | During execution, any occurrences of `$file` or `$glob` will be replaced with the the relevant filepath or glob pattern. 23 | 24 | #### options 25 | Type: `object`
26 | 27 | `@taskr/shell` uses [execa](https://github.com/sindresorhus/execa) as its `child_process` wrapper. This means it has the same options as [child_process.exec](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) and shares `execa`'s [additional options](https://github.com/sindresorhus/execa#options). 28 | 29 | #### options.cmd 30 | Type: `string`
31 | 32 | Same as [`command`](#command). You may want to use this if you only want to specify an `options` object. 33 | 34 | #### options.glob 35 | Type: `boolean`
36 | 37 | If the command should use the glob pattern within `task.source()`, you must set this to `true`. See [here](#iterate-once-per-glob) for example. 38 | 39 | 40 | ## Usage 41 | 42 | #### Iterate Once Per File 43 | 44 | You can apply a command to each file of your `glob` match. 45 | 46 | Instances of `$file` will be replaced by the file's path. 47 | 48 | ```js 49 | exports.default = function * (task) { 50 | yield task.source('src/*.js') 51 | .shell('cat $file') 52 | //=> @taskr/shell: console.log('this is src/a.js') 53 | //=> @taskr/shell: console.log('this is src/b.js') 54 | //=> @taskr/shell: console.log('this is src/c.js') 55 | .dist('dist'); 56 | } 57 | ``` 58 | 59 | #### Iterate Once Per Glob 60 | 61 | You can use the current glob within your shell command. 62 | 63 | Instances of `$file` will be replaced by the glob: 64 | 65 | ```js 66 | exports.default = function * (task) { 67 | yield task.source('src/*.js') 68 | .shell('cat $file', { glob:true }) 69 | //=> @taskr/shell: 70 | //=> console.log('this is src/a.js') 71 | //=> console.log('this is src/b.js') 72 | //=> console.log('this is src/c.js') 73 | .dist('dist'); 74 | 75 | yield task.source(['src/*.js', 'src/*.css']) 76 | .shell({ 77 | cmd: 'cat $glob', 78 | glob: true 79 | }) 80 | //=> @taskr/shell: 81 | //=> console.log('this is src/a.js') 82 | //=> console.log('this is src/b.js') 83 | //=> console.log('this is src/c.js') 84 | //=> body{margin:0;}header{color:black} 85 | //=> .hero{width:100%;height:400px} 86 | .dist('dist'); 87 | } 88 | ``` 89 | 90 | #### Passing Arguments 91 | 92 | Of course, command arguments may be passed within your [command string](#command). 93 | 94 | ```js 95 | exports.default = function * (task) { 96 | yield task.source('src').shell('ls -alh $file').dist('dist'); 97 | } 98 | ``` 99 | 100 | ## Support 101 | 102 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 103 | 104 | Please be sure to specify that you are using `@taskr/shell`. 105 | 106 | ## License 107 | 108 | MIT © [Luke Edwards](https://lukeed.com) 109 | -------------------------------------------------------------------------------- /packages/shell/test/fixtures/bar.js: -------------------------------------------------------------------------------- 1 | console.log('hello bar'); 2 | -------------------------------------------------------------------------------- /packages/shell/test/fixtures/baz.js: -------------------------------------------------------------------------------- 1 | console.log('hello baz'); 2 | -------------------------------------------------------------------------------- /packages/shell/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | console.log('hello foo'); 2 | -------------------------------------------------------------------------------- /packages/shell/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | let num = 0; 8 | const outlog = () => num++; 9 | const dir = join(__dirname, 'fixtures'); 10 | 11 | const create = tasks => new Taskr({ tasks, plugins }); 12 | 13 | test('@taskr/shell', t => { 14 | t.plan(5); 15 | const glob = `${dir}/*.js`; 16 | 17 | const taskr = new Taskr({ 18 | plugins: [ 19 | require('../'), 20 | require('@taskr/clear') 21 | ], 22 | tasks: { 23 | *foo(f) { 24 | t.true('shell' in f, 'attach the `shell()` plugin to internal task'); 25 | }, 26 | *bar(f) { 27 | yield f.source(glob).shell('cat $file').target('.tmp'); 28 | const arr = yield f.$.expand('.tmp/*'); 29 | t.equal(arr.length, 3, 'sends both files to target'); 30 | yield f.clear('.tmp'); 31 | }, 32 | *baz(f) { 33 | num = 0; 34 | f.$.log = outlog; 35 | yield f.source(glob).shell('cat $file'); 36 | t.equal(num, 3, 'runs `cat` on each file individually'); 37 | }, 38 | *bat(f) { 39 | num = 0; 40 | f.$.log = outlog; 41 | yield f.source(glob).shell('cat $file', { glob:true }); 42 | t.equal(num, 1, 'runs `cat` once per glob'); 43 | } 44 | } 45 | }); 46 | 47 | t.true('shell' in taskr.plugins, 'attach the `shell()` plugin to taskr'); 48 | 49 | taskr.serial(['foo', 'bar', 'baz', 'bat']); 50 | }); 51 | -------------------------------------------------------------------------------- /packages/stylus/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const stylus = require('stylus'); 5 | 6 | module.exports = function (task, utils) { 7 | task.plugin('stylus', {}, function * (file, opts) { 8 | opts = opts || {}; 9 | opts.filename = p.format(file); // to fix inline maps 10 | opts.paths = [file.dir].concat(opts.paths || '.'); 11 | 12 | const str = file.data.toString(); 13 | const ctx = stylus(str, opts); 14 | 15 | const mOpts = opts.sourceMap || opts.sourcemap; 16 | const isInline = !!(mOpts || {}).inline; 17 | if (mOpts !== void 0) { 18 | ctx.set('sourcemap', mOpts); 19 | } 20 | 21 | // render each file's contents (utils.promisfy breaks this??) 22 | yield new Promise((resolve, reject) => { 23 | ctx.render((err, css) => { 24 | if (err) return reject(err); 25 | // rename extensions 26 | file.base = file.base.replace(/\.styl$/i, '.css'); 27 | // `stylus` will include inline sourcemap if config'd 28 | file.data = Buffer.from(css); 29 | // handle external sourcemaps (only) 30 | if (ctx.sourcemap !== void 0 && !isInline) { 31 | const base = `${file.base}.map`; 32 | const data = JSON.stringify(ctx.sourcemap); 33 | // Create a new file 34 | this._.files.push({ base, dir:file.dir, data:Buffer.from(data) }); 35 | } 36 | resolve(); // exit 37 | }); 38 | }); 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /packages/stylus/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/stylus", 3 | "version": "1.1.0", 4 | "description": "Compile Stylus to CSS with Taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "scripts": { 12 | "test": "tape test/*.js | tap-spec" 13 | }, 14 | "keywords": [ 15 | "taskr", 16 | "taskr-plugin", 17 | "compie", 18 | "stylus", 19 | "styles", 20 | "css" 21 | ], 22 | "author": { 23 | "name": "Luke Edwards", 24 | "email": "luke@lukeed.com", 25 | "url": "https://lukeed.com" 26 | }, 27 | "dependencies": { 28 | "stylus": "^0.54.0" 29 | }, 30 | "devDependencies": { 31 | "@taskr/clear": "^1.1.0", 32 | "taskr": "^1.1.0" 33 | }, 34 | "engines": { 35 | "node": ">= 4.6" 36 | }, 37 | "publishConfig": { 38 | "access": "public" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/stylus/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/stylus [![npm](https://img.shields.io/npm/v/@taskr/stylus.svg)](https://npmjs.org/package/@taskr/stylus) 2 | 3 | > Compile [Stylus](http://stylus-lang.com/) to CSS with [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/stylus 9 | ``` 10 | 11 | ## Usage 12 | 13 | The paths within `task.source()` should always point to files that you want transformed into `.css` files. 14 | 15 | ```js 16 | exports.styles = function * (task) { 17 | yield task.source('src/pages/*.styl').stylus({ 18 | sourceMap: { inline:true } 19 | }).target('dist/css'); 20 | } 21 | ``` 22 | 23 | ## API 24 | 25 | ### .stylus(options) 26 | 27 | Check out the Stylus [JavaScript API](http://stylus-lang.com/docs/js.html) and [Sourcemaps](http://stylus-lang.com/docs/sourcemaps.html) docs to see the available options. 28 | 29 | 30 | ## Support 31 | 32 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 33 | 34 | Please be sure to specify that you are using `@taskr/stylus`. 35 | 36 | ## License 37 | 38 | MIT © [Luke Edwards](https://lukeed.com) 39 | -------------------------------------------------------------------------------- /packages/stylus/test/fixtures/expect.css: -------------------------------------------------------------------------------- 1 | .box { 2 | -webkit-border-radius: 5px; 3 | -moz-border-radius: 5px; 4 | border-radius: 5px; 5 | color: #fe33ac; 6 | border-color: #fb74c4; 7 | } 8 | .box div { 9 | -webkit-border-radius: 2px; 10 | -moz-border-radius: 2px; 11 | border-radius: 2px; 12 | } 13 | .bar { 14 | display: table; 15 | } 16 | .foo { 17 | display: none; 18 | } 19 | .main { 20 | display: block; 21 | } 22 | -------------------------------------------------------------------------------- /packages/stylus/test/fixtures/foo.styl: -------------------------------------------------------------------------------- 1 | .foo 2 | display: none 3 | -------------------------------------------------------------------------------- /packages/stylus/test/fixtures/style.styl: -------------------------------------------------------------------------------- 1 | @import 'sub/bar' 2 | @import 'foo' 3 | 4 | .main 5 | display: block 6 | -------------------------------------------------------------------------------- /packages/stylus/test/fixtures/sub/bar.styl: -------------------------------------------------------------------------------- 1 | @import 'baz' 2 | 3 | .bar 4 | display: table 5 | -------------------------------------------------------------------------------- /packages/stylus/test/fixtures/sub/baz.styl: -------------------------------------------------------------------------------- 1 | base-color = #f938ab 2 | 3 | border-radius(val) 4 | -webkit-border-radius: val 5 | -moz-border-radius: val 6 | border-radius: val 7 | 8 | .box 9 | border-radius(5px) 10 | color: saturate(base-color, 5%) 11 | border-color: lighten(base-color, 30%) 12 | div 13 | border-radius(2px) 14 | -------------------------------------------------------------------------------- /packages/stylus/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const plugins = [require('../'), require('@taskr/clear')]; 8 | const dir = join(__dirname, 'fixtures'); 9 | const src = `${dir}/style.styl`; 10 | 11 | const tmpDir = str => join(__dirname, str); 12 | const create = tasks => new Taskr({ tasks, plugins }); 13 | 14 | test('@taskr/stylus', t => { 15 | t.plan(1); 16 | const taskr = create({ 17 | *foo(f) { 18 | t.true('stylus' in taskr.plugins, 'attach `stylus()` plugin to taskr'); 19 | } 20 | }); 21 | taskr.start('foo'); 22 | }); 23 | 24 | test('@taskr/stylus (default)', t => { 25 | t.plan(2); 26 | create({ 27 | *foo(f) { 28 | const tmp = tmpDir('tmp-1'); 29 | const tar = `${tmp}/style.css`; 30 | 31 | const expect = yield f.$.read(`${dir}/expect.css`, 'utf8'); 32 | yield f.source(src).stylus().target(tmp); 33 | 34 | t.ok(yield f.$.find(tar), 'create a `.css` file correctly'); 35 | t.equal(yield f.$.read(tar, 'utf8'), expect, 'compile multi-tiered imports'); 36 | yield f.clear(tmp); 37 | } 38 | }).start('foo'); 39 | }); 40 | 41 | test('@taskr/stylus (sourcemap)', t => { 42 | t.plan(2); 43 | create({ 44 | *foo(f) { 45 | const tmp = tmpDir('tmp-2'); 46 | yield f.source(src).stylus({ sourcemap:true }).target(tmp); 47 | 48 | const arr = yield f.$.expand(`${tmp}/*`); 49 | const str = yield f.$.read(`${tmp}/style.css`, 'utf8'); 50 | 51 | t.equal(arr.length, 2, 'creates an external sourcemap file'); 52 | t.true(str.indexOf('sourceMappingURL=test/fixtures/style.css.map') !== -1, 'appends external sourcemap link'); 53 | yield f.clear(tmp); 54 | } 55 | }).start('foo'); 56 | }); 57 | 58 | test('@taskr/stylus (inline)', t => { 59 | t.plan(2); 60 | create({ 61 | *foo(f) { 62 | const tmp = tmpDir('tmp-3'); 63 | yield f.source(src).stylus({sourcemap:{ inline:true }}).target(tmp); 64 | 65 | const arr = yield f.$.expand(`${tmp}/*`); 66 | const str = yield f.$.read(`${tmp}/style.css`, 'utf8'); 67 | 68 | t.equal(arr.length, 1, 'creates only one file'); 69 | t.true(str.indexOf('sourceMappingURL=data:application/json') !== -1, 'appends inline sourcemap'); 70 | yield f.clear(tmp); 71 | } 72 | }).start('foo'); 73 | }); 74 | 75 | test('@taskr/stylus (no-comment)', t => { 76 | t.plan(2); 77 | create({ 78 | *foo(f) { 79 | const tmp = tmpDir('tmp-4'); 80 | yield f.source(src).stylus({sourcemap:{ comment:false }}).target(tmp); 81 | 82 | const arr2 = yield f.$.expand(`${tmp}/*`); 83 | const str2 = yield f.$.read(`${tmp}/style.css`, 'utf8'); 84 | 85 | t.equal(arr2.length, 2, 'creates an external sourcemap file'); 86 | t.true(str2.indexOf('sourceMappingURL=style.css.map') === -1, 'does NOT append external sourcemap link'); 87 | yield f.clear(tmp); 88 | } 89 | }).start('foo'); 90 | }); 91 | -------------------------------------------------------------------------------- /packages/taskr/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | const Promise = require('bluebird'); 5 | const reporter = require('./lib/reporter'); 6 | const utils = require('./lib/utils'); 7 | const cli = require('./lib/cli'); 8 | const pkg = require('./package'); 9 | const co = Promise.coroutine; 10 | 11 | co(function* () { 12 | // get command options 13 | const o = cli.options(); 14 | const t = o.tasks.length ? o.tasks : ['default']; 15 | 16 | if (o.help) { 17 | return cli.help(); 18 | } 19 | 20 | if (o.version) { 21 | return cli.version(pkg); 22 | } 23 | 24 | const taskr = yield cli.spawn(o.cwd); 25 | reporter.call(taskr); 26 | 27 | if (!taskr.file) { 28 | return taskr.emit('taskfile_not_found'); 29 | } 30 | 31 | if (o.list) { 32 | return cli.list(taskr.tasks, o.list === 'bare'); 33 | } 34 | 35 | // announce start 36 | taskr.emit('task_run', taskr.file); 37 | // run `tasks` in `mode` 38 | taskr[o.mode](t); 39 | 40 | })().catch(err => { 41 | if (err.type === 'cli') { 42 | utils.error(`CLI Error! ${err.message}`); 43 | } else { 44 | console.error(utils.trace(err.stack)); 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /packages/taskr/lib/boot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Promise = require('bluebird'); 4 | 5 | function deferAll(obj) { 6 | const o = {}; 7 | for (const k in obj) { 8 | o[k] = function () { 9 | return this.then(() => obj[k].apply(obj, arguments)); 10 | } 11 | } 12 | return o; 13 | } 14 | 15 | function wrapAll(obj) { 16 | const o = {}; 17 | for (const k in obj) { 18 | if (!(obj[k].call)) continue; // only functions 19 | o[k] = wrap(obj[k]).bind(obj); 20 | } 21 | return o; 22 | } 23 | 24 | function wrap(fn) { 25 | return function () { 26 | return fn.apply(this, arguments); 27 | } 28 | } 29 | 30 | function liquidate(obj) { 31 | const promised = wrapAll(obj); 32 | // merge with Promise API 33 | Object.assign(Promise.prototype, deferAll(promised)); 34 | return promised; 35 | } 36 | 37 | module.exports = liquidate; 38 | -------------------------------------------------------------------------------- /packages/taskr/lib/cli/help.js: -------------------------------------------------------------------------------- 1 | module.exports = _ => 2 | console.log(` 3 | Usage: taskr [options] [tasks] 4 | 5 | Options 6 | -m --mode=MODE Run in 'parallel' or 'serial'. Default: 'serial' 7 | -d --cwd=DIR Set Taskr's home directory. Default: '.' 8 | -l --list Display all available tasks. 9 | -v --version Display Taskr's version. 10 | -h --help Display this help text. 11 | 12 | Examples 13 | taskr -d=/demo 14 | taskr -m=parallel task1 task2 15 | taskr --mode=serial task1 task2 16 | `.replace(/^\n/, "")) 17 | -------------------------------------------------------------------------------- /packages/taskr/lib/cli/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | module.exports = { 4 | help: require("./help"), 5 | list: require("./list"), 6 | options: require("./options"), 7 | spawn: require("./spawn"), 8 | version: pkg => console.log(`${pkg.name}, ${pkg.version}`) 9 | } 10 | -------------------------------------------------------------------------------- /packages/taskr/lib/cli/list.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const fmt = require("../fmt") 4 | const rgx = /@desc(.*)/ 5 | 6 | /** 7 | * List available tasks within a Taskr instance 8 | * @param {Object} tasks The available tasks 9 | * @param {Boolean} bare Should output be unstyled? 10 | */ 11 | module.exports = function (tasks, bare) { 12 | bare = bare || false 13 | tasks = tasks || {} 14 | 15 | const out = [`\n${fmt.text.dim("Available tasks")}`] 16 | 17 | // parse tasks" descriptions, if any 18 | for (const k in tasks) { 19 | const arr = rgx.exec(tasks[k].toString()) 20 | const txt = arr ? arr.pop().replace(/\*\//, "") : "" 21 | out.push(`\t${fmt.title(k)}\t${txt}`) 22 | } 23 | 24 | out.push("") 25 | 26 | if (bare) { 27 | out.shift() 28 | out.pop() 29 | } 30 | 31 | return console.log(out.join("\n")) 32 | } 33 | -------------------------------------------------------------------------------- /packages/taskr/lib/cli/options.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const parse = require('mri') 4 | 5 | /** 6 | * Generic Error class for CLI errors 7 | */ 8 | class UnknownError extends Error { 9 | constructor(msg) { 10 | super() 11 | this.type = 'cli' 12 | this.message = msg 13 | } 14 | } 15 | 16 | /** 17 | * Make sense of an input string. 18 | * @param {Array} arr Input argument segments 19 | * @return {Object} 20 | */ 21 | module.exports = function (arr) { 22 | return parse(arr || process.argv.slice(2), { 23 | default: { 24 | cwd: '.', 25 | mode: 'serial' 26 | }, 27 | alias: { 28 | v: 'version', 29 | m: 'mode', 30 | h: 'help', 31 | l: 'list', 32 | d: 'cwd', 33 | _: 'tasks' 34 | }, 35 | unknown: key => { 36 | throw new UnknownError(`Unknown option: \`${key}\`. Run \`taskr -h\` to see available options.`); 37 | } 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /packages/taskr/lib/cli/spawn.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const co = require("bluebird").coroutine 4 | const load = require("../plugins").load 5 | const find = require("../utils/find") 6 | const read = require("../utils/read") 7 | const Taskr = require("../taskr") 8 | 9 | /** 10 | * Create a new Taskr instance 11 | * @param {String} cwd The directory to find a `taskfile.js` 12 | * @return {Taskr} The new Taskr instance 13 | */ 14 | module.exports = co(function * (cwd) { 15 | const file = yield find("taskfile.js", cwd) 16 | 17 | if (!file) { 18 | return new Taskr() 19 | } 20 | 21 | // find & `require()`. will load `@taskr/esnext` before spawning 22 | const plugins = yield load(file) 23 | 24 | // spawn options 25 | const opts = {cwd, file, plugins} 26 | 27 | try { 28 | const esnext = require("@taskr/esnext") 29 | if (esnext) { 30 | const data = yield read(file, "utf8") 31 | opts.tasks = esnext(file, data) 32 | } 33 | } catch (err) {} 34 | 35 | return new Taskr(opts) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/taskr/lib/fmt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const c = require('clorox'); 4 | 5 | module.exports = { 6 | complete: c.blue.bold, 7 | title: c.bold.yellow, 8 | error: c.bold.red, 9 | path: c.underline.cyan, 10 | warn: c.bold.magenta, 11 | text: c.bold.white, 12 | time: c.green 13 | }; 14 | -------------------------------------------------------------------------------- /packages/taskr/lib/fn.js: -------------------------------------------------------------------------------- 1 | /* eslint no-nested-ternary:0 */ 2 | 'use strict'; 3 | const tinydate = require('tinydate'); 4 | 5 | const $ = exports; 6 | 7 | // @see http://stackoverflow.com/a/16608074 8 | $.isObject = val => Boolean(val) && (val.constructor === Object); 9 | 10 | $.isEmptyObj = val => $.isObject(val) && !Object.keys(val).length; 11 | 12 | $.toArray = val => Array.isArray(val) ? val : (val == null) ? [] : [val]; 13 | 14 | /** 15 | * Format a task's duration. 16 | * @param {Array} arr Output from `process.hrtime` 17 | * @return {String} 18 | */ 19 | $.formatTime = arr => { 20 | let unit = 'ms'; 21 | let num = Math.round(arr[1] / 1000000); 22 | if (arr[0] > 0) { 23 | unit = 's'; 24 | num = (arr[0] + num / 1000).toFixed(2); 25 | } 26 | return `${num}${unit}`; 27 | } 28 | 29 | /** 30 | * Get the current time! 31 | * @return {String} Formatted as `[HH:mm:ss]`. 32 | */ 33 | $.getTime = tinydate('[{HH}:{mm}:{ss}]'); 34 | 35 | /** 36 | * Check if value is unique within the group. Modify if is not. 37 | * @param {String} val The value to check. 38 | * @param {Array} arr The array of values to check against. 39 | * @return {String} The unique value possibly incremented. 40 | */ 41 | $.valUniq = (val, arr) => { 42 | let n = 0; 43 | let v = val; 44 | while (arr.indexOf(v) !== -1) { 45 | n++; 46 | v = val.concat(n); 47 | } 48 | return v; 49 | } 50 | 51 | /** 52 | * Get a unique Set of Array values 53 | * @param {Array} arr The values to check 54 | * @return {Set} The unique values 55 | */ 56 | $.getUniques = arr => { 57 | const len = arr.length; 58 | const res = []; 59 | let i = 0; 60 | 61 | for (; i < len; i++) { 62 | const curr = arr[i]; 63 | if (res.indexOf(curr) === -1) { 64 | res.push(curr); 65 | } 66 | } 67 | 68 | return res; 69 | } 70 | 71 | function flat(arr, res) { 72 | let i = 0; 73 | const len = arr.length; 74 | for (; i < len; i++) { 75 | const cur = arr[i]; 76 | Array.isArray(cur) ? flat(cur, res) : res.push(cur); 77 | } 78 | return res; 79 | } 80 | 81 | $.flatten = arr => flat(arr, []); 82 | -------------------------------------------------------------------------------- /packages/taskr/lib/plugins.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const flatten = require('./fn').flatten; 5 | const isObject = require('./fn').isObject; 6 | const co = require('bluebird').coroutine; 7 | const $ = require('./utils'); 8 | 9 | const rgx = /^@(taskr|fly)|(taskr|fly)-/i; 10 | const dirname = p.dirname; 11 | const resolve = p.resolve; 12 | const join = p.join; 13 | 14 | /** 15 | * Attempt to dynamically `require()` a file or package 16 | * @param {String} name The dep-name or filepath to require. 17 | * @param {String} base Path to `node_modules` directory. 18 | */ 19 | function req(name, base) { 20 | try { 21 | try { 22 | name = require.resolve(name); 23 | } catch (_) { 24 | name = join(base, name); 25 | } finally { 26 | return require(name); 27 | } 28 | } catch (e) { 29 | $.alert(e.message); 30 | } 31 | } 32 | 33 | /** 34 | * Find a sibling `package.json` file & return its contents. 35 | * @param {Object} file A `package.json` contents as JSON 36 | * @return {Array} The names of all dependencies, flattened 37 | */ 38 | function getDependencies(pkg) { 39 | if (!pkg) { 40 | return []; 41 | } 42 | 43 | if (!isObject(pkg)) { 44 | $.error('Content from `package.json` must be an `Object`!'); 45 | return []; 46 | } 47 | 48 | // get all possible dependencies 49 | const deps = [ 50 | 'dependencies', 'devDependencies', 'peerDependencies' 51 | ].filter(key => pkg[key] !== void 0).map(k => Object.keys(pkg[k])); 52 | 53 | return flatten(deps); 54 | } 55 | 56 | /** 57 | * Find & Read a `package.json` file, starting from `dir`. 58 | * @param {String} dir 59 | * @yield {Object} If found, returns as `{file, data}` 60 | */ 61 | const getPackage = co(function * (dir) { 62 | // traverse upwards from `dir` 63 | const file = yield $.find('package.json', dir); 64 | 65 | if (!file) { 66 | return false; 67 | } 68 | 69 | // check if there's a 'taskr' config entry 70 | const data = JSON.parse(yield $.read(file)); 71 | 72 | if (data.taskr && data.taskr.pkg) { 73 | dir = resolve(dir, data.taskr.pkg); 74 | return yield getPackage(dir); 75 | } 76 | 77 | return { file, data }; 78 | }); 79 | 80 | /** 81 | * Loads all (fly|taskr)-related plugins! 82 | * @param {String} taskfile The full `taskfile.js` path 83 | * @return {Array} All loaded plugins. 84 | */ 85 | const load = co(function * (taskfile) { 86 | // find a `package.json`, starting with `taskfile` dir 87 | const pkg = yield getPackage(dirname(taskfile)); 88 | 89 | if (!pkg) { 90 | $.error('No `package.json` found!'); 91 | return []; 92 | } 93 | 94 | // get ALL deps filter down to (taskr|fly)-only 95 | const deps = getDependencies(pkg.data).filter(dep => rgx.test(dep)); 96 | const locals = pkg.data.taskr && pkg.data.taskr.requires; 97 | const hasNext = deps.indexOf('@taskr/esnext'); 98 | 99 | if (locals) { 100 | let i = 0; 101 | const len = locals.length; 102 | const pkgDir = dirname(pkg.file); 103 | for (; i < len; i++) { 104 | deps.push(join(pkgDir, locals[i])); 105 | } 106 | } 107 | 108 | // if '@taskr/esnext' remove from `deps` 109 | if (hasNext !== -1) { 110 | deps.splice(hasNext, 1); 111 | } 112 | 113 | const modules = join(dirname(pkg.file), 'node_modules'); 114 | 115 | // format return 116 | return deps.map(str => req(str, modules)); 117 | }); 118 | 119 | module.exports = { 120 | load, 121 | getPackage, 122 | getDependencies 123 | }; 124 | -------------------------------------------------------------------------------- /packages/taskr/lib/reporter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fmt = require('./fmt'); 4 | const $ = require('./utils/logging'); 5 | const formatTime = require('./fn').formatTime; 6 | 7 | module.exports = function () { 8 | return this 9 | .on('task_run', file => { 10 | $.log(`Running with ${fmt.path(file)}`); 11 | }) 12 | 13 | .on('taskfile_not_found', () => { 14 | $.log('Taskfile not found!'); 15 | process.exit(1); 16 | }) 17 | 18 | .on('task_watch', () => { 19 | $.log(`${fmt.warn('Watching files...')}`); 20 | }) 21 | 22 | .on('task_watch_event', obj => { 23 | $.log(`File ${obj.action}: ${fmt.warn(obj.file)}`); 24 | }) 25 | 26 | .on('globs_no_match', (globs, opts) => { 27 | let str = `${fmt.warn('Warning:')} Source did not match any files!`; 28 | str += `\n\t Patterns: ${JSON.stringify(globs)}`; 29 | opts && (str += `\n\t Options: ${JSON.stringify(opts)}`); 30 | $.log(str); 31 | }) 32 | 33 | .on('plugin_load', obj => { 34 | $.log(`Loading plugin ${fmt.title(obj.plugin)}`); 35 | }) 36 | 37 | .on('plugin_load_error', str => { 38 | $.log(`Problem loading plugin: ${fmt.title(str)}`); 39 | }) 40 | 41 | .on('plugin_rename', (old, nxt) => { 42 | $.log(`${fmt.title(old)} was renamed to ${fmt.title(nxt)} because its name was taken`); 43 | }) 44 | 45 | .on('plugin_warning', obj => { 46 | $.log(`${fmt.warn(obj.plugin)} warned that ${fmt.warn(obj.warning)}`); 47 | }) 48 | 49 | .on('plugin_error', obj => { 50 | process.exitCode = 1; 51 | $.log(`${fmt.error(obj.plugin)} failed because ${fmt.error(obj.error)}`); 52 | }) 53 | 54 | .on('tasks_force_object', () => { 55 | $.error('Invalid Tasks!'); 56 | $.log('Custom `tasks` must be an `object`.'); 57 | process.exit(1); 58 | }) 59 | 60 | .on('task_error', (name, msg) => { 61 | $.log(`${fmt.error(name)} failed because ${fmt.error(msg)}`); 62 | }) 63 | 64 | .on('task_start', str => { 65 | $.log(`Starting ${fmt.title(str)}`); 66 | }) 67 | 68 | .on('task_complete', (str, time) => { 69 | const t = formatTime(time); 70 | $.log(`Finished ${fmt.complete(str)} in ${fmt.time(t)}`); 71 | }) 72 | 73 | .on('task_not_found', str => { 74 | $.log(`${fmt.error(str)} not found in Taskfile.`); 75 | process.exit(1); 76 | }) 77 | 78 | .on('serial_error', () => { 79 | process.exitCode = 1; 80 | $.error('Task chain was aborted!'); 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /packages/taskr/lib/task.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const Promise = require('bluebird'); 5 | const wrapp = require('./wrapp'); 6 | const util = require('./utils'); 7 | const boot = require('./boot'); 8 | const $ = require('./fn'); 9 | 10 | const RGX = /[\\|\/]/g; 11 | const co = Promise.coroutine; 12 | const normalize = p.normalize; 13 | const format = p.format; 14 | const parse = p.parse; 15 | const sep = p.sep; 16 | 17 | function Task(ctx) { 18 | // construct shape 19 | this.$ = util; 20 | this.root = ctx.root; 21 | this._ = { files:[], globs:[], prevs:[] }; 22 | // attach parent fns to Task 23 | this.parallel = ctx.parallel.bind(ctx); 24 | this.serial = ctx.serial.bind(ctx); 25 | this.start = ctx.start.bind(ctx); 26 | this.emit = ctx.emit.bind(ctx); 27 | // attach `ctx.plugins` to prototype 28 | for (const k in ctx.plugins) { 29 | this[k] = ctx.plugins[k].bind(this); 30 | } 31 | // return chained methods + shared 32 | return boot(this); 33 | } 34 | 35 | Task.prototype.exec = function (fn, opts, data) { 36 | // cache ref to `ctx.tasks[].data` values 37 | this._ = data; 38 | return fn.call(this, this, opts); 39 | }; 40 | 41 | Task.prototype.run = co(function * (opts, func) { 42 | return yield wrapp(opts, func).call(this); 43 | }); 44 | 45 | Task.prototype.source = co(function * (globs, opts) { 46 | globs = $.flatten($.toArray(globs)); 47 | const files = yield this.$.expand(globs, opts); 48 | 49 | if (globs.length && !files.length) { 50 | this.emit('globs_no_match', globs, opts); 51 | } 52 | 53 | // pre-fetch each file's content 54 | const datas = yield Promise.all(files.map(f => this.$.read(f))); 55 | 56 | // update known globs 57 | this._.globs = globs; 58 | // update known files, as (mod'd) `pathObject`s 59 | this._.files = files.map((el, idx) => { 60 | const obj = parse(el); 61 | return { 62 | dir: normalize(obj.dir), 63 | data: datas[idx], 64 | base: obj.base 65 | }; 66 | }); 67 | }); 68 | 69 | Task.prototype.target = co(function * (dirs, opts) { 70 | dirs = $.flatten($.toArray(dirs)); 71 | opts = opts || {}; 72 | 73 | const files = this._.files; 74 | // using `watcher`? original globs passed as `prevs` 75 | // non-wildcard glob segments that should be trimmed! 76 | const globs = (this._.prevs.length > 0) ? this._.prevs : this._.globs; 77 | 78 | const trims = globs.map(g => { 79 | let seg = g.split(RGX); 80 | const idx = seg.findIndex(str => str.includes('*')); 81 | 82 | if (idx === -1) { 83 | seg.pop(); 84 | } else { 85 | seg = seg.slice(0, idx); 86 | } 87 | 88 | return normalize(seg.join(sep)); 89 | }).sort((a, b) => b.length - a.length); 90 | 91 | const tLength = trims.length; 92 | 93 | return yield Promise.all( 94 | $.flatten( 95 | files.map(obj => dirs.map(d => { 96 | let i = 0; 97 | // clone `pathObject` per target dir 98 | const o = { dir:obj.dir, base:obj.base }; 99 | // replace `source` segments with `target` dir 100 | for (; i < tLength; i++) { 101 | o.dir = o.dir.replace(trims[i], d); 102 | } 103 | // create final filepath & write to it! 104 | return this.$.write(format(o), obj.data, opts); 105 | })) 106 | ) 107 | ); 108 | }); 109 | 110 | module.exports = Task; 111 | -------------------------------------------------------------------------------- /packages/taskr/lib/taskr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const res = require('path').resolve; 4 | const Promise = require('bluebird'); 5 | const Emitter = require('events'); 6 | const wrapp = require('./wrapp'); 7 | const util = require('./utils'); 8 | const Task = require('./task'); 9 | const $ = require('./fn'); 10 | 11 | const co = Promise.coroutine; 12 | 13 | class Taskr extends Emitter { 14 | constructor(opts) { 15 | super(); 16 | 17 | opts = opts || {}; 18 | 19 | const file = opts.file; 20 | const plugins = opts.plugins || []; 21 | const tasks = opts.tasks || file && require(file) || {}; 22 | 23 | // if custom `tasks`, must be object 24 | if (!$.isObject(tasks)) { 25 | this.emit('tasks_force_object'); 26 | return; 27 | } 28 | 29 | this.file = file; 30 | this.root = res(opts.cwd || '.'); 31 | 32 | // construct V8 shapes 33 | this.tasks = {}; 34 | this.plugins = {}; 35 | this.plugNames = []; 36 | 37 | this.start = co(this.start).bind(this); 38 | this.serial = co(this.serial).bind(this); 39 | this.parallel = co(this.parallel).bind(this); 40 | 41 | // nothing to do, stop 42 | if (!file && $.isEmptyObj(tasks)) { 43 | return; 44 | } 45 | 46 | for (const k in tasks) { 47 | if (!(tasks[k].call)) continue; 48 | this.tasks[k] = { 49 | data: { files:[], globs:[], prevs:[] }, 50 | func: co(tasks[k]) 51 | }; 52 | } 53 | 54 | let fn, i = 0; 55 | for (; i < plugins.length; i++) { 56 | if (!plugins[i]) continue; 57 | fn = plugins[i]; 58 | if ($.isObject(fn)) { 59 | this.plugin(fn); 60 | } else if (fn.call) { 61 | fn.call(this, this, util); 62 | } 63 | } 64 | } 65 | 66 | plugin(name, opts, func) { 67 | // accept an object with all val 68 | if ($.isObject(name)) { 69 | opts = name; 70 | name = opts.name; 71 | } 72 | // check if plugin name exists 73 | const nxt = $.valUniq(name, this.plugNames); 74 | // if it did, emit event warning 75 | if (nxt !== name) { 76 | this.emit('plugin_rename', name, nxt); 77 | } 78 | // save / reserve plugin name 79 | this.plugNames.push(nxt); 80 | // safely attach to `plugins` object 81 | this.plugins[nxt] = wrapp(opts, func); 82 | } 83 | 84 | *start(name, opts) { 85 | name = name || 'default'; 86 | opts = Object.assign({ src:null, val:null }, opts); 87 | 88 | const task = this.tasks[name]; 89 | 90 | if (!task) { 91 | return this.emit('task_not_found', name); 92 | } 93 | 94 | // restore previous data, if any 95 | const old = task.data.prevs || []; 96 | // new task ~> reset `data` 97 | task.data = { files:[], globs:[], prevs:old }; 98 | 99 | try { 100 | // get start time 101 | const start = process.hrtime(); 102 | // announce start 103 | this.emit('task_start', name); 104 | // attempt to execute 105 | const val = yield new Task(this).exec(task.func, opts, task.data); 106 | // announce completion 107 | const end = process.hrtime(start); 108 | this.emit('task_complete', name, end); 109 | // send back 110 | return val; 111 | } catch (err) { 112 | this.emit('task_error', name, err.message); 113 | throw err; 114 | } 115 | } 116 | 117 | *parallel(tasks, opts) { 118 | try { 119 | yield Promise.all(tasks.map(t => this.start(t, opts))); 120 | } catch (err) { 121 | // 122 | } 123 | } 124 | 125 | *serial(tasks, opts) { 126 | opts = opts || {}; 127 | try { 128 | return yield Promise.reduce(tasks, (val, str) => { 129 | val && Object.assign(opts, { val }); 130 | return this.start(str, opts); 131 | }, opts.val || null); 132 | } catch (err) { 133 | this.emit('serial_error'); 134 | } 135 | } 136 | } 137 | 138 | module.exports = Taskr; 139 | -------------------------------------------------------------------------------- /packages/taskr/lib/utils/expand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Promise = require('bluebird'); 4 | const glob = Promise.promisify(require('glob')); 5 | const getUniques = require('../fn').getUniques; 6 | const toArray = require('../fn').toArray; 7 | 8 | const isString = val => typeof val === 'string'; 9 | const hasIgnore = val => val.charAt(0) === '!'; 10 | 11 | function validate(arr) { 12 | if (!arr.every(isString)) { 13 | throw new TypeError('All patterns must be strings!'); 14 | } 15 | } 16 | 17 | module.exports = function (patterns, opts) { 18 | opts = opts || {}; 19 | patterns = toArray(patterns); 20 | 21 | try { 22 | validate(patterns); 23 | } catch (err) { 24 | return Promise.reject(err); 25 | } 26 | 27 | let ignore; 28 | const globs = []; 29 | const ignores = toArray(opts.ignore) || []; 30 | 31 | patterns.forEach((pat, i) => { 32 | if (hasIgnore(pat)) { 33 | return; 34 | } 35 | 36 | ignore = ignores.concat( 37 | patterns.slice(i).filter(hasIgnore).map(p => p.slice(1)) 38 | ) 39 | 40 | globs.push({ 41 | pattern: pat, 42 | options: Object.assign(opts, { ignore }) 43 | }); 44 | }); 45 | 46 | return Promise.all( 47 | globs.map(g => glob(g.pattern, g.options)) 48 | ).then(all => getUniques([].concat.apply([], all))); 49 | } 50 | -------------------------------------------------------------------------------- /packages/taskr/lib/utils/find.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const promisify = require('bluebird').promisify; 5 | const glob = promisify(require('glob')); 6 | 7 | /** 8 | * Find a file from a given path 9 | * @param {String} file The filename to find. 10 | * @param {String} dir The directory to begin searching within. 11 | * @yield {String} The file's full path or `null`. 12 | */ 13 | module.exports = function (file, dir) { 14 | return glob(p.resolve(dir || '.', file)).then(arr => arr.length ? p.normalize(arr[0]) : null); 15 | } 16 | -------------------------------------------------------------------------------- /packages/taskr/lib/utils/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const Promise = require("bluebird") 4 | const logging = require("./logging") 5 | 6 | module.exports = Object.assign(logging, { 7 | coroutine: Promise.coroutine, 8 | expand: require("./expand"), 9 | find: require("./find"), 10 | promisify: Promise.promisify, 11 | read: require("./read"), 12 | trace: require("./trace"), 13 | write: require("./write") 14 | }) 15 | -------------------------------------------------------------------------------- /packages/taskr/lib/utils/logging.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @todo 5 | * - use 'fmt' object definitions 6 | * - use es2015 7 | */ 8 | 9 | const clorox = require('clorox'); 10 | const homedir = require('os').homedir; 11 | const getTime = require('../fn').getTime; 12 | 13 | /** 14 | * Apply args to the `console[method]` & Add a date stamp. 15 | * Bind `this` to an object with the following options: 16 | * 17 | * @param {String} args.date The color string to use for the date 18 | * @param {String} args.method The `console` method to use 19 | * @param {String} args.custom The custom styling to append to args 20 | */ 21 | function stamp() { 22 | let i = 0; 23 | const args = new Array(arguments.length); 24 | // i is always valid index 25 | for (; i < args.length; ++i) { 26 | args[i] = arguments[i]; 27 | } 28 | 29 | // print the curr time. 30 | process.stdout.write(clorox[this.color](getTime()) + ' '); 31 | 32 | // apply arguments to `console` method 33 | console[this.method].apply(console, (this.custom ? [this.custom].concat(args) : args)); 34 | } 35 | 36 | /** 37 | * Logging Utilities 38 | */ 39 | 40 | function log() { 41 | stamp.apply({method: 'log', color: 'magenta'}, arguments); 42 | return this; 43 | } 44 | 45 | function error() { 46 | stamp.apply({method: 'error', color: 'red'}, arguments); 47 | return this; 48 | } 49 | 50 | function alert() { 51 | if (process.env.VERBOSE) { 52 | stamp.apply({ 53 | custom: clorox.yellow.bold("%s"), 54 | color: 'yellow', 55 | method: 'log' 56 | }, arguments); 57 | } 58 | return this; 59 | } 60 | 61 | module.exports = { alert, error, log }; 62 | -------------------------------------------------------------------------------- /packages/taskr/lib/utils/read.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const Promise = require('bluebird'); 5 | const stat = Promise.promisify(fs.stat); 6 | const read = Promise.promisify(fs.readFile); 7 | 8 | /** 9 | * Return a file's contents. Will not read directory! 10 | * @param {String} file The file's path. 11 | * @param {Object|String} opts See `fs.readFile`. 12 | * @yield {Buffer|String} 13 | */ 14 | module.exports = Promise.coroutine(function * (file, opts) { 15 | const s = yield stat(file) 16 | return s.isFile() ? yield read(file, opts) : null 17 | }); 18 | -------------------------------------------------------------------------------- /packages/taskr/lib/utils/trace.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const extractPath = /\s+at.*(?:\(|\s)(.*)\)?/; 4 | const isPath = /^(?:(?:(?:node|(?:internal\/[\w/]*)?\w+)\.js:\d+:\d+)|native)/; 5 | 6 | module.exports = function (stack) { 7 | return stack.replace(/\\/g, '/').split('\n').filter(x => { 8 | const matches = x.match(extractPath); 9 | return matches === null || !matches[1] || !isPath.test(matches[1]); 10 | }).filter(x => x.trim() !== '').join('\n'); 11 | } 12 | -------------------------------------------------------------------------------- /packages/taskr/lib/utils/write.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const mkdir = require('mk-dirs'); 5 | const Promise = require('bluebird'); 6 | const write = Promise.promisify(require('fs').writeFile); 7 | 8 | /** 9 | * Write to a file with given data. 10 | * Creates ancestor directories if needed. 11 | * @param {String} file The full file's path. 12 | * @param {String} data The data to write. 13 | * @param {Object} opts See `fs.writeFile`. 14 | */ 15 | module.exports = Promise.coroutine(function * (file, data, opts) { 16 | try { 17 | file = p.normalize(file); 18 | yield mkdir(p.dirname(file)); 19 | yield write(file, data, opts); 20 | } catch (_) {} 21 | }); 22 | -------------------------------------------------------------------------------- /packages/taskr/lib/wrapp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Promise = require('bluebird'); 4 | const co = Promise.coroutine 5 | 6 | module.exports = function (opts, func) { 7 | // assign against defaults 8 | opts = Object.assign({ every:true, files:true }, opts); 9 | func = opts.func || func; 10 | 11 | return co(function * (o) { 12 | o = o || {}; 13 | const args = []; 14 | args.push.apply(args, arguments) && args.shift(); 15 | // grab alias to chosen source type 16 | const arr = this._[opts.files ? 'files' : 'globs']; 17 | // wrapper pass all arguments to plugin func 18 | const run = s => co(func).apply(this, [s, o].concat(args)); 19 | // loop thru EACH if `every`, else send full source array 20 | yield (opts.every ? Promise.all(arr.map(run)) : run(arr)); 21 | // send back instance allow chain 22 | return this; 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /packages/taskr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "taskr", 3 | "version": "1.1.0", 4 | "description": "Generator & Coroutine-based task runner. Fasten your seatbelt.", 5 | "homepage": "https://github.com/lukeed/taskr", 6 | "repository": "lukeed/taskr", 7 | "license": "MIT", 8 | "author": { 9 | "name": "Luke Edwards", 10 | "email": "luke@lukeed.com", 11 | "url": "https://lukeed.com" 12 | }, 13 | "types": "taskr.d.ts", 14 | "main": "lib/taskr.js", 15 | "bin": "cli.js", 16 | "files": [ 17 | "lib", 18 | "cli.js", 19 | "taskr.d.ts" 20 | ], 21 | "dependencies": { 22 | "bluebird": "^3.5.0", 23 | "clorox": "^1.0.1", 24 | "glob": "^7.1.2", 25 | "mk-dirs": "^1.0.0", 26 | "mri": "^1.1.0", 27 | "tinydate": "^1.0.0" 28 | }, 29 | "devDependencies": { 30 | "rimraf": "^2.6.1" 31 | }, 32 | "scripts": { 33 | "test": "tape test/*.js | tap-spec" 34 | }, 35 | "keywords": [ 36 | "cli", 37 | "task", 38 | "build", 39 | "async", 40 | "await", 41 | "minify", 42 | "uglify", 43 | "promise", 44 | "pipeline", 45 | "generator", 46 | "coroutine", 47 | "automation", 48 | "task runner", 49 | "build system" 50 | ], 51 | "engines": { 52 | "node": ">= 4.6" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/taskr/taskr.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace taskr { 2 | export interface Instance { 3 | /** 4 | * Start a Task by its name; may also pass initial values. 5 | * Can return anything the Task is designed to. 6 | */ 7 | start(task: string, options?: object), 8 | 9 | /** 10 | * Run a group of tasks simultaneously. Cascading is disabled 11 | */ 12 | parallel(tasks: Array, options?: object): IterableIterator, 13 | 14 | /** 15 | * Run a group of tasks sequentially. Cascading is enabled 16 | */ 17 | serial(tasks: Array, options?: object): IterableIterator 18 | 19 | /** 20 | * Perform local plugin 21 | */ 22 | plugin(name: string, options: any, plugin?: (files: any, options?: any) => Iterator) 23 | } 24 | 25 | export interface Utils { 26 | /** 27 | * Print to console with timestamp and alert coloring 28 | */ 29 | alert(...msg: Array): void, 30 | 31 | /** 32 | * Alias for `Bluebird.coroutine`. 33 | */ 34 | coroutine(generator: GeneratorFunction), 35 | 36 | /** 37 | * Print to console with timestamp and error coloring. 38 | */ 39 | error(...msg: Array): void, 40 | 41 | /** 42 | * Get all filepaths that match the glob pattern constraints. 43 | */ 44 | expand(globs: string | Array, options?: object) 45 | 46 | /** 47 | * Find a complete filepath from a given path, or optional directory. 48 | */ 49 | find(filename: string, dir: string) 50 | 51 | /** 52 | * Print to console with timestamp and normal coloring. 53 | */ 54 | log(...msg: Array): void 55 | 56 | /** 57 | * Alias for `Bluebird.promisify`. 58 | */ 59 | promisify(fn: Function): Function 60 | 61 | /** 62 | * Get a file's contents. Ignores directory paths. 63 | */ 64 | read(filepath: string, options?: object | string): IterableIterator 65 | 66 | /** 67 | * Parse and prettify an Error's stack. 68 | */ 69 | trace(stack: string): string 70 | 71 | /** 72 | * Write given data to a filepath. Will create directories as needed. 73 | */ 74 | write(filepath: string, data: any , options?: object) 75 | } 76 | 77 | interface File { 78 | dir: string, 79 | base: string, 80 | data: any 81 | } 82 | 83 | type InnerState = { 84 | /** 85 | * The Task's active files. 86 | * Each object contains a dir and base key from its pathObject and 87 | * maintains the file's Buffer contents as a data key. 88 | */ 89 | files: Array 90 | 91 | /** 92 | * The Task's glob patterns, from task.source(). Used to populate `task._.files`. 93 | */ 94 | globs: Array 95 | 96 | /** 97 | * The Task's last-known (aka, outdated) set of glob patterns. Used only for `taskr-watch`. 98 | */ 99 | prevs: Array 100 | } 101 | 102 | export interface Task extends Instance { 103 | /** 104 | * The directory wherein taskfile.js resides, 105 | * now considered the root. Also accessible within plugins 106 | */ 107 | root: string 108 | 109 | /** 110 | * The Task's internal state, populated by task.source(). 111 | * Also accessible within plugins. 112 | */ 113 | _: InnerState 114 | 115 | /** 116 | * A collection of utility helpers to make life easy. 117 | */ 118 | $: Utils 119 | 120 | source(globs: Array | string, options?: object) 121 | 122 | /** 123 | * Send output to certain destination(s) 124 | */ 125 | target(dirs: Array | string, options?: object) 126 | 127 | /** 128 | * Perform an inline plugin. 129 | */ 130 | run(options: any, plugin?: (files: any, options?: any) => Iterator) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/alt/.gitignore: -------------------------------------------------------------------------------- 1 | # include our fake node_modules in the repo 2 | !node_modules 3 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/alt/local-plugin.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | module.exports = function (task, utils) { 4 | const self = this 5 | task.plugin("localPlugin", {every: 0}, function * (_, opts) { 6 | const t = opts.t 7 | t.true("root" in task && "emit" in task && "tasks" in task, "plugin creator receives `Taskr` instance") 8 | t.true("expand" in utils && "find" in utils && "write" in utils, "plugin creator receives `utils` helpers object") 9 | t.deepEqual(task, self, "plugin creator context bound to `task` instance") 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/alt/node_modules/fly-plugin1/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | this.plugin('plugOne', {}, function * (d, o) { 5 | const data = d.data.toString().split('').reverse().join(''); 6 | d.data = new Buffer(data); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/alt/node_modules/taskr-plugin-2/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | every: 0, 5 | name: 'plugTwo', 6 | *func(arr, o) { 7 | for (let file of arr) { 8 | file.data = new Buffer(file.data.toString().split('').reverse().join('')); 9 | } 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/alt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "fly-plugin1": "*", 4 | "taskr-plugin-2": "*", 5 | "fly-no-exist": "*", 6 | "@taskr/foobar": "*", 7 | "@demo/fly-thing": "*", 8 | "@foo-bar/fly-fake": "*", 9 | "@foo/ignore": "*" 10 | }, 11 | "devDependencies": { 12 | "fake": "*" 13 | }, 14 | "peerDependencies": { 15 | "peer": "*" 16 | }, 17 | "taskr": { 18 | "requires": [ 19 | "./local-plugin.js" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/alt/sub/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fake-sub-pkg", 3 | "dependencies": { 4 | }, 5 | "taskr": { 6 | "pkg": "../" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/alt/taskfile.js: -------------------------------------------------------------------------------- 1 | exports.a = function * () {}; 2 | // export async function b () {} 3 | // export function* c () {} 4 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/bar.txt: -------------------------------------------------------------------------------- 1 | bar baz 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/foo.txt: -------------------------------------------------------------------------------- 1 | foo bar 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/foo.txt.map: -------------------------------------------------------------------------------- 1 | "{\"version\":3,\"sources\":[\"foo.txt\"],\"names\":[],\"mappings\":\"AAAA;AACA\",\"file\":\"foo.txt\"}" -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/one/one.md: -------------------------------------------------------------------------------- 1 | # FIRST LEVEL 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/one/two/two-1.md: -------------------------------------------------------------------------------- 1 | # SECOND LEVEL, FIRST FILE 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/one/two/two-2.md: -------------------------------------------------------------------------------- 1 | # SECOND LEVEL, SECOND FILE 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/taskfile.js: -------------------------------------------------------------------------------- 1 | exports.taskA = function * () { 2 | /** @desc This is task-a"s description */ 3 | } 4 | 5 | exports.taskB = function * () { 6 | /** @desc This is task-b"s description */ 7 | } 8 | 9 | exports.taskC = function * () { 10 | /** @desc This is task-c"s description */ 11 | } 12 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/utils/a.js: -------------------------------------------------------------------------------- 1 | const pi = 3.14 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/utils/b.js: -------------------------------------------------------------------------------- 1 | const pi2 = 6.28 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/utils/sample.babel.js: -------------------------------------------------------------------------------- 1 | export function getSecret() { 2 | return 42 3 | } 4 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/utils/sub/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukeed/taskr/7a50e6e8c1fb8c01c0020d9f0e4d8897ccc4cc28/packages/taskr/test/fixtures/utils/sub/.gitkeep -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/utils/taskfile.js: -------------------------------------------------------------------------------- 1 | // 2 | -------------------------------------------------------------------------------- /packages/taskr/test/fixtures/utils/z.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hi 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/taskr/test/fn.js: -------------------------------------------------------------------------------- 1 | /* eslint no-array-constructor:0,no-new-object:0,no-new-func:0,prefer-arrow-callback:0 */ 2 | "use strict" 3 | 4 | const test = require("tape") 5 | const $ = require("../lib/fn") 6 | 7 | test("fn.isObject", t => { 8 | const fn = $.isObject 9 | 10 | t.true(fn({}), `true: {}`) 11 | t.true(fn({a: "a"}), `true: {a: "a"}`) 12 | t.true(fn(new Object()), `true: new Object`) 13 | t.true(fn(Object.assign({})), `true: Object.assign({})`) 14 | 15 | t.false(fn(), `false: blank`) 16 | t.false(fn([]), `false: []`) 17 | t.false(fn(null), `false: null`) 18 | t.false(fn(undefined), `false: undefined`) 19 | t.false(fn(15), `false: 15`) 20 | t.false(fn("Array"), `false: "Array"`) 21 | t.false(fn("Object"), `false: "Object"`) 22 | t.false(fn(function () {}), `false: function () {}`) 23 | t.false(fn(new Function()), `false: new Function`) 24 | t.false(fn(new Date()), `false: new Date`) 25 | t.false(fn(true), `false: true`) 26 | t.false(fn(false), `false: false`) 27 | 28 | t.end() 29 | }) 30 | 31 | test("fn.isEmptyObj", t => { 32 | const fn = $.isEmptyObj 33 | 34 | const o1 = {} 35 | const o2 = {} 36 | 37 | // enumerable: false ~~> default 38 | Object.defineProperty(o1, "key", {value: "any"}) 39 | 40 | Object.defineProperty(o2, "key", { 41 | enumerable: true, 42 | value: "any" 43 | }) 44 | 45 | t.true(fn({}), `true: {}`) 46 | t.true(fn(new Object()), `true: new Object()`) 47 | t.false(fn({a: 1}), `false: {a: 1}`) 48 | t.false(fn([]), `false: []`) 49 | t.false(fn(new Function()), `false: new Function()`) 50 | t.false(fn(new Date()), `false: new Date()`) 51 | 52 | t.true(fn(o1), "true: valued object with `{enumerable: false}`") 53 | t.false(fn(o2), "false: valued object with `{enumerable: true}`") 54 | 55 | t.end() 56 | }) 57 | 58 | test("fn.toArray", t => { 59 | const fn = $.toArray 60 | t.deepEqual(fn([]), [], "keeps `[]` as is") 61 | t.deepEqual(fn(null), [], "converts `null` to empty array") 62 | t.deepEqual(fn(undefined), [], "converts `undefined` to empty array") 63 | t.deepEqual(fn(-1), [-1], "converts `-1` to `[-1]`") 64 | t.deepEqual(fn(0), [0], "converts `0` to `[0]`") 65 | t.deepEqual(fn(1), [1], "converts `1` to `[1]`") 66 | t.deepEqual(fn("foo"), ["foo"]) 67 | t.deepEqual(fn(["foo"]), ["foo"]) 68 | t.end() 69 | }) 70 | 71 | test("fn.formatTime", t => { 72 | const fn = $.formatTime 73 | t.equal(fn([0, -1e6]), "-1ms", "accepts negative numbers") 74 | t.equal(fn([0, 0]), "0ms", "accepts zero") 75 | t.equal(fn([0, 0.999e9]), "999ms", "accepts positive number") 76 | t.equal(fn([1, 0]), "1.00s", "simple seconds") 77 | t.equal(fn([2, 2.2e7]), "2.02s", "converts large, quirky number") 78 | t.end() 79 | }) 80 | 81 | test("fn.getTime", t => { 82 | const out = $.getTime() 83 | t.equal(typeof out, "string", "returns a string") 84 | t.equal(out.split(":").length, 3, "has 3 segments") 85 | t.equal(out.length, 10, "is always 10 characters long") 86 | t.end() 87 | }) 88 | 89 | test("fn.valUniq", t => { 90 | const fn = $.valUniq 91 | const arr = ["a", "b", "a1", "a2", "a3"] 92 | 93 | const out1 = fn("a", arr) 94 | t.equal(typeof out1, "string", "returns a string") 95 | t.equal(out1, "a4", "loops increment multiple times") 96 | 97 | const out2 = fn("b", arr) 98 | t.equal(out2, "b1", "increments once") 99 | 100 | const out3 = fn("c", arr) 101 | t.equal(out3, "c", "does nothing if was unique") 102 | 103 | t.end() 104 | }) 105 | 106 | test("fn.getUniques", t => { 107 | const fn = $.getUniques 108 | t.deepEqual(fn([1, 2, 2, 3, 1, 2, 4]), [1, 2, 3, 4]) 109 | t.deepEqual(fn(["a", "a", "b", "a", "c", "a", "d"]), ["a", "b", "c", "d"]) 110 | t.end() 111 | }) 112 | 113 | test("fn.flatten", t => { 114 | const fn = $.flatten 115 | t.deepEqual(fn(["a", "b", ["c"], "d", ["e"]]), ["a", "b", "c", "d", "e"], "flatten nested arrays") 116 | t.deepEqual(fn([[["a", ["b"]]], ["c"]]), ["a", "b", "c"], "flatten deeply nested arrays") 117 | t.end() 118 | }) 119 | -------------------------------------------------------------------------------- /packages/taskr/test/helpers/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const bb = require("bluebird") 4 | const stat = bb.promisify(require("fs").stat) 5 | const rimraf = bb.promisify(require("rimraf")) 6 | const toArray = require("../../lib/fn").toArray 7 | 8 | /** 9 | * `@taskr/clear` stub 10 | * serves as test-util only 11 | */ 12 | exports.del = bb.coroutine(function * (src) { 13 | yield bb.all(toArray(src).map(g => rimraf(g))) 14 | }) 15 | 16 | /** 17 | * Check if a File has given rights 18 | * @param {String} file A file path 19 | * @param {Number} mode A desired permission. 20 | * @return {Boolean} 21 | */ 22 | exports.isMode = bb.coroutine(function * (file, mode) { 23 | if (process.platform === "win32") { 24 | return true 25 | } 26 | const info = yield stat(file) 27 | return info.isFile() ? Number((info.mode & 0o777).toString(8)) === mode : false 28 | }) 29 | -------------------------------------------------------------------------------- /packages/taskr/test/reporter.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const E = require("events") 4 | const test = require("tape") 5 | 6 | const reporter = require("../lib/reporter") 7 | 8 | class Emit extends E { 9 | constructor(t) { 10 | super() 11 | this.ok = t.ok 12 | } 13 | 14 | on(e) { 15 | this.ok(true, `listens to the "${e}" event`) 16 | return this 17 | } 18 | } 19 | 20 | test("Taskr.reporter", t => { 21 | const all = [ 22 | "fake_event", 23 | "task_run", 24 | "taskfile_not_found", 25 | "task_watch", 26 | "task_watch_event", 27 | "globs_no_match", 28 | "plugin_load", 29 | "plugin_load_error", 30 | "plugin_error", 31 | "plugin_warning", 32 | "plugin_rename", 33 | "tasks_force_object", 34 | "task_error", 35 | "task_start", 36 | "task_complete", 37 | "task_not_found", 38 | "serial_error" 39 | ] 40 | 41 | t.plan(all.length + 1) 42 | 43 | const ctx = new Emit(t) 44 | const rep = reporter.call(ctx) 45 | 46 | t.deepEqual(rep, ctx, "returns the bound object") 47 | 48 | all.forEach(e => ctx.emit(e)) 49 | 50 | t.ok(true, "the `fake_event` was ignored") 51 | }) 52 | -------------------------------------------------------------------------------- /packages/taskr/test/wrapp.js: -------------------------------------------------------------------------------- 1 | const test = require("tape") 2 | const wrapp = require("../lib/wrapp") 3 | const co = require("bluebird").coroutine 4 | 5 | test("wrapp", co(function * (t) { 6 | t.plan(12) 7 | const globs = ['baz'] 8 | const files = ['foo', 'bar'] 9 | const ctx = {_: {files, globs}} 10 | 11 | const foo = function * (src, opt) { 12 | t.true(files.indexOf(src) > -1, "loops each file entry by default") 13 | t.equal(opt, "hi", "can also receive options") 14 | } 15 | 16 | const bar = function * (src) { 17 | t.deepEqual(this, ctx, "internal context is preserved") 18 | t.deepEqual(src, globs, "receive all globs; no loop") 19 | } 20 | 21 | const wrapped = wrapp({}, foo) 22 | 23 | t.equal(typeof wrapped, "function", "returns a function") 24 | t.notEqual(wrapped, foo, "is not the original function") 25 | 26 | try { 27 | yield wrapped() 28 | } catch (err) { 29 | t.true(/Cannot read property/.test(err.toString()), "wrapped function is unbound") 30 | } 31 | 32 | // defaults 33 | const out1 = yield wrapped.apply(ctx, ['hi']) 34 | t.pass("does not throw if binds to context") 35 | t.deepEqual(out1, ctx, "returns the new context") 36 | 37 | // modified opts 38 | const out2 = yield wrapp({every: false, files: false}, bar).apply(ctx) 39 | t.deepEqual(out2, ctx, "returns the new context") 40 | })) 41 | -------------------------------------------------------------------------------- /packages/typescript/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ts = require('typescript'); 4 | const extname = require('path').extname; 5 | 6 | module.exports = function (task) { 7 | task.plugin('typescript', { every:true }, function * (file, options) { 8 | options = options || {}; 9 | const opts = { fileName:file.base }; 10 | 11 | // "steal" transpiler options from `options` 12 | if (options.moduleName) { 13 | opts.moduleName = options.moduleName; 14 | } 15 | 16 | if (options.renamedDependencies) { 17 | opts.renamedDependencies = options.renamedDependencies; 18 | } 19 | 20 | // everything else is `compilerOptions` 21 | opts.compilerOptions = options.compilerOptions || options; 22 | 23 | // modify extension 24 | const ext = new RegExp(extname(file.base).replace('.', '\\.') + '$', 'i'); 25 | file.base = file.base.replace(ext, '.js'); 26 | 27 | // compile output 28 | const result = ts.transpileModule(file.data.toString(), opts); 29 | 30 | if (opts.compilerOptions.sourceMap && result.sourceMapText) { 31 | // add sourcemap to `files` array 32 | this._.files.push({ 33 | dir: file.dir, 34 | base: `${file.base}.map`, 35 | data: new Buffer(JSON.stringify(result.sourceMapText)) 36 | }); 37 | } 38 | 39 | // update file's data 40 | file.data = new Buffer(result.outputText); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /packages/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/typescript", 3 | "version": "1.1.0", 4 | "description": "Compile Typescript with Taskr.", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "scripts": { 9 | "test": "tape test/*.js | tap-spec" 10 | }, 11 | "author": { 12 | "name": "Luke Edwards", 13 | "email": "luke@lukeed.com", 14 | "url": "https://lukeed.com" 15 | }, 16 | "dependencies": { 17 | "typescript": "^2.3.0" 18 | }, 19 | "devDependencies": { 20 | "@taskr/clear": "^1.1.0", 21 | "taskr": "^1.1.0" 22 | }, 23 | "engines": { 24 | "node": ">= 4.6" 25 | }, 26 | "keywords": [ 27 | "taskr", 28 | "taskr-plugin", 29 | "typescript", 30 | "compile" 31 | ], 32 | "publishConfig": { 33 | "access": "public" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/typescript/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/typescript [![npm](https://img.shields.io/npm/v/@taskr/typescript.svg)](https://npmjs.org/package/@taskr/typescript) 2 | 3 | > Compile [Typescript](https://github.com/Microsoft/TypeScript) with [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/typescript 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | exports.scripts = function * (task) { 15 | yield task.source('src/**/*.ts').typescript({ 16 | jsx: 'React', 17 | target: 'ES5', 18 | sourceMap: true, 19 | removeComments: true 20 | }).target('dist/js'); 21 | } 22 | ``` 23 | 24 | ## API 25 | 26 | ### .typescript(options) 27 | 28 | Unlike most plugins, this plugin provides access to all of Typescript's [Transpile options](https://github.com/Microsoft/TypeScript/blob/master/src/services/transpile.ts#L2-L8). However, _for the sake of simplicity_, this plugin **flattens** all `compilerOptions` keys into the same object. In other words, we **assume** that you're providing `compilerOptions`, unless the given key matches the name of another `TranspileOption`. 29 | 30 | > Check out Typescript's [Compile Options](https://www.typescriptlang.org/docs/handbook/compiler-options.html) to see all Compiler options. 31 | 32 | For example: 33 | 34 | ```js 35 | task.source('...').typescript({ 36 | moduleName: 'FooBar', 37 | compilerOptions: { 38 | module: 'System', 39 | sourceMap: true 40 | } 41 | }).target('...'); 42 | 43 | // can be written as: 44 | 45 | task.source('...').typescript({ 46 | moduleName: 'FooBar', 47 | module: 'System', 48 | sourceMap: true 49 | }).target('...'); 50 | ``` 51 | 52 | Notice that `compilerOptions` is no longer defined, and instead, its children (`module`, `sourceMap`, etc) are defined _alongside_ `moduleName`! 53 | 54 | > **Note:** The first example (aka, using `compilerOptions`) will still work. 55 | 56 | ## Support 57 | 58 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 59 | 60 | Please be sure to specify that you are using `@taskr/typescript`. 61 | 62 | ## License 63 | 64 | MIT © [Luke Edwards](https://lukeed.com) 65 | -------------------------------------------------------------------------------- /packages/typescript/test/fixtures/app.ts: -------------------------------------------------------------------------------- 1 | export default class App { 2 | constructor(public str: string) { } 3 | 4 | greet() { 5 | /* This is a comment that should be removed */ 6 | return this.str; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/typescript/test/index.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const Taskr = require('taskr'); 3 | const test = require('tape'); 4 | 5 | const dir = join(__dirname, 'fixtures'); 6 | const tmp = join(__dirname, '.tmp'); 7 | 8 | test('@taskr/typescript', t => { 9 | t.plan(16); 10 | 11 | const taskr = new Taskr({ 12 | plugins: [ 13 | require('../'), 14 | require('@taskr/clear') 15 | ], 16 | tasks: { 17 | *a(f) { 18 | yield f.source(`${dir}/*.ts`).typescript().target(tmp); 19 | const arr = yield f.$.expand(`${tmp}/*.js`); 20 | t.equal(arr.length, 1, 'converts to `.js` extension'); 21 | const str = yield f.$.read(`${tmp}/app.js`, 'utf8'); 22 | t.ok(/var App/.test(str), 'compiles to ES3 JavaScript'); 23 | yield f.clear(tmp); 24 | }, 25 | *b(f) { 26 | yield f.source(`${dir}/*.ts`).typescript({ removeComments: true }).target(tmp); 27 | const str = yield f.$.read(`${tmp}/app.js`, 'utf8'); 28 | t.false(/This is a comment/.test(str), 'remove comments if given option'); 29 | yield f.clear(tmp); 30 | }, 31 | *c(f) { 32 | yield f.source(`${dir}/*.ts`).typescript({ inlineSourceMap: true }).target(tmp); 33 | const arr = yield f.$.expand(`${tmp}/*`); 34 | t.equal(arr.length, 1, 'creates only 1 file'); 35 | const str = yield f.$.read(`${tmp}/app.js`, 'utf8'); 36 | t.ok(/sourceMappingURL/.test(str), 'via `inlineSourceMap`; append `sourceMappingURL` comment'); 37 | t.ok(/data:application\/json/.test(str), 'via `inlineSourceMap`; embed inline sourcemap'); 38 | }, 39 | *d(f) { 40 | yield f.source(`${dir}/*.ts`).typescript({ sourceMap: true }).target(tmp); 41 | const arr = yield f.$.expand(`${tmp}/*`); 42 | t.equal(arr.length, 2, 'creates 2 files'); 43 | const str = yield f.$.read(`${tmp}/app.js`, 'utf8'); 44 | t.ok(/sourceMappingURL/.test(str), 'via `sourceMap`; append `sourceMappingURL` comment'); 45 | t.ok(/app.js.map/.test(str), 'via `sourceMap`; embed link to external sourcemap'); 46 | yield f.clear(tmp); 47 | }, 48 | *e(f) { 49 | yield f.source(`${dir}/*.ts`).typescript({ 50 | moduleName: 'FooBar', 51 | module: 'System', 52 | target: 'ES2015' 53 | }).target(tmp); 54 | const str = yield f.$.read(`${tmp}/app.js`, 'utf8'); 55 | t.ok(/FooBar/.test(str), 'listen to `moduleName` option'); 56 | t.ok(/System.register/.test(str), 'listen to `compilerOptions.module` option'); 57 | t.ok(/App = class App/.test(str), 'listen to `compilerOptions.target` option'); 58 | yield f.clear(tmp); 59 | }, 60 | *f(f) { 61 | yield f.source(`${dir}/*.ts`).typescript({ 62 | moduleName: 'FooBar', 63 | compilerOptions: { 64 | module: 'System', 65 | target: 'ES2015' 66 | } 67 | }).target(tmp); 68 | const str = yield f.$.read(`${tmp}/app.js`, 'utf8'); 69 | t.ok(/FooBar/.test(str), 'listen to `moduleName` option'); 70 | t.ok(/System.register/.test(str), 'listen to `compilerOptions.module` option'); 71 | t.ok(/App = class App/.test(str), 'listen to `compilerOptions.target` option'); 72 | yield f.clear(tmp); 73 | } 74 | } 75 | }); 76 | 77 | t.ok('typescript' in taskr.plugins, 'add the `typescript` plugin'); 78 | 79 | taskr.serial(['a', 'b', 'c', 'd', 'e', 'f']); 80 | }); 81 | -------------------------------------------------------------------------------- /packages/uglify/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const extname = require('path').extname; 4 | const minify = require('uglify-js').minify; 5 | 6 | module.exports = function (task) { 7 | task.plugin('uglify', {}, function * (file, opts) { 8 | opts = Object.assign({}, opts, { fromString:true }); 9 | 10 | const ext = extname(file.base); 11 | const rgx = new RegExp(`\\${ext}$`, 'i'); 12 | // replace extension with `.js` 13 | file.base = file.base.replace(rgx, '.js'); 14 | 15 | const out = minify(file.data.toString(), opts); 16 | 17 | // write output 18 | file.data = new Buffer(out.code); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/uglify/next.js: -------------------------------------------------------------------------------- 1 | /** 2 | * For Uglify v3 3 | * --- currently sourceMaps not supported: 4 | * Error: `sourceMap` is not a supported option 5 | */ 6 | 7 | 'use strict'; 8 | 9 | const extn = require('path').extname; 10 | const minify = require('uglify-js').minify; 11 | 12 | const errMsg = obj => `${obj.message} in \`${obj.filename}\` on line ${obj.line}`; 13 | 14 | module.exports = function (task) { 15 | task.plugin('uglify', {}, function * (file, opts) { 16 | const ext = extn(file.base); 17 | const rgx = new RegExp(`\\${ext}$`, 'i'); 18 | const filename = file.base.replace(rgx, '.js'); 19 | 20 | let isInline = false; 21 | let isMapping = false; 22 | 23 | opts = Object.assign({ sourceMap:isMapping }, opts); 24 | 25 | if (opts.sourceMap === 'inline') { 26 | isInline = true; 27 | opts.sourceMap = { url:'inline' }; 28 | } else if (opts.sourceMap !== isMapping) { 29 | isMapping = true; 30 | const url = `${filename}.map`; 31 | opts.sourceMap = Object.assign({ filename, url }, opts); 32 | // check again... just in case 33 | if (opts.sourceMap.url === 'inline') { 34 | isInline = true; 35 | } 36 | } 37 | 38 | const res = minify({ [file.base]:file.data.toString() }, opts); 39 | 40 | console.log('THIS IS RES', res); 41 | 42 | // check for errors 43 | if (res.error) { 44 | return task.emit('plugin_error', { 45 | plugin: '@taskr/uglify', 46 | error: errMsg(res.error) 47 | }); 48 | } 49 | 50 | file.base = filename; // ensure always `.js` 51 | 52 | file.data = new Buffer(res.code); // write output 53 | 54 | // handle external sourcemaps (only) 55 | if (res.map !== void 0 && isMapping && !isInline) { 56 | // Uglify 3.0 will auto-write a comment link 57 | console.log('HAS MAP', res.map); 58 | } 59 | }); 60 | }; 61 | -------------------------------------------------------------------------------- /packages/uglify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/uglify", 3 | "version": "1.1.0", 4 | "description": "Uglify plugin for Taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "scripts": { 9 | "test": "tape test/*.js | tap-spec" 10 | }, 11 | "author": { 12 | "name": "Luke Edwards", 13 | "email": "luke@lukeed.com", 14 | "url": "https://lukeed.com" 15 | }, 16 | "keywords": [ 17 | "taskr", 18 | "taskr-plugin", 19 | "uglify" 20 | ], 21 | "dependencies": { 22 | "uglify-js": "^2.8.0" 23 | }, 24 | "devDependencies": { 25 | "@taskr/clear": "^1.1.0", 26 | "taskr": "^1.1.0" 27 | }, 28 | "engines": { 29 | "node": ">= 4.6" 30 | }, 31 | "publishConfig": { 32 | "access": "public" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/uglify/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/uglify [![npm](https://img.shields.io/npm/v/@taskr/uglify.svg)](https://npmjs.org/package/@taskr/uglify) 2 | 3 | > [UglifyJS](https://github.com/mishoo/UglifyJS2) plugin for [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/uglify 9 | ``` 10 | 11 | ## API 12 | 13 | ### .uglify(options) 14 | 15 | > Check out the [UglifyJS documentation](https://github.com/mishoo/UglifyJS2#usage) to see the available options. 16 | 17 | ## Usage 18 | 19 | ```js 20 | exports.build = function * (task) { 21 | yield task.source('src/**/*.uglify') 22 | .uglify({ 23 | compress: { 24 | drop_console: true, 25 | join_vars: true 26 | } 27 | }) 28 | .target('dist'); 29 | } 30 | ``` 31 | 32 | ## Support 33 | 34 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 35 | 36 | Please be sure to specify that you are using `@taskr/uglify`. 37 | 38 | ## License 39 | 40 | MIT © [Luke Edwards](https://lukeed.com) 41 | -------------------------------------------------------------------------------- /packages/uglify/test/fixtures/a.js: -------------------------------------------------------------------------------- 1 | if (true) { 2 | console.log('this is a') 3 | } 4 | -------------------------------------------------------------------------------- /packages/uglify/test/fixtures/sub/b.js: -------------------------------------------------------------------------------- 1 | if (!true) { 2 | console.log('howdy partner') 3 | } 4 | -------------------------------------------------------------------------------- /packages/uglify/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const join = require('path').join; 4 | const Taskr = require('taskr'); 5 | const test = require('tape'); 6 | 7 | const dir = join(__dirname, 'fixtures'); 8 | const tmp = join(__dirname, 'tmp'); 9 | 10 | test('@taskr/uglify', t => { 11 | t.plan(4); 12 | 13 | const taskr = new Taskr({ 14 | plugins: [ 15 | require('../'), 16 | require('@taskr/clear') 17 | ], 18 | tasks: { 19 | * foo(f) { 20 | const src = `${dir}/**/*.js`; 21 | t.ok('uglify' in taskr.plugins, 'attach `uglify()` plugin to taskr'); 22 | 23 | yield f.source(src).uglify().target(tmp); 24 | const str1 = yield f.$.read(`${tmp}/a.js`, 'utf8'); 25 | t.equal(str1, `console.log("this is a");`, 'apply `uglify-js` to content'); 26 | const arr1 = yield f.$.expand(`${tmp}/**/*.js`); 27 | t.equal(arr1.length, 2, 'keep all files'); 28 | 29 | /* eslint camelcase:0 */ 30 | yield f.source(src).uglify({compress: { drop_console:true }}).target(tmp); 31 | const str2 = yield f.$.read(`${tmp}/a.js`, 'utf8'); 32 | t.equal(str2, '', 'accept custom config (`compress` options)'); 33 | 34 | yield f.clear(tmp); 35 | } 36 | } 37 | }); 38 | 39 | taskr.start('foo'); 40 | }); 41 | -------------------------------------------------------------------------------- /packages/uglify/test/next.js: -------------------------------------------------------------------------------- 1 | // for Uglify v3.x 2 | 3 | // 'use strict'; 4 | 5 | // const join = require('path').join; 6 | // const Taskr = require('taskr'); 7 | // const test = require('tape'); 8 | 9 | // const dir = join(__dirname, 'fixtures'); 10 | // const plugins = [require('../'), require('@taskr/clear')]; 11 | // const glob = `${dir}/**/*.js`; 12 | 13 | // const tmpDir = str => join(__dirname, str); 14 | // const create = tasks => new Taskr({ tasks, plugins }); 15 | 16 | // test('@taskr/uglify', t => { 17 | // t.plan(1); 18 | // const taskr = create({ 19 | // *foo(f) { 20 | // t.true('uglify' in taskr.plugins, 'attach `uglify()` plugin to taskr'); 21 | // } 22 | // }); 23 | // taskr.start('foo'); 24 | // }); 25 | 26 | // test('@taskr/uglify (default)', t => { 27 | // t.plan(2); 28 | // create({ 29 | // *foo(f) { 30 | // const tmp = tmpDir('tmp-1'); 31 | // yield f.source(glob).uglify().target(tmp); 32 | 33 | // const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 34 | // t.equal(str, `console.log("this is a");`, 'apply `uglify-js` to content'); 35 | // const arr = yield f.$.expand(`${tmp}/**/*.*`); 36 | // t.equal(arr.length, 2, 'keep all files'); 37 | 38 | // yield f.clear(tmp); 39 | // } 40 | // }).start('foo'); 41 | // }); 42 | 43 | // test('@taskr/uglify (options)', t => { 44 | // t.plan(1); 45 | // create({ 46 | // *foo(f) { 47 | // const tmp = tmpDir('tmp-2'); 48 | // const opts = { drop_console:true }; 49 | // yield f.source(glob).uglify({ compress:opts }).target(tmp); 50 | 51 | // const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 52 | // t.equal(str, '', 'accepts custom config'); 53 | 54 | // // yield f.clear(tmp); 55 | // } 56 | // }).start('foo'); 57 | // }); 58 | 59 | // test('@taskr/uglify (sourceMap)', t => { 60 | // t.plan(2); 61 | // create({ 62 | // *foo(f) { 63 | // const tmp = tmpDir('tmp-3'); 64 | // yield f.source(glob).uglify({ sourceMap:true }).target(tmp); 65 | 66 | // const arr = yield f.$.expand(`${tmp}/**/*.*`); 67 | // t.equal(arr.length, 4, 'creates external sourcemaps per each file'); 68 | // const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 69 | // t.true(str.indexOf('sourceMappingURL=a.js') !== -1, 'appends sourcemap link comment'); 70 | 71 | // yield f.clear(tmp); 72 | // } 73 | // }).start('foo'); 74 | // }); 75 | 76 | // test('@taskr/uglify (inline)', t => { 77 | // t.plan(2); 78 | // create({ 79 | // *foo(f) { 80 | // const tmp = tmpDir('tmp-4'); 81 | // yield f.source(glob).uglify({ sourceMap:'inline' }).target(tmp); 82 | 83 | // const arr = yield f.$.expand(`${tmp}/**/*.*`); 84 | // t.equal(arr.length, 2, 'does NOT create external sourcemaps'); 85 | // const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 86 | // t.true(str.indexOf('sourceMappingURL=data:application/json') !== -1, 'appends inline sourcemap'); 87 | 88 | // yield f.clear(tmp); 89 | // } 90 | // }).start('foo'); 91 | // }); 92 | 93 | // test('@taskr/uglify (custom map)', t => { 94 | // t.plan(3); 95 | // create({ 96 | // *foo(f) { 97 | // const tmp = tmpDir('tmp-5'); 98 | // const sourceMap = { out:'foobar.js.map' }; 99 | // yield f.source(glob).uglify({ sourceMap }).target(tmp); 100 | 101 | // const arr = yield f.$.expand(`${tmp}/**/*.*`); 102 | // t.equal(arr.length, 4, 'creates external sourcemaps'); 103 | // const str = yield f.$.read(`${tmp}/a.js`, 'utf8'); 104 | // t.true(str.indexOf(`sourceMappingURL=${sourceMap.out}`) !== -1, 'appends link to custom sourcemap'); 105 | // const has = yield f.$.find(`${tmp}/${sourceMap.out}`); 106 | // t.true(has, 'creates external sourcemap with custom filename'); 107 | // // yield f.clear(tmp); 108 | // } 109 | // }).start('foo'); 110 | // }); 111 | -------------------------------------------------------------------------------- /packages/unflow/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const clean = require('flow-remove-types'); 4 | 5 | module.exports = function (task) { 6 | task.plugin('unflow', { every:false }, function * (files, opts) { 7 | opts = Object.assign({ pretty:true, all:true }, opts); 8 | 9 | const type = opts.sourceMap || false; 10 | const maps = []; 11 | 12 | files.forEach(file => { 13 | const out = clean(file.data.toString(), opts); 14 | file.data = Buffer.from(out.toString()); 15 | 16 | const mdata = Buffer.from(type ? JSON.stringify(out.generateMap()) : ''); 17 | 18 | // handle sourcemaps 19 | if (type === 'inline') { 20 | file.data += Buffer.from(`\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${mdata.toString('base64')}`); 21 | } else if (type === 'external') { 22 | const mfile = `${file.base}.map`; 23 | file.data += Buffer.from(`\n//# sourceMappingURL=${mfile}`); 24 | // push an external sourcemap to output 25 | maps.push({ 26 | dir: file.dir, 27 | base: mfile, 28 | data: mdata 29 | }); 30 | } 31 | }); 32 | 33 | if (maps.length > 0) { 34 | this._.files = this._.files.concat(maps); 35 | } 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/unflow/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/unflow", 3 | "version": "1.1.0", 4 | "description": "Removes Flow type annotations with Taskr", 5 | "repository": "lukeed/taskr", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "flowtype", 15 | "remove", 16 | "types", 17 | "flow" 18 | ], 19 | "scripts": { 20 | "test": "tape test/*.js | tap-spec" 21 | }, 22 | "author": { 23 | "name": "Luke Edwards", 24 | "email": "luke.edwards05@gmail.com", 25 | "url": "http://github.com/lukeed" 26 | }, 27 | "dependencies": { 28 | "flow-remove-types": "^1.2.0" 29 | }, 30 | "devDependencies": { 31 | "@taskr/clear": "^1.1.0", 32 | "taskr": "^1.1.0" 33 | }, 34 | "engines": { 35 | "node": ">= 4.6" 36 | }, 37 | "publishConfig": { 38 | "access": "public" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/unflow/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/unflow [![npm](https://img.shields.io/npm/v/@taskr/unflow.svg)](https://npmjs.org/package/@taskr/unflow) 2 | 3 | > Removes [Flow](https://flow.org/) type annotations with [Taskr](https://github.com/lukeed/taskr). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save-dev @taskr/unflow 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | exports.build = function * (task) { 15 | yield task.source('src/**/*.js').unflow({ 16 | all: false, 17 | sourceMap: 'inline' 18 | }).target('lib'); 19 | }; 20 | ``` 21 | 22 | ## API 23 | 24 | ### .unflow(options) 25 | 26 | #### options.all 27 | 28 | Type: `Boolean`
29 | Default: `true` 30 | 31 | Transforms _all_ files; not just those with a "@flow" comment. 32 | 33 | #### options.pretty 34 | 35 | Type: `Boolean`
36 | Default: `true` 37 | 38 | Remove whitespace where annotations used to be. See [here](https://github.com/flowtype/flow-remove-types#pretty-transform) for more info. 39 | 40 | #### options.sourceMap 41 | 42 | Type: `String`
43 | Options: `internal|external`
44 | Default: `''` 45 | 46 | Create an inline or an external sourcemap for each entry file. A `sourceMappingURL` comment is appended to each destination file. 47 | 48 | > If using external maps, a `foo.js` entry will also generate a `foo.js.map` file. 49 | 50 | ## Support 51 | 52 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 53 | 54 | Please be sure to specify that you are using `@taskr/unflow`. 55 | 56 | ## License 57 | 58 | MIT © [Luke Edwards](https://lukeed.com) 59 | -------------------------------------------------------------------------------- /packages/unflow/test/fixtures/bar.js: -------------------------------------------------------------------------------- 1 | interface Bar { 2 | foo: String; 3 | baz?: Object; 4 | } 5 | 6 | function foobar(bar: Bar): Object { 7 | return {bar}; 8 | } 9 | -------------------------------------------------------------------------------- /packages/unflow/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | interface Foo { 4 | foo: String; 5 | bar?: Number; 6 | } 7 | 8 | function foobar(foo: Foo): Object { 9 | return {foo}; 10 | } 11 | -------------------------------------------------------------------------------- /packages/unflow/test/index.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const Taskr = require('taskr'); 3 | const test = require('tape'); 4 | 5 | const dir = join(__dirname, 'fixtures'); 6 | 7 | const plugins = [require('@taskr/clear'), require('../')]; 8 | 9 | const tmpDir = str => join(__dirname, str); 10 | const hasFlow = str => /flow|interface|:/.test(str); 11 | const create = tasks => new Taskr({ tasks, plugins }); 12 | 13 | test('@taskr/unflow', t => { 14 | t.plan(2); 15 | const taskr = create({ 16 | *foo(f) { 17 | t.true('unflow' in f, 'attach `unflow` to Task instance'); 18 | t.true('unflow' in taskr.plugins, 'attach `unflow` plugin to instance'); 19 | } 20 | }); 21 | taskr.start('foo'); 22 | }); 23 | 24 | test('@taskr/unflow (defaults)', t => { 25 | t.plan(3); 26 | create({ 27 | *foo(f) { 28 | const tmp = tmpDir('tmp-1'); 29 | yield f.source(`${dir}/*.js`).unflow().target(tmp); 30 | // totals 31 | const arr = yield f.$.expand(`${tmp}/*.js`); 32 | t.equal(arr.length, 2, 'send all files to target'); 33 | // contents 34 | const str1 = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 35 | const str2 = yield f.$.read(`${tmp}/bar.js`, 'utf8'); 36 | t.false(hasFlow(str1), 'remove flow evidence from `foo.js`'); 37 | t.false(hasFlow(str2), 'remove flow evidence from `bar.js`'); 38 | yield f.clear(tmp); 39 | } 40 | }).start('foo'); 41 | }); 42 | 43 | test('@taskr/unflow (all:false)', t => { 44 | t.plan(2); 45 | create({ 46 | *foo(f) { 47 | const tmp = tmpDir('tmp-2'); 48 | yield f.source(`${dir}/*.js`).unflow({ all:false }).target(tmp); 49 | const str1 = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 50 | const str2 = yield f.$.read(`${tmp}/bar.js`, 'utf8'); 51 | t.false(hasFlow(str1), 'remove flow evidence from `foo.js`'); 52 | t.true(hasFlow(str2), 'keeps flow evidence within `bar.js`'); 53 | yield f.clear(tmp); 54 | } 55 | }).start('foo'); 56 | }); 57 | 58 | test('@taskr/unflow (sourceMap:`inline`)', t => { 59 | t.plan(1); 60 | create({ 61 | *foo(f) { 62 | const tmp = tmpDir('tmp-3'); 63 | yield f.source(`${dir}/*.js`).unflow({sourceMap: 'inline'}).target(tmp); 64 | const str = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 65 | t.true(/sourceMappingURL=data:application/.test(str), 'attach an `inline` sourceMap'); 66 | yield f.clear(tmp); 67 | } 68 | }).start('foo'); 69 | }); 70 | 71 | test('@taskr/unflow (sourceMap:`external`)', t => { 72 | t.plan(1); 73 | create({ 74 | *foo(f) { 75 | const tmp = tmpDir('tmp-4'); 76 | yield f.source(`${dir}/*.js`).unflow({ sourceMap:'external' }).target(tmp); 77 | const str = yield f.$.read(`${tmp}/foo.js`, 'utf8'); 78 | t.true(/sourceMappingURL=foo.js.map/.test(str), 'attach an `external` sourceMap link'); 79 | yield f.clear(tmp); 80 | } 81 | }).start('foo'); 82 | }); 83 | -------------------------------------------------------------------------------- /packages/watch/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const toArr = val => Array.isArray(val) ? val : (val == null) ? [] : [val]; 4 | 5 | const types = { 6 | add: 'added', 7 | change: 'changed', 8 | unlink: 'removed' 9 | }; 10 | 11 | module.exports = function (Taskr, utils) { 12 | Taskr.plugin('watch', { every:false, files:false }, function * (_, globs, names, opts) { 13 | globs = toArr(globs); 14 | names = toArr(names); 15 | opts = opts || {}; 16 | 17 | // announce start 18 | Taskr.emit('task_watch'); 19 | 20 | return require('chokidar') 21 | .watch(globs, {ignoreInitial: 1}) 22 | .on('error', utils.error) 23 | .on('all', (event, filepath) => { 24 | // store previous globs (`prevs`) 25 | // used within `target` for `trims` 26 | this._.prevs = globs; 27 | // also update ALL chained `names` for their own `target` 28 | names.forEach(k => { 29 | Taskr.tasks[k].data.prevs = globs; 30 | }); 31 | // broadcast 32 | Taskr.emit('task_watch_event', { action:types[event], file:filepath }); 33 | // pass single file to task params 34 | opts.src = filepath; 35 | // re-run task chain 36 | return Taskr.serial(names, opts); 37 | }); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /packages/watch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/watch", 3 | "version": "1.1.0", 4 | "description": "Watch files & Execute specified tasks on change", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Luke Edwards", 9 | "email": "luke.edwards05@gmail.com", 10 | "url": "https://lukeed.com" 11 | }, 12 | "engines": { 13 | "node": ">=4.6" 14 | }, 15 | "scripts": { 16 | "test": "tape test/*.js | tap-spec" 17 | }, 18 | "files": [ 19 | "index.js" 20 | ], 21 | "keywords": [ 22 | "taskr", 23 | "taskr-plugin", 24 | "chokidar", 25 | "watch" 26 | ], 27 | "dependencies": { 28 | "chokidar": "^1.7.0" 29 | }, 30 | "devDependencies": { 31 | "bluebird": "^3.5.0", 32 | "taskr": "^1.1.0", 33 | "touch": "^1.0.0" 34 | }, 35 | "publishConfig": { 36 | "access": "public" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/watch/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/watch [![npm](https://img.shields.io/npm/v/@taskr/watch.svg)](https://npmjs.org/package/@taskr/watch) 2 | 3 | > Watch files & Execute specified tasks on change 4 | 5 | After initializing a [Chokidar](https://github.com/paulmillr/chokidar) instance, specified paths will be watched and run Tasks _serially_ in response to adding, updating, or deleting a matching filepath. 6 | 7 | When a Task is restarted by `task.watch()`, the Task's `options.src` will contain the full path of the file that triggered a response. 8 | 9 | 10 | ## Install 11 | 12 | ``` 13 | $ npm install --save-dev @taskr/watch 14 | ``` 15 | 16 | 17 | ## Usage 18 | 19 | ```js 20 | module.exports = { 21 | * lint(task, opts) { 22 | // process single file via `opts.src` if populated 23 | yield task.source(opts.src || "src/*.js").eslint() 24 | }, 25 | * scripts(task, opts) { 26 | // process single file via `opts.src` if populated 27 | yield task.source(opts.src || "src/*.js").babel({ presets: ["es2015"] }).target("dist/js") 28 | }, 29 | * styles(task) { 30 | yield task.source("src/app.sass").sass().target("dist/css") 31 | }, 32 | * default(task) { 33 | // watch all JS files; run 'lint' then 'scripts' 34 | yield task.watch("src/**/*.js", ["lint", "scripts"]) 35 | // watch multiple paths; only run "styles" 36 | yield task.watch(["src/foo/*.sass", "src/*.sass"], "styles") 37 | } 38 | } 39 | ``` 40 | 41 | 42 | ## API 43 | 44 | ### .watch(globs, tasks, [options]) 45 | 46 | #### globs 47 | 48 | Type: `string` or `array` 49 | 50 | A filepath, directory path, or glob pattern. Multiple paths must use an `array`. 51 | 52 | 53 | #### tasks 54 | 55 | Type: `string` or `array` 56 | 57 | The task(s) to run when a matched file (from `globs`) is added, changed, or deleted. Multiple tasks must use an `array` and will run as a [serial chain](https://www.npmjs.com/package/taskr#taskrserialtasks-options). 58 | 59 | #### options 60 | 61 | Type: `object`
62 | Default: `{}` 63 | 64 | Initial options to be passed to each Task. See [`Taskr.start`](https://www.npmjs.com/package/taskr#taskrstarttask-options) for more info. 65 | 66 | 67 | ## Support 68 | 69 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 70 | 71 | Please be sure to specify that you are using `@taskr/watch`. 72 | 73 | ## License 74 | 75 | MIT © [Luke Edwards](https://lukeed.com) 76 | -------------------------------------------------------------------------------- /packages/watch/test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | console.log('foo'); 2 | -------------------------------------------------------------------------------- /packages/watch/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const join = require('path').join; 4 | const co = require('bluebird').coroutine; 5 | const touch = require('touch'); 6 | const Taskr = require('taskr'); 7 | const test = require('tape'); 8 | 9 | const fixtures = join(__dirname, 'fixtures'); 10 | 11 | test('@taskr/watch', co(function * (t) { 12 | // t.plan(17) 13 | t.plan(14) 14 | 15 | const glob = join(fixtures, '*.js'); 16 | const file = join(fixtures, 'foo.js'); 17 | const want = ['bar', 'foo']; 18 | 19 | let val = 10; 20 | let order = []; 21 | 22 | const taskr = new Taskr({ 23 | plugins: [ 24 | require('../') 25 | ], 26 | tasks: { 27 | * default(f, o) { 28 | t.true('watch' in f, 'task runtime has access to `watch()`'); 29 | yield f.watch(glob, want, o); 30 | }, 31 | * foo(f, o) { 32 | order.push('foo'); 33 | t.equal(o.val, 11, 'cascade `serial` task values'); 34 | t.deepEqual(order, want, 'run `watch` task chain in `serial` mode'); 35 | 36 | t.equal(o.src, file, '(foo) receives new `src` key after `watch_event`'); 37 | 38 | t.true('prevs' in f._, 'add the `prevs` key to task internals'); 39 | t.true(Array.isArray(f._.prevs), 'the `f._.prevs` key is an array'); 40 | t.equal(f._.prevs[0], glob, 'save the previous `glob` to `taskr._.prevs`'); 41 | 42 | // finished, force exit 43 | setTimeout(() => process.exit(0), 100); 44 | }, 45 | * bar(f, o) { 46 | order.push('bar'); 47 | t.equal(o.val, val, 'pass (initial) options to tasks on init'); 48 | t.equal(o.src, file, '(bar) receives new `src` key after `watch_event`'); 49 | return ++val; 50 | } 51 | } 52 | }) 53 | 54 | taskr.emit = function (e, obj) { 55 | if (e === 'task_watch') { 56 | t.pass('notify when `watch` starts'); 57 | } 58 | 59 | if (e === 'task_watch_event') { 60 | t.pass('notify when `watch` events occur'); 61 | t.equal(obj.action, 'changed', 'receive the correct event `type`'); 62 | t.equal(obj.file, file, 'receive the relevant `file` for given event'); 63 | } 64 | } 65 | 66 | t.true('watch' in taskr.plugins, 'attach watch plugin to taskr'); 67 | 68 | yield taskr.start('default', { val }); 69 | 70 | // force trigger 71 | setTimeout(() => touch(file), 100); 72 | })); 73 | -------------------------------------------------------------------------------- /packages/zip/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const p = require('path'); 4 | const JSZip = require('jszip'); 5 | 6 | module.exports = function (task, utils) { 7 | const zip = new JSZip(); 8 | 9 | task.plugin('zip', { every:false }, function * (files, opts) { 10 | opts = Object.assign({ file:'archive.zip' }, opts); 11 | 12 | let curr; 13 | for (const file of files) { 14 | if (file.data) { 15 | curr = p.relative(task.root, p.format(file)); 16 | zip.file(curr, file.data, { base64:true }); 17 | } 18 | } 19 | 20 | const outdata = yield zip.generateAsync({ type:'nodebuffer' }); 21 | 22 | // if an alt `dest` was given 23 | if (opts.dest !== void 0) { 24 | // write file without overwriting files 25 | const outfile = p.resolve(task.root, opts.dest, opts.file); 26 | yield utils.write(outfile, outdata); 27 | } else { 28 | // overwrite with the archive 29 | this._.files = [{ 30 | dir: files[0].dir, 31 | base: opts.file, 32 | data: outdata 33 | }]; 34 | } 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /packages/zip/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@taskr/zip", 3 | "version": "1.1.0", 4 | "description": "ZIP compress files with taskr", 5 | "repository": "lukeed/taskr", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "files": [ 9 | "index.js" 10 | ], 11 | "keywords": [ 12 | "taskr", 13 | "taskr-plugin", 14 | "zip", 15 | "archive", 16 | "archiver", 17 | "compress", 18 | "compression" 19 | ], 20 | "scripts": { 21 | "test": "tape test/*.js | tap-spec" 22 | }, 23 | "author": { 24 | "name": "Luke Edwards", 25 | "email": "luke.edwards05@gmail.com", 26 | "url": "https://lukeed.com" 27 | }, 28 | "dependencies": { 29 | "jszip": "^3.1.0" 30 | }, 31 | "devDependencies": { 32 | "@taskr/clear": "^1.1.0", 33 | "taskr": "^1.1.0" 34 | }, 35 | "engines": { 36 | "node": ">= 4.6" 37 | }, 38 | "publishConfig": { 39 | "access": "public" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/zip/readme.md: -------------------------------------------------------------------------------- 1 | # @taskr/zip [![npm](https://img.shields.io/npm/v/@taskr/zip.svg)](https://npmjs.org/package/@taskr/zip) 2 | 3 | > ZIP compress files with [Taskr](https://github.com/lukeed/taskr). 4 | 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install --save-dev @taskr/zip 10 | ``` 11 | 12 | ## Usage 13 | 14 | This example will produce `releases/Archive.zip`, containing all contents within the `dist` directory: 15 | 16 | ```js 17 | // Option 1 18 | exports.zip = function * (task) { 19 | yield task.source('dist/**/*').zip({ file:'Archive.zip' }).target('releases'); 20 | } 21 | //=> only writes ZIP file to 'releases' dir 22 | 23 | // Option 2 24 | exports.zip = function * (task) { 25 | yield task.source('dist/**/*').zip({ 26 | file: 'Archive.zip', 27 | dest: '.' 28 | }).target('releases'); 29 | } 30 | //=> writes all files to 'releases' 31 | //=> also writes ZIP file to root dir 32 | ``` 33 | 34 | ## API 35 | 36 | ### .zip(options) 37 | 38 | #### options.dest 39 | 40 | Type: `string`
41 | Default: `null` 42 | 43 | If specified, is an alternate directory wherein the ZIP file should be placed. This should only be used if you'd like to write to a location other than your `task.target()` location. 44 | 45 | > **Important:** By providing a `dest` value, the files from `task.source()` will be preserved and remain accessible within the task-chain! 46 | 47 | #### options.file 48 | 49 | Type: `string`
50 | Default: `'archive.zip'` 51 | 52 | The name of your ZIP file. It must include `.zip`. 53 | 54 | ## Support 55 | 56 | Any issues or questions can be sent to the [Taskr monorepo](https://github.com/lukeed/taskr/issues/new). 57 | 58 | Please be sure to specify that you are using `@taskr/zip`. 59 | 60 | ## License 61 | 62 | MIT © [Luke Edwards](https://lukeed.com) 63 | -------------------------------------------------------------------------------- /packages/zip/test/fixtures/bat.baz: -------------------------------------------------------------------------------- 1 | a second fake file 2 | -------------------------------------------------------------------------------- /packages/zip/test/fixtures/foo.baz: -------------------------------------------------------------------------------- 1 | hello there, how are you today? this is a fake file 2 | -------------------------------------------------------------------------------- /packages/zip/test/index.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const Taskr = require('taskr'); 3 | const test = require('tape'); 4 | 5 | const dir = join(__dirname, 'fixtures'); 6 | 7 | const plugins = [ 8 | require('@taskr/clear'), 9 | require('../') 10 | ]; 11 | 12 | const tmpDir = str => join(__dirname, str); 13 | const create = tasks => new Taskr({ tasks, plugins }); 14 | 15 | test('@taskr/zip', t => { 16 | t.plan(2); 17 | const taskr = create({ 18 | *foo(f) { 19 | t.true('zip' in f, 'attach `zip` to Task instance'); 20 | t.true('zip' in taskr.plugins, 'attach `zip` plugin to instance'); 21 | } 22 | }); 23 | taskr.start('foo'); 24 | }); 25 | 26 | test('@taskr/zip (defaults)', t => { 27 | t.plan(2); 28 | create({ 29 | *foo(f) { 30 | const tmp = tmpDir('tmp-2'); 31 | yield f.source(`${dir}/*.baz`).zip().target(tmp); 32 | const arr = yield f.$.expand(`${tmp}/*`); 33 | t.equal(arr.length, 1, 'sends one file to target'); 34 | t.true(arr[0].indexOf('archive.zip') !== -1, 'creates `tmp/archive.zip` file'); 35 | yield f.clear(tmp); 36 | } 37 | }).start('foo'); 38 | }); 39 | 40 | test('@taskr/zip (file)', t => { 41 | t.plan(2); 42 | create({ 43 | *foo(f) { 44 | const tmp = tmpDir('tmp-2'); 45 | yield f.source(`${dir}/*.baz`).zip({ file:'foo.zip' }).target(tmp); 46 | const arr = yield f.$.expand(`${tmp}/*`); 47 | t.equal(arr.length, 1, 'sends one file to target'); 48 | t.true(arr[0].indexOf('foo.zip') !== -1, 'creates `tmp/foo.zip` file'); 49 | yield f.clear(tmp); 50 | } 51 | }).start('foo'); 52 | }); 53 | 54 | test('@taskr/zip (dest)', t => { 55 | t.plan(3); 56 | create({ 57 | *foo(f) { 58 | const tmp1 = tmpDir('tmp-3'); 59 | const tmp2 = tmpDir('tmp-4'); 60 | yield f.source(`${dir}/*.baz`).zip({ dest:tmp2 }).target(tmp1); 61 | 62 | const arr1 = yield f.$.expand(`${tmp1}/*`); 63 | const arr2 = yield f.$.expand(`${tmp2}/*`); 64 | 65 | t.equal(arr1.length, 2, 'sends two file to `target` dir'); 66 | 67 | t.equal(arr2.length, 1, 'sends one file to `dest` dir'); 68 | t.true(arr2[0].indexOf('archive.zip') !== -1, 'creates `dest/archive.zip` file'); 69 | 70 | yield f.clear([tmp1, tmp2]); 71 | } 72 | }).start('foo'); 73 | }); 74 | --------------------------------------------------------------------------------