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
Built-in utilities for shell command execution and file operations, providing cross-platform build automation capabilities and common operations needed in build scripts.
Execute shell commands asynchronously with comprehensive options for output handling and error control.
/**
* Executes shell-commands asynchronously with optional callback
* Arguments after cmds can be provided in any order and are parsed by type
* @param {string|string[]} cmds - The shell command(s) to execute
* @param {Object} [opts] - Execution options (optional, any order)
* @param {boolean} [opts.printStdout=false] - Print stdout from each command
* @param {boolean} [opts.printStderr=false] - Print stderr from each command
* @param {boolean} [opts.breakOnError=true] - Stop execution on first error
* @param {boolean} [opts.windowsVerbatimArguments=false] - Don't translate arguments on Windows
* @param {boolean} [opts.interactive=false] - Run command interactively
* @param {Function} [callback] - Callback to run after executing commands (optional, any order)
* @returns {Exec} Exec instance for monitoring execution
*/
function exec(cmds, ...args);Usage Examples:
// Simple command execution
jake.exec(['echo "Hello World"'], { printStdout: true });
// Multiple commands with options
const cmds = [
'echo "Showing directories"',
'ls -al | grep ^d',
'echo "Moving up a directory"',
'cd ../'
];
jake.exec(cmds, {
printStdout: true,
printStderr: true
}, function () {
console.log('Finished running commands.');
});
// Flexible argument order - these are all equivalent:
jake.exec(['npm test'], { printStdout: true }, callback);
jake.exec(['npm test'], callback, { printStdout: true });
jake.exec(['npm test'], callback); // options omitted
jake.exec(['npm test'], { printStdout: true }); // callback omitted
// Error handling
jake.exec(['invalid-command'], {
breakOnError: false,
printStderr: true
}, function () {
console.log('Commands completed (some may have failed)');
});
// Interactive command
jake.exec(['npm init'], {
interactive: true
}, function () {
console.log('Interactive npm init completed');
});
// Platform-specific commands
const isWindows = process.platform === 'win32';
const cmd = isWindows ? 'dir' : 'ls -la';
jake.exec([cmd], { printStdout: true });Direct access to the Exec class for advanced command execution control.
/**
* Command execution handler with EventEmitter capabilities
*/
class Exec extends EventEmitter {
constructor(cmds, opts, callback);
append(cmd: string): void; // Add command to execution queue
run(): void; // Start command execution
}Exec Events:
interface ExecEvents {
'cmdStart': (cmd: string) => void; // Command started executing
'cmdEnd': (cmd: string) => void; // Command finished successfully
'stdout': (data: Buffer) => void; // Stdout data received
'stderr': (data: Buffer) => void; // Stderr data received
'error': (msg: string, code: number) => void; // Command failed
'end': () => void; // All commands completed
}Usage Examples:
// Create exec instance for monitoring
const ex = new jake.Exec(['npm test', 'npm run build']);
ex.on('cmdStart', function (cmd) {
console.log('Starting:', cmd);
});
ex.on('stdout', function (data) {
process.stdout.write(data.toString());
});
ex.on('stderr', function (data) {
process.stderr.write(data.toString());
});
ex.on('error', function (msg, code) {
console.error('Command failed:', msg, 'Exit code:', code);
});
ex.on('end', function () {
console.log('All commands completed');
});
// Add more commands dynamically
ex.append('npm run lint');
ex.run();Cross-platform file and directory operations for common build tasks.
/**
* Copies files and directories recursively
* @param {string} fromPath - The source path to copy from
* @param {string} toPath - The destination path to copy to
* @param {Object} [opts] - Copy options
* @param {boolean} [opts.preserveMode=false] - Preserve file modes when overwriting
* @returns {void}
*/
function cpR(fromPath, toPath, opts);Usage Examples:
// Copy directory recursively
jake.cpR('src/assets', 'dist/assets');
// Copy file to directory
jake.cpR('config.json', 'dist/');
// Copy with options
jake.cpR('build/', 'backup/', { preserveMode: true });
// Copy and rename
jake.cpR('src/app.js', 'dist/bundle.js');
// Copy multiple items in a task
task('copyAssets', function () {
jake.cpR('src/images', 'dist/images');
jake.cpR('src/fonts', 'dist/fonts');
jake.cpR('src/data', 'dist/data');
});/**
* Create directories recursively (like mkdir -p)
* @param {string} dir - The directory path to create
* @param {number} [mode=0755] - The mode/permissions for created directories
* @returns {void}
*/
function mkdirP(dir, mode);Usage Examples:
// Create single directory
jake.mkdirP('dist');
// Create nested directories
jake.mkdirP('dist/assets/images');
// Create with specific permissions
jake.mkdirP('tmp/cache', parseInt('755', 8));
// Create multiple directories
task('setupDirs', function () {
jake.mkdirP('dist/css');
jake.mkdirP('dist/js');
jake.mkdirP('dist/images');
jake.mkdirP('tmp/build');
});
// Ensure directory exists before file operations
file('dist/bundle.js', ['src/**/*.js'], function () {
jake.mkdirP('dist'); // Ensure target directory exists
jake.exec(['webpack src/app.js dist/bundle.js']);
});/**
* Remove files and directories recursively (like rm -rf)
* @param {string} path - The path to remove (file or directory)
* @param {Object} [options] - Removal options
* @returns {void}
*/
function rmRf(path, options);Usage Examples:
// Remove directory and all contents
jake.rmRf('dist');
// Remove specific file
jake.rmRf('temp.log');
// Clean task
desc('Clean build artifacts');
task('clean', function () {
jake.rmRf('dist');
jake.rmRf('tmp');
jake.rmRf('coverage');
jake.rmRf('*.log');
});
// Conditional removal
task('cleanOld', function () {
const fs = require('fs');
if (fs.existsSync('old-dist')) {
jake.rmRf('old-dist');
}
});Utilities for working with file paths and determining absolute vs relative paths.
/**
* Checks if a path is absolute or relative
* @param {string} path - Path to check
* @returns {boolean|string} If absolute, returns first character; otherwise false
*/
function isAbsolute(path);/**
* Returns the absolute path for the given path
* @param {string} path - The path to make absolute
* @returns {string} The absolute path
*/
function absolutize(path);Usage Examples:
// Check if path is absolute
const path1 = '/home/user/project';
const path2 = 'src/app.js';
console.log(jake.isAbsolute(path1)); // '/'
console.log(jake.isAbsolute(path2)); // false
// Convert to absolute path
const absolutePath = jake.absolutize('src/app.js');
console.log(absolutePath); // '/current/working/directory/src/app.js'
// Use in file operations
task('copyConfig', function () {
const configPath = jake.absolutize('config/app.json');
const distPath = jake.absolutize('dist/config.json');
jake.cpR(configPath, distPath);
});
// Resolve paths in rules
rule('dist/%.js', 'src/%.js', function () {
const srcPath = jake.absolutize(this.source);
const distPath = jake.absolutize(this.name);
console.log('Compiling:', srcPath, '->', distPath);
jake.exec(['babel ' + srcPath + ' -o ' + distPath]);
});// Conditional command execution
task('deploy', function () {
const env = process.env.NODE_ENV || 'development';
if (env === 'production') {
jake.exec([
'npm run build:prod',
'docker build -t myapp:latest .',
'docker push myapp:latest'
], { printStdout: true });
} else {
jake.exec([
'npm run build:dev',
'rsync -av dist/ staging-server:/var/www/'
], { printStdout: true });
}
});
// Command chaining with error handling
task('testAndDeploy', { async: true }, function () {
jake.exec(['npm test'], {
printStdout: true,
printStderr: true
}, function () {
console.log('Tests passed, deploying...');
jake.exec(['npm run deploy'], {
printStdout: true
}, function () {
console.log('Deployment complete');
complete();
});
});
});
// Parallel command execution
task('buildAll', { async: true }, function () {
let completed = 0;
const commands = [
['npm run build:css'],
['npm run build:js'],
['npm run build:images']
];
commands.forEach(function (cmd) {
jake.exec(cmd, { printStdout: true }, function () {
completed++;
if (completed === commands.length) {
console.log('All builds completed');
complete();
}
});
});
});// Backup and restore operations
task('backup', function () {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupDir = `backup-${timestamp}`;
jake.mkdirP(backupDir);
jake.cpR('dist', `${backupDir}/dist`);
jake.cpR('config', `${backupDir}/config`);
console.log('Backup created:', backupDir);
});
task('restore', function (backupName) {
if (!backupName) {
fail('Please specify backup name: jake restore[backup-2023-...]');
}
jake.rmRf('dist');
jake.rmRf('config');
jake.cpR(`${backupName}/dist`, 'dist');
jake.cpR(`${backupName}/config`, 'config');
console.log('Backup restored:', backupName);
});
// Cleanup with pattern matching
task('cleanLogs', function () {
const fs = require('fs');
const path = require('path');
const files = fs.readdirSync('.');
files.forEach(function (file) {
if (file.match(/\.log$/)) {
jake.rmRf(file);
console.log('Removed log file:', file);
}
});
});
// Archive old builds
task('archiveBuilds', function () {
const fs = require('fs');
const path = require('path');
if (fs.existsSync('dist')) {
const timestamp = Date.now();
const archiveDir = `archive/build-${timestamp}`;
jake.mkdirP('archive');
jake.cpR('dist', archiveDir);
console.log('Archived build to:', archiveDir);
}
});// Platform-specific operations
const isWindows = process.platform === 'win32';
const isMac = process.platform === 'darwin';
const isLinux = process.platform === 'linux';
task('install-deps', function () {
const commands = [];
if (isWindows) {
commands.push('powershell -Command "& {Install-Module -Name SomeModule}"');
} else if (isMac) {
commands.push('brew install some-package');
} else if (isLinux) {
commands.push('sudo apt-get install some-package');
}
jake.exec(commands, { printStdout: true });
});
// Path handling across platforms
task('setupPaths', function () {
const sep = path.sep;
const buildPath = ['dist', 'assets', 'js'].join(sep);
jake.mkdirP(buildPath);
const sourcePath = jake.absolutize('src' + sep + 'app.js');
const targetPath = jake.absolutize(buildPath + sep + 'app.js');
jake.cpR(sourcePath, targetPath);
});The Exec class provides direct control over command execution with event-based monitoring and lifecycle management.
/**
* Creates an Exec instance for advanced command control
* @param {string|string[]} cmds - Commands to execute
* @param {Object} [opts] - Execution options
* @param {Function} [callback] - Completion callback
* @returns {Exec} Exec instance
*/
function createExec(cmds, opts, callback);
/**
* Exec class for command execution control
*/
class Exec extends EventEmitter {
constructor(cmds, opts, callback);
// Methods
run(): void; // Start command execution
append(cmd: string): void; // Add command to execution queue
// Events (inherited from EventEmitter)
// 'cmdStart' - Emitted when a command starts
// 'cmdEnd' - Emitted when a command completes successfully
// 'stdout' - Emitted when command outputs to stdout
// 'stderr' - Emitted when command outputs to stderr
// 'error' - Emitted when a command fails
// 'end' - Emitted when all commands complete
}Usage Examples:
// Create exec instance for monitoring
const exec = createExec([
'npm install',
'npm run build',
'npm test'
], {
printStdout: true,
breakOnError: false
});
// Monitor execution progress
exec.on('cmdStart', function(cmd) {
console.log('Starting:', cmd);
});
exec.on('cmdEnd', function(cmd) {
console.log('Completed:', cmd);
});
exec.on('stdout', function(data) {
console.log('Output:', data.toString());
});
exec.on('error', function(err, code) {
console.log('Command failed:', err, 'Exit code:', code);
});
exec.on('end', function() {
console.log('All commands completed');
});
// Start execution
exec.run();
// Add more commands dynamically
exec.append('npm run deploy');Generate unique identifiers for tasks, temporary files, or other build artifacts.
/**
* Generates a UUID string
* @param {number} [length] - Specific length for compact form
* @param {number} [radix] - Number base for character set (default: 62)
* @returns {string} Generated UUID
*/
function uuid(length, radix);Usage Examples:
// Generate standard RFC4122 UUID
const id = jake.uuid();
console.log(id); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
// Generate compact UUID
const shortId = jake.uuid(8);
console.log(shortId); // "3B7nZq4k"
// Generate with specific radix
const hexId = jake.uuid(12, 16);
console.log(hexId); // "a3b5c7d9e1f3"
// Use in build tasks
task('generateTempFiles', function() {
const tempDir = `temp-${jake.uuid(8)}`;
jake.mkdirP(tempDir);
// Process files in temp directory
jake.exec([`process-files ${tempDir}`], { printStdout: true });
});
// Create unique artifact names
task('package', function() {
const buildId = jake.uuid(6);
const packageName = `myapp-${jake.version}-${buildId}.tar.gz`;
jake.exec([`tar -czf ${packageName} dist/`], { printStdout: true });
});Access Jake's built-in logging system for consistent output formatting and log levels.
/**
* Jake's logger instance with formatted output methods
*/
interface Logger {
log(message: string): void; // Standard log output
error(message: string): void; // Error output to stderr
warn(message: string): void; // Warning output
info(message: string): void; // Informational output
}
// Access via jake.logger
const logger = jake.logger;Usage Examples:
// Use logger in tasks
task('deploy', function() {
jake.logger.info('Starting deployment process...');
try {
jake.exec(['npm run build'], { printStdout: true });
jake.logger.log('Build completed successfully');
jake.exec(['rsync -av dist/ server:/var/www/'], { printStdout: true });
jake.logger.log('Deployment completed successfully');
} catch (err) {
jake.logger.error('Deployment failed: ' + err.message);
fail(err);
}
});
// Custom logging in functions
function logBuildStep(step, message) {
jake.logger.log(`[${step}] ${message}`);
}
task('build', function() {
logBuildStep('CLEAN', 'Removing old build files');
jake.rmRf('dist');
logBuildStep('COMPILE', 'Compiling TypeScript');
jake.exec(['tsc'], { printStdout: true });
logBuildStep('BUNDLE', 'Creating bundle');
jake.exec(['webpack'], { printStdout: true });
jake.logger.log('Build process completed');
});