0
# Task Organization
1
2
Organize tasks hierarchically using namespaces and create dynamic tasks using pattern-based rules for scalable build systems and complex project structures.
3
4
## Capabilities
5
6
### Namespace
7
8
Creates a namespace for logical grouping of tasks and prevents name collisions. Namespaces can be nested inside other namespaces.
9
10
```javascript { .api }
11
/**
12
* Creates a namespace for logical task grouping
13
* @param {string} name - The name of the namespace
14
* @param {Function} closure - The enclosing scope for the namespaced tasks
15
* @returns {Namespace} The created namespace instance
16
*/
17
function namespace(name, closure);
18
```
19
20
**Usage Examples:**
21
22
```javascript
23
// Basic namespace
24
namespace('doc', function () {
25
desc('Generate documentation');
26
task('generate', ['doc:clean'], function () {
27
jake.exec(['jsdoc src -d docs'], { printStdout: true });
28
});
29
30
desc('Clean documentation directory');
31
task('clean', function () {
32
jake.rmRf('docs');
33
});
34
});
35
36
// Run with: jake doc:generate or jake doc:clean
37
38
// Nested namespaces
39
namespace('build', function () {
40
namespace('assets', function () {
41
desc('Compile CSS');
42
task('css', function () {
43
jake.exec(['sass src/styles:dist/css'], { printStdout: true });
44
});
45
46
desc('Optimize images');
47
task('images', function () {
48
jake.exec(['imagemin src/images dist/images'], { printStdout: true });
49
});
50
});
51
52
desc('Build JavaScript');
53
task('js', function () {
54
jake.exec(['webpack --mode=production'], { printStdout: true });
55
});
56
57
desc('Build all assets');
58
task('all', ['assets:css', 'assets:images', 'js'], function () {
59
console.log('All assets built successfully');
60
});
61
});
62
63
// Run with: jake build:assets:css, jake build:all, etc.
64
65
// Cross-namespace dependencies
66
namespace('test', function () {
67
desc('Run unit tests');
68
task('unit', ['build:js'], function () {
69
jake.exec(['mocha test/unit/**/*.js'], { printStdout: true });
70
});
71
});
72
```
73
74
### Rules
75
76
Creates pattern-based rules that can automatically generate tasks based on file patterns. Useful for build systems that need to handle many similar files.
77
78
```javascript { .api }
79
/**
80
* Creates a Jake Suffix Rule for pattern-based task generation
81
* Arguments after pattern and source can be provided in any order and are parsed by type
82
* @param {string} pattern - The target file pattern to match
83
* @param {string} source - The source file pattern or function
84
* @param {string[]} [prereqs] - Additional prerequisites for generated tasks (optional, any order)
85
* @param {Function} [action] - The action to perform for matched tasks (optional, any order)
86
* @param {Object} [opts] - Task options (optional, any order)
87
* @param {boolean} [opts.async=false] - Perform tasks asynchronously
88
* @returns {void}
89
*/
90
function rule(pattern, source, ...args);
91
```
92
93
**Usage Examples:**
94
95
```javascript
96
// Simple suffix rule - compile .c files to .o files
97
desc('Compile C files');
98
rule('.o', '.c', function () {
99
const cmd = `gcc -c ${this.source} -o ${this.name}`;
100
jake.exec([cmd], { printStdout: true });
101
});
102
103
// Rule with prerequisites - arguments can be in any order after pattern/source
104
rule('.o', '.c', ['config.h'], {async: true}, function () {
105
const cmd = `gcc -c ${this.source} -o ${this.name}`;
106
jake.exec([cmd], function () {
107
complete();
108
}, { printStdout: true });
109
});
110
111
// Flexible argument order - these are all equivalent:
112
rule('.min.js', '.js', function () { /* action */ }, {async: true});
113
rule('.min.js', '.js', {async: true}, function () { /* action */ });
114
rule('.min.js', '.js', ['package.json'], function () { /* action */ });
115
rule('.min.js', '.js', function () { /* action */ }, ['package.json']);
116
117
// Pattern-based rules with % wildcards
118
rule('%.min.js', '%.js', function () {
119
const cmd = `uglifyjs ${this.source} -o ${this.name}`;
120
jake.exec([cmd], { printStdout: true });
121
});
122
123
rule('dist/%.css', 'src/%.scss', ['src/_variables.scss'], function () {
124
const cmd = `sass ${this.source} ${this.name}`;
125
jake.exec([cmd], { printStdout: true });
126
});
127
128
// Directory-specific patterns
129
rule('obj/%.o', 'src/%.c', {async: true}, function () {
130
jake.mkdirP('obj'); // Ensure target directory exists
131
const cmd = `gcc -c ${this.source} -o ${this.name}`;
132
jake.exec([cmd], function () {
133
complete();
134
}, { printStdout: true });
135
});
136
137
// Complex pattern rules
138
rule('build/compressed/%.min.js', 'build/compiled/%.js', ['build/compiled'], function () {
139
const cmd = `uglifyjs ${this.source} --compress --mangle -o ${this.name}`;
140
jake.exec([cmd], { printStdout: true });
141
});
142
143
// Chain rules for multiple transformations
144
rule('%.pdf', '%.dvi', {async: true}, function () {
145
const cmd = `dvipdfm ${this.source}`;
146
jake.exec([cmd], function () {
147
complete();
148
}, { printStdout: true });
149
});
150
151
rule('%.dvi', '%.tex', {async: true}, function () {
152
const cmd = `latex ${this.source}`;
153
jake.exec([cmd], function () {
154
complete();
155
}, { printStdout: true });
156
});
157
158
// Now you can do: jake document.pdf
159
// This will: document.tex → document.dvi → document.pdf
160
```
161
162
### Namespace Class
163
164
Direct access to the Namespace class for programmatic namespace manipulation.
165
166
```javascript { .api }
167
/**
168
* Namespace class for organizing tasks hierarchically
169
*/
170
class Namespace {
171
constructor(name, parentNamespace);
172
173
name: string; // Namespace name
174
parentNamespace: Namespace | null; // Parent namespace
175
childNamespaces: Object; // Child namespaces by name
176
tasks: Object; // Tasks in this namespace by name
177
rules: Object; // Rules in this namespace by pattern
178
path: string; // Colon-separated path from root
179
fullName: string; // Full namespaced name
180
181
addTask(task: Task): void; // Add task to namespace
182
resolveTask(name: string): Task | null; // Find task by name
183
resolveNamespace(name: string): Namespace | null; // Find child namespace
184
matchRule(name: string): Rule | null; // Find matching rule
185
getPath(): string; // Get namespace path
186
isRootNamespace(): boolean; // Check if root namespace
187
}
188
189
/**
190
* Root namespace class - singleton container for all tasks
191
*/
192
class RootNamespace extends Namespace {
193
constructor();
194
}
195
```
196
197
## Advanced Organization Patterns
198
199
### Modular Build System
200
201
```javascript
202
// Load tasks from separate files
203
const loadTasks = function (path) {
204
const tasks = require(path);
205
if (typeof tasks === 'function') {
206
tasks(); // Execute task definitions
207
}
208
};
209
210
// tasks/build.js
211
module.exports = function () {
212
namespace('build', function () {
213
desc('Build CSS');
214
task('css', function () {
215
jake.exec(['sass src:dist'], { printStdout: true });
216
});
217
218
desc('Build JavaScript');
219
task('js', function () {
220
jake.exec(['webpack'], { printStdout: true });
221
});
222
223
desc('Build all');
224
task('all', ['css', 'js']);
225
});
226
};
227
228
// tasks/test.js
229
module.exports = function () {
230
namespace('test', function () {
231
desc('Run unit tests');
232
task('unit', ['build:all'], function () {
233
jake.exec(['mocha test/unit'], { printStdout: true });
234
});
235
236
desc('Run integration tests');
237
task('integration', ['build:all'], function () {
238
jake.exec(['mocha test/integration'], { printStdout: true });
239
});
240
241
desc('Run all tests');
242
task('all', ['unit', 'integration']);
243
});
244
};
245
246
// Jakefile.js
247
loadTasks('./tasks/build');
248
loadTasks('./tasks/test');
249
250
desc('Complete build and test');
251
task('default', ['build:all', 'test:all']);
252
```
253
254
### Environment-Specific Namespaces
255
256
```javascript
257
const environments = ['development', 'staging', 'production'];
258
259
environments.forEach(function (env) {
260
namespace(env, function () {
261
desc(`Deploy to ${env}`);
262
task('deploy', [`build:${env}`], function () {
263
console.log(`Deploying to ${env} environment`);
264
jake.exec([`deploy-script --env=${env}`], { printStdout: true });
265
});
266
267
desc(`Build for ${env}`);
268
task('build', function () {
269
process.env.NODE_ENV = env;
270
jake.exec(['webpack'], { printStdout: true });
271
});
272
273
desc(`Test ${env} build`);
274
task('test', [`build`], function () {
275
jake.exec([`test-script --env=${env}`], { printStdout: true });
276
});
277
});
278
});
279
280
// Usage: jake production:deploy, jake development:test, etc.
281
```
282
283
### Rule-Based Asset Pipeline
284
285
```javascript
286
// Asset processing rules
287
namespace('assets', function () {
288
// Compile SCSS to CSS
289
rule('dist/css/%.css', 'src/scss/%.scss', ['src/scss/_variables.scss'], function () {
290
jake.mkdirP('dist/css');
291
const cmd = `sass ${this.source} ${this.name}`;
292
jake.exec([cmd], { printStdout: true });
293
});
294
295
// Minify CSS
296
rule('dist/css/%.min.css', 'dist/css/%.css', function () {
297
const cmd = `cleancss ${this.source} -o ${this.name}`;
298
jake.exec([cmd], { printStdout: true });
299
});
300
301
// Process JavaScript
302
rule('dist/js/%.js', 'src/js/%.js', function () {
303
jake.mkdirP('dist/js');
304
const cmd = `babel ${this.source} -o ${this.name}`;
305
jake.exec([cmd], { printStdout: true });
306
});
307
308
// Minify JavaScript
309
rule('dist/js/%.min.js', 'dist/js/%.js', function () {
310
const cmd = `uglifyjs ${this.source} -o ${this.name}`;
311
jake.exec([cmd], { printStdout: true });
312
});
313
314
// Optimize images
315
rule('dist/images/%.jpg', 'src/images/%.jpg', function () {
316
jake.mkdirP('dist/images');
317
const cmd = `imagemin ${this.source} --out-dir=dist/images`;
318
jake.exec([cmd], { printStdout: true });
319
});
320
321
rule('dist/images/%.png', 'src/images/%.png', function () {
322
jake.mkdirP('dist/images');
323
const cmd = `imagemin ${this.source} --out-dir=dist/images`;
324
jake.exec([cmd], { printStdout: true });
325
});
326
327
// Build all assets
328
desc('Build all CSS files');
329
task('css', function () {
330
const fs = require('fs');
331
const path = require('path');
332
333
const scssFiles = fs.readdirSync('src/scss')
334
.filter(f => f.endsWith('.scss') && !f.startsWith('_'))
335
.map(f => `dist/css/${path.basename(f, '.scss')}.min.css`);
336
337
scssFiles.forEach(cssFile => {
338
jake.Task[cssFile] && jake.Task[cssFile].invoke();
339
});
340
});
341
342
desc('Build all JavaScript files');
343
task('js', function () {
344
const fs = require('fs');
345
const path = require('path');
346
347
const jsFiles = fs.readdirSync('src/js')
348
.filter(f => f.endsWith('.js'))
349
.map(f => `dist/js/${path.basename(f, '.js')}.min.js`);
350
351
jsFiles.forEach(jsFile => {
352
jake.Task[jsFile] && jake.Task[jsFile].invoke();
353
});
354
});
355
356
desc('Process all images');
357
task('images', function () {
358
const glob = require('glob');
359
360
const imageFiles = glob.sync('src/images/**/*.{jpg,png}')
361
.map(f => f.replace('src/', 'dist/'));
362
363
imageFiles.forEach(imgFile => {
364
jake.Task[imgFile] && jake.Task[imgFile].invoke();
365
});
366
});
367
368
desc('Build all assets');
369
task('all', ['css', 'js', 'images']);
370
});
371
```
372
373
### Conditional Task Loading
374
375
```javascript
376
// Load tasks based on environment or configuration
377
const config = require('./build.config.js');
378
379
if (config.features.includes('typescript')) {
380
namespace('typescript', function () {
381
desc('Compile TypeScript');
382
task('compile', function () {
383
jake.exec(['tsc'], { printStdout: true });
384
});
385
386
rule('dist/%.js', 'src/%.ts', function () {
387
const cmd = `tsc ${this.source} --outDir dist`;
388
jake.exec([cmd], { printStdout: true });
389
});
390
});
391
}
392
393
if (config.features.includes('docker')) {
394
namespace('docker', function () {
395
desc('Build Docker image');
396
task('build', function () {
397
jake.exec(['docker build -t myapp .'], { printStdout: true });
398
});
399
400
desc('Run Docker container');
401
task('run', ['build'], function () {
402
jake.exec(['docker run -p 3000:3000 myapp'], { printStdout: true });
403
});
404
});
405
}
406
```