137 lines
4.9 KiB
JavaScript
137 lines
4.9 KiB
JavaScript
var fs = require('fs'),
|
|
nodePath = require('path'),
|
|
|
|
_ = require('lodash'),
|
|
async = require('async'),
|
|
mkdirp = require('mkdirp'),
|
|
|
|
// @todo: ES6: Change the sequence below to use object destructuring when Node v4 support is dropped
|
|
joinPath = nodePath.join,
|
|
parsePath = nodePath.parse,
|
|
resolvePath = nodePath.resolve,
|
|
|
|
/**
|
|
* The root path specifier
|
|
*
|
|
* @const
|
|
* @private
|
|
* @type {string}
|
|
*/
|
|
E = '',
|
|
|
|
/**
|
|
* Default timestamp separator.
|
|
*
|
|
* @const
|
|
* @private
|
|
* @type {string}
|
|
*/
|
|
TS_SEP = '-',
|
|
|
|
/**
|
|
* Writes the specified content to a file at the provided path.
|
|
*
|
|
* @param {Object} path - A set of path details for file writing.
|
|
* @param {String|Buffer} content - The content to be written to the file.
|
|
* @param {Object} options - A set of options for the current file write.
|
|
* @param {Function} cb - The callback invoked when the file writing operation has completed, with/without errors.
|
|
*/
|
|
writeFile = function (path, content, options, cb) {
|
|
fs.writeFile(path.unparsed, content, function (err) {
|
|
cb(_.set(err, 'help',
|
|
`error writing file "${path.unparsed}" for ${options.name || 'unknown-source'}`), path);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Generate a timestamp from date
|
|
*
|
|
* @param {Date=} date - The timestamp used to mark the exported file.
|
|
* @param {String=} separator - The optional string with which to separate different sections of the timestamp,
|
|
* defaults to TS_SEP
|
|
* @returns {String} - yyyy-mm-dd-HH-MM-SS-MS-0
|
|
*/
|
|
timestamp = function (date, separator) {
|
|
// use the iso string to ensure left padding and other stuff is taken care of
|
|
return (date || new Date()).toISOString().replace(/[^\d]+/g, _.isString(separator) ? separator : TS_SEP);
|
|
};
|
|
|
|
/**
|
|
* Module whose job is to export a file which is in an export format.
|
|
*
|
|
* @param {Object} options - The set of file export options.
|
|
* @param {String} options.path - The path to the exported file.
|
|
* @param {String|Object} options.content - The JSON / stringified content that is to be written to the file.
|
|
* @param {Function} done - The callback whose invocation marks the end of the file export routine.
|
|
* @returns {*}
|
|
*/
|
|
module.exports = function (options, done) {
|
|
// parse the path if one is available as string
|
|
var path = _.isString(options.path) && parsePath(resolvePath(options.path)),
|
|
content = _.isPlainObject(options.content) ? JSON.stringify(options.content, 0, 2) : (options.content || E);
|
|
|
|
// if a path was not provided by user, we need to prepare the default path. but create the default path only if one
|
|
// is provided.
|
|
if (!path && _.isString(options.default)) {
|
|
path = parsePath(options.default);
|
|
// delete the path and directory if one is detected when parsing defaults
|
|
path.root = E;
|
|
path.dir = 'newman';
|
|
|
|
// append timestamp
|
|
path.name = `${path.name}-${timestamp()}0`; // @todo make -0 become incremental if file name exists
|
|
path.base = path.name + path.ext;
|
|
}
|
|
// final check that path is valid
|
|
if (!(path && path.base)) {
|
|
return;
|
|
}
|
|
|
|
// now sore the unparsed result back for quick re-use during writing and a single place for unparsing
|
|
path.unparsed = joinPath(path.dir, path.base);
|
|
|
|
// in case the path has a directory, ensure that the directory is available
|
|
if (path.dir) {
|
|
async.waterfall([
|
|
function (next) {
|
|
mkdirp(path.dir)
|
|
.then(() => {
|
|
return next();
|
|
})
|
|
.catch((err) => {
|
|
return next(_.set(err, 'help',
|
|
`error creating path for file "${path.unparsed}" for ${options.name || 'unknown-source'}`));
|
|
});
|
|
},
|
|
function (next) {
|
|
fs.stat(path.unparsed, function (err, stat) { // eslint-disable-line handle-callback-err
|
|
next(null, stat);
|
|
});
|
|
},
|
|
function (stat, next) {
|
|
var target;
|
|
|
|
// handle cases where the specified export path is a pre-existing directory
|
|
if (stat && stat.isDirectory()) {
|
|
target = parsePath(options.default);
|
|
|
|
// append timestamp
|
|
// @todo make -0 become incremental if file name exists
|
|
target.name += '-' + timestamp() + '0';
|
|
target.base = target.name + target.ext;
|
|
|
|
path.unparsed = joinPath(path.unparsed, target.base);
|
|
}
|
|
|
|
next(null, path);
|
|
},
|
|
function (path, next) {
|
|
writeFile(path, content, options, next);
|
|
}
|
|
], done);
|
|
}
|
|
else {
|
|
writeFile(path, content, options, done);
|
|
}
|
|
};
|