├── .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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 [](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 |
--------------------------------------------------------------------------------