amie
Version:
Amalgamation Made Insanely Easy. A tool to easily amalgamate stuff!
105 lines (94 loc) • 3.41 kB
JavaScript
;
const fs = require('fs');
const path = require('path');
const async = require('async');
const defaultOptions = require('../config/defaultOptions');
let amie = {
includeRegex: /^[ \t]*#[ \t]*include[ \t]/,
systemIncludeRegex: /<(.+?)>/,
userIncludeRegex: /"(.+?)"/
};
/**
* Will process a single line of code. Effectively handling includes.
*
* @param {String} root Directory of the current folder. For relative includes.
* @param {String} line Current line to process.
* @param {Function} callback Callback to to call with the new line.
*/
amie.processLine = function(line, opts, callback) {
if (amie.includeRegex.test(line)) {
const match = amie.userIncludeRegex.exec(line);
if (!match)
return callback(null, line);
let includePaths = [];
if (opts.rootIncludePath)
includePaths.push(opts.rootIncludePath);
includePaths = includePaths.concat(opts.includePaths);
async.detectSeries(includePaths, (filePath, done) => {
fs.access(path.resolve(filePath, match[1]), (err) => done(null, !err));
}, (err, includePath) => {
if (err)
return callback(err);
if (!includePath)
return callback(new Error(`Unable to find file '${match[1]}'`));
const file = path.resolve(includePath, match[1]);
amie.doFile(file, opts, callback);
});
} else {
callback(null, line);
}
};
/**
* Amalgamate a string content.
*
* @param {String} content Content to process.
* @param {Function} callback The callback to call once the process is done.
*/
amie.doString = function(content, opts, callback) {
let lines = content.split('\n');
async.map(lines, (line, done) => amie.processLine(line, opts, done),
(err, res) => callback(err, res ? res.join('\n') : undefined));
};
/**
* Amalgamate a single file.
*
* @param {String} inputFile Path to the file to amalgamate.
* @param {Function} callback The callback to call once the file is done.
*/
amie.doFile = function(inputFile, opts, callback) {
let handle = function (err, data) {
if (err)
return callback(err);
if (opts.caching)
opts.cache[inputFile] = data;
opts.rootIncludePath = path.dirname(inputFile);
amie.doString(data, opts, callback);
};
if (opts.caching && opts.cache[inputFile])
return handle(null, opts.cache[inputFile]);
fs.readFile(inputFile, 'utf8', handle);
};
/**
* Main function used to amalgamate stuff.
*
* @param {AmieOptions} options Object defining the options for the engine.
* @param {Function} callback The callback to call once amalgamated.
*/
amie.amalgamate = function(options, callback) {
const opts = Object.assign({}, defaultOptions, options);
const input = opts.input;
const output = opts.output;
const doer = opts.fromString ? amie.doString : amie.doFile;
opts.rootIncludePath = '';
opts.cache = {};
doer(input, opts, (err, data) => {
if (err)
return callback(err);
if (!output) {
return callback(null, data);
}
// If an error occurred, we still pass the computed data to the callback.
fs.writeFile(output, data, (err) => callback(err, data));
});
};
module.exports = amie.amalgamate;