UNPKG

2.96 kBJavaScriptView Raw
1"use strict"
2
3const res = require("path").resolve
4const Promise = require("bluebird")
5const Emitter = require("events")
6const wrapp = require("./wrapp")
7const util = require("./utils")
8const Task = require("./task")
9const $ = require("./fn")
10
11const co = Promise.coroutine
12
13class 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
138module.exports = Taskr