JavaScript build tool, similar to Make or Rake
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Organize tasks hierarchically using namespaces and create dynamic tasks using pattern-based rules for scalable build systems and complex project structures.
Creates a namespace for logical grouping of tasks and prevents name collisions. Namespaces can be nested inside other namespaces.
/**
* Creates a namespace for logical task grouping
* @param {string} name - The name of the namespace
* @param {Function} closure - The enclosing scope for the namespaced tasks
* @returns {Namespace} The created namespace instance
*/
function namespace(name, closure);Usage Examples:
// Basic namespace
namespace('doc', function () {
desc('Generate documentation');
task('generate', ['doc:clean'], function () {
jake.exec(['jsdoc src -d docs'], { printStdout: true });
});
desc('Clean documentation directory');
task('clean', function () {
jake.rmRf('docs');
});
});
// Run with: jake doc:generate or jake doc:clean
// Nested namespaces
namespace('build', function () {
namespace('assets', function () {
desc('Compile CSS');
task('css', function () {
jake.exec(['sass src/styles:dist/css'], { printStdout: true });
});
desc('Optimize images');
task('images', function () {
jake.exec(['imagemin src/images dist/images'], { printStdout: true });
});
});
desc('Build JavaScript');
task('js', function () {
jake.exec(['webpack --mode=production'], { printStdout: true });
});
desc('Build all assets');
task('all', ['assets:css', 'assets:images', 'js'], function () {
console.log('All assets built successfully');
});
});
// Run with: jake build:assets:css, jake build:all, etc.
// Cross-namespace dependencies
namespace('test', function () {
desc('Run unit tests');
task('unit', ['build:js'], function () {
jake.exec(['mocha test/unit/**/*.js'], { printStdout: true });
});
});Creates pattern-based rules that can automatically generate tasks based on file patterns. Useful for build systems that need to handle many similar files.
/**
* Creates a Jake Suffix Rule for pattern-based task generation
* Arguments after pattern and source can be provided in any order and are parsed by type
* @param {string} pattern - The target file pattern to match
* @param {string} source - The source file pattern or function
* @param {string[]} [prereqs] - Additional prerequisites for generated tasks (optional, any order)
* @param {Function} [action] - The action to perform for matched tasks (optional, any order)
* @param {Object} [opts] - Task options (optional, any order)
* @param {boolean} [opts.async=false] - Perform tasks asynchronously
* @returns {void}
*/
function rule(pattern, source, ...args);Usage Examples:
// Simple suffix rule - compile .c files to .o files
desc('Compile C files');
rule('.o', '.c', function () {
const cmd = `gcc -c ${this.source} -o ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
// Rule with prerequisites - arguments can be in any order after pattern/source
rule('.o', '.c', ['config.h'], {async: true}, function () {
const cmd = `gcc -c ${this.source} -o ${this.name}`;
jake.exec([cmd], function () {
complete();
}, { printStdout: true });
});
// Flexible argument order - these are all equivalent:
rule('.min.js', '.js', function () { /* action */ }, {async: true});
rule('.min.js', '.js', {async: true}, function () { /* action */ });
rule('.min.js', '.js', ['package.json'], function () { /* action */ });
rule('.min.js', '.js', function () { /* action */ }, ['package.json']);
// Pattern-based rules with % wildcards
rule('%.min.js', '%.js', function () {
const cmd = `uglifyjs ${this.source} -o ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
rule('dist/%.css', 'src/%.scss', ['src/_variables.scss'], function () {
const cmd = `sass ${this.source} ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
// Directory-specific patterns
rule('obj/%.o', 'src/%.c', {async: true}, function () {
jake.mkdirP('obj'); // Ensure target directory exists
const cmd = `gcc -c ${this.source} -o ${this.name}`;
jake.exec([cmd], function () {
complete();
}, { printStdout: true });
});
// Complex pattern rules
rule('build/compressed/%.min.js', 'build/compiled/%.js', ['build/compiled'], function () {
const cmd = `uglifyjs ${this.source} --compress --mangle -o ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
// Chain rules for multiple transformations
rule('%.pdf', '%.dvi', {async: true}, function () {
const cmd = `dvipdfm ${this.source}`;
jake.exec([cmd], function () {
complete();
}, { printStdout: true });
});
rule('%.dvi', '%.tex', {async: true}, function () {
const cmd = `latex ${this.source}`;
jake.exec([cmd], function () {
complete();
}, { printStdout: true });
});
// Now you can do: jake document.pdf
// This will: document.tex → document.dvi → document.pdfDirect access to the Namespace class for programmatic namespace manipulation.
/**
* Namespace class for organizing tasks hierarchically
*/
class Namespace {
constructor(name, parentNamespace);
name: string; // Namespace name
parentNamespace: Namespace | null; // Parent namespace
childNamespaces: Object; // Child namespaces by name
tasks: Object; // Tasks in this namespace by name
rules: Object; // Rules in this namespace by pattern
path: string; // Colon-separated path from root
fullName: string; // Full namespaced name
addTask(task: Task): void; // Add task to namespace
resolveTask(name: string): Task | null; // Find task by name
resolveNamespace(name: string): Namespace | null; // Find child namespace
matchRule(name: string): Rule | null; // Find matching rule
getPath(): string; // Get namespace path
isRootNamespace(): boolean; // Check if root namespace
}
/**
* Root namespace class - singleton container for all tasks
*/
class RootNamespace extends Namespace {
constructor();
}// Load tasks from separate files
const loadTasks = function (path) {
const tasks = require(path);
if (typeof tasks === 'function') {
tasks(); // Execute task definitions
}
};
// tasks/build.js
module.exports = function () {
namespace('build', function () {
desc('Build CSS');
task('css', function () {
jake.exec(['sass src:dist'], { printStdout: true });
});
desc('Build JavaScript');
task('js', function () {
jake.exec(['webpack'], { printStdout: true });
});
desc('Build all');
task('all', ['css', 'js']);
});
};
// tasks/test.js
module.exports = function () {
namespace('test', function () {
desc('Run unit tests');
task('unit', ['build:all'], function () {
jake.exec(['mocha test/unit'], { printStdout: true });
});
desc('Run integration tests');
task('integration', ['build:all'], function () {
jake.exec(['mocha test/integration'], { printStdout: true });
});
desc('Run all tests');
task('all', ['unit', 'integration']);
});
};
// Jakefile.js
loadTasks('./tasks/build');
loadTasks('./tasks/test');
desc('Complete build and test');
task('default', ['build:all', 'test:all']);const environments = ['development', 'staging', 'production'];
environments.forEach(function (env) {
namespace(env, function () {
desc(`Deploy to ${env}`);
task('deploy', [`build:${env}`], function () {
console.log(`Deploying to ${env} environment`);
jake.exec([`deploy-script --env=${env}`], { printStdout: true });
});
desc(`Build for ${env}`);
task('build', function () {
process.env.NODE_ENV = env;
jake.exec(['webpack'], { printStdout: true });
});
desc(`Test ${env} build`);
task('test', [`build`], function () {
jake.exec([`test-script --env=${env}`], { printStdout: true });
});
});
});
// Usage: jake production:deploy, jake development:test, etc.// Asset processing rules
namespace('assets', function () {
// Compile SCSS to CSS
rule('dist/css/%.css', 'src/scss/%.scss', ['src/scss/_variables.scss'], function () {
jake.mkdirP('dist/css');
const cmd = `sass ${this.source} ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
// Minify CSS
rule('dist/css/%.min.css', 'dist/css/%.css', function () {
const cmd = `cleancss ${this.source} -o ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
// Process JavaScript
rule('dist/js/%.js', 'src/js/%.js', function () {
jake.mkdirP('dist/js');
const cmd = `babel ${this.source} -o ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
// Minify JavaScript
rule('dist/js/%.min.js', 'dist/js/%.js', function () {
const cmd = `uglifyjs ${this.source} -o ${this.name}`;
jake.exec([cmd], { printStdout: true });
});
// Optimize images
rule('dist/images/%.jpg', 'src/images/%.jpg', function () {
jake.mkdirP('dist/images');
const cmd = `imagemin ${this.source} --out-dir=dist/images`;
jake.exec([cmd], { printStdout: true });
});
rule('dist/images/%.png', 'src/images/%.png', function () {
jake.mkdirP('dist/images');
const cmd = `imagemin ${this.source} --out-dir=dist/images`;
jake.exec([cmd], { printStdout: true });
});
// Build all assets
desc('Build all CSS files');
task('css', function () {
const fs = require('fs');
const path = require('path');
const scssFiles = fs.readdirSync('src/scss')
.filter(f => f.endsWith('.scss') && !f.startsWith('_'))
.map(f => `dist/css/${path.basename(f, '.scss')}.min.css`);
scssFiles.forEach(cssFile => {
jake.Task[cssFile] && jake.Task[cssFile].invoke();
});
});
desc('Build all JavaScript files');
task('js', function () {
const fs = require('fs');
const path = require('path');
const jsFiles = fs.readdirSync('src/js')
.filter(f => f.endsWith('.js'))
.map(f => `dist/js/${path.basename(f, '.js')}.min.js`);
jsFiles.forEach(jsFile => {
jake.Task[jsFile] && jake.Task[jsFile].invoke();
});
});
desc('Process all images');
task('images', function () {
const glob = require('glob');
const imageFiles = glob.sync('src/images/**/*.{jpg,png}')
.map(f => f.replace('src/', 'dist/'));
imageFiles.forEach(imgFile => {
jake.Task[imgFile] && jake.Task[imgFile].invoke();
});
});
desc('Build all assets');
task('all', ['css', 'js', 'images']);
});// Load tasks based on environment or configuration
const config = require('./build.config.js');
if (config.features.includes('typescript')) {
namespace('typescript', function () {
desc('Compile TypeScript');
task('compile', function () {
jake.exec(['tsc'], { printStdout: true });
});
rule('dist/%.js', 'src/%.ts', function () {
const cmd = `tsc ${this.source} --outDir dist`;
jake.exec([cmd], { printStdout: true });
});
});
}
if (config.features.includes('docker')) {
namespace('docker', function () {
desc('Build Docker image');
task('build', function () {
jake.exec(['docker build -t myapp .'], { printStdout: true });
});
desc('Run Docker container');
task('run', ['build'], function () {
jake.exec(['docker run -p 3000:3000 myapp'], { printStdout: true });
});
});
}