UNPKG

fakeit

Version:

Command-line utility that generates fake data which can be output as JSON, YAML, CSON, or CSV formats based on models defined in YAML.

652 lines (504 loc) 21.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.validate = exports.output_types = undefined; var _regenerator = require('babel-runtime/regenerator'); var _regenerator2 = _interopRequireDefault(_regenerator); var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); exports.isServer = isServer; exports.isString = isString; var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _lodash = require('lodash'); var _toJs = require('to-js'); var _toJs2 = _interopRequireDefault(_toJs); var _base = require('../base'); var _base2 = _interopRequireDefault(_base); var _utils = require('../utils'); var _defaultOptions = require('./default-options'); var _defaultOptions2 = _interopRequireDefault(_defaultOptions); var _perfy = require('perfy'); var _perfy2 = _interopRequireDefault(_perfy); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var output_types = exports.output_types = ['return', 'console', 'couchbase', 'sync-gateway']; /// @name Output /// @description /// This is used to output data into different environments //// /// @page api //// var Output = function (_Base) { (0, _inherits3.default)(Output, _Base); ///# @name constructor ///# @arg {object} options [{}] - The options that apply to Base ///# @arg {object} output_options - The options for how you want save data ///# { ///# ///# } ///# @todo update the output_options to have the final options and descriptions of each function Output() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var output_options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; (0, _classCallCheck3.default)(this, Output); var _this = (0, _possibleConstructorReturn3.default)(this, (Output.__proto__ || (0, _getPrototypeOf2.default)(Output)).call(this, options)); _this.output_options = (0, _lodash.extend)({}, _defaultOptions2.default, output_options); _this.validateOutputOptions(); _this.prepared = false; return _this; } ///# @name prepare ///# @description ///# This is used to prepare the saving functionality that is determined by the ///# options that were passed to the constructor. ///# It sets a variable of `this.preparing` that ultimately calls `this.setup` that returns a promise. ///# This way when you go to save data it, that function will know if the setup is complete or not and ///# wait for it to be done before it starts saving data. ///# @returns {promise} - The setup function that was called ///# @async (0, _createClass3.default)(Output, [{ key: 'prepare', value: function prepare() { this.preparing = true; this.preparing = this.setup(); return this.preparing; } ///# @name setup ///# @description ///# This is used to setup the saving function that will be used. }, { key: 'setup', value: function () { var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee() { var _this2 = this; var _output_options, output, archive, Outputter; return _regenerator2.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!(this.preparing == null)) { _context.next = 2; break; } return _context.abrupt('return', this.prepare()); case 2: _output_options = this.output_options, output = _output_options.output, archive = _output_options.archive; if (!(output_types.indexOf(output) !== -1)) { output = !!archive ? 'zip' : 'folder'; } // get the outputter to use if (!(output !== 'return')) { _context.next = 12; break; } Outputter = require('./' + output).default; // creates a new instance of it so that we can use it to output the data in // what ever way that the user wants to output it in. this.outputter = new Outputter(this.options, this.output_options); // if the outputter has a prepare function call it and await for it to be done if (!(typeof this.outputter.prepare === 'function')) { _context.next = 10; break; } _context.next = 10; return this.outputter.prepare(); case 10: this.prepared = true; return _context.abrupt('return'); case 12: process.nextTick(function () { _this2.prepared = true; }); case 13: case 'end': return _context.stop(); } } }, _callee, this); })); function setup() { return _ref.apply(this, arguments); } return setup; }() ///# @name output ///# @description ///# This is used to save data to any place that was passed in the constructor ///# @arg {array, object} documents - The data that you want to be saved ///# @returns {array, object, string} - This is determined by the output type that's passed and the format that's used. ///# @async }, { key: 'output', value: function () { var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(documents) { var _this3 = this; var count, _output_options2, format, spacing, limit, output, name, spinner, times, update, parser, parsed, result; return _regenerator2.default.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: count = 0; if (documents) { _context3.next = 3; break; } return _context3.abrupt('return', this.log('error', 'You must pass in documents to the output')); case 3: documents = _toJs2.default.array(documents); if (!(this.prepared !== true)) { _context3.next = 8; break; } if (this.preparing == null) { this.prepare(); } _context3.next = 8; return this.preparing; case 8: _output_options2 = this.output_options, format = _output_options2.format, spacing = _output_options2.spacing, limit = _output_options2.limit, output = _output_options2.output; name = documents[0].__name; // eslint-disable-line spinner = this.spinner('Outputting ' + name); times = []; update = function update() { spinner.text = 'Outputting ' + name + ' to ' + output + ' (' + count + '/' + documents.length + ')'; if (times.length) { spinner.text += ' (' + (0, _lodash.mean)(times).toFixed(2) + 'ms on average)'; } }; parser = this.getParser(output, format); // if the output type is `return` or `console` then this will return the complete // data set instead of running them individually if (!(['return', 'console'].indexOf(output) !== -1)) { _context3.next = 28; break; } _context3.next = 17; return parser(documents, spacing); case 17: parsed = _context3.sent; if (!(output === 'console')) { _context3.next = 27; break; } spinner.start(); _context3.next = 22; return this.outputter.output(null, parsed); case 22: result = _context3.sent; spinner.text = 'Outputting ' + name + ' to ' + output; spinner.stop(); console.log(result); return _context3.abrupt('return', result); case 27: return _context3.abrupt('return', parsed); case 28: // if the output isn't `return` or `console` and the `format` is `csv` // then it needs to be updated if (format === 'csv') { documents = [documents]; } // reformat the data into the output type spinner.start(); return _context3.abrupt('return', (0, _utils.pool)(documents, function () { var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(document, i) { var label, key, result; return _regenerator2.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: label = (0, _lodash.uniqueId)('document ' + name + ' ' + i); _perfy2.default.start(label); key = document.__key || document.__name || (document[0] || {}).__name || ''; // eslint-disable-line no-underscore-dangle // use the outputter's output function to output the data _context2.t0 = _this3.outputter; _context2.t1 = key; _context2.next = 7; return parser(document, spacing); case 7: _context2.t2 = _context2.sent; _context2.next = 10; return _context2.t0.output.call(_context2.t0, _context2.t1, _context2.t2); case 10: result = _context2.sent; update(count++); times.push(_perfy2.default.end(label).milliseconds); return _context2.abrupt('return', result); case 14: case 'end': return _context2.stop(); } } }, _callee2, _this3); })); return function (_x4, _x5) { return _ref3.apply(this, arguments); }; }(), limit).then(function (result) { spinner.stop(); return result; }).catch(function (err) { spinner.fail(err); })); case 31: case 'end': return _context3.stop(); } } }, _callee3, this); })); function output(_x3) { return _ref2.apply(this, arguments); } return output; }() ///# @name finalize ///# @description ///# This is used to clean up anything that needs to be cleaned up ///# like a connection to a data base, any event listeners, or finish outputting a zip file. ///# @async }, { key: 'finalize', value: function () { var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4() { return _regenerator2.default.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: if (!(this.outputter && _toJs.is.function(this.outputter.finalize))) { _context4.next = 3; break; } _context4.next = 3; return this.outputter.finalize(); case 3: case 'end': return _context4.stop(); } } }, _callee4, this); })); function finalize() { return _ref4.apply(this, arguments); } return finalize; }() ///# @name validateOutputOptions ///# @description This is used to validate the output options ///# @throws {error} - If an option that was passed is invalid. }, { key: 'validateOutputOptions', value: function validateOutputOptions() { var _this4 = this; _toJs2.default.each(this.output_options, function (_ref5) { var key = _ref5.key, value = _ref5.value; try { validate[key](value, _this4.output_options); } catch (e) { _this4.log('error', e); } }); } ///# @name getParser ///# @description Returns a parser function for the given output type and format ///# @arg {string} output - Output type ///# @arg {string} format - Output format ///# @returns {function} - Function to format a document }, { key: 'getParser', value: function getParser(output, format) { if (output === 'couchbase' && format === 'json') { return function (obj) { return obj; }; } return _utils.parsers[format].stringify; } }]); return Output; }(_base2.default); /// @name Output validate /// @description This holds the different options that can be passed to the Output constructor /// @type {object} exports.default = Output; var validate = exports.validate = { ///# @name format ///# @description Used to validate the format option ///# @arg {string} option - The option to validate against ///# @throws {error} - If the format option that was pass was invalid format: function format(option) { var formats = ['json', 'csv', 'yaml', 'yml', 'cson']; if (isString(option, 'format') && formats.indexOf(option) !== -1) { return; } throw new Error('You must use one of the following formats ' + formats + '. You passed ' + option); }, ///# @name spacing ///# @description Used to validate the spacing option ///# @arg {number} option - The option to validate against ///# @throws {error} - If the spacing option that was pass was invalid spacing: function spacing(option) { if (option === '0' || option === 'null') { option = 0; } if (!_toJs.is.number(option)) { throw new Error('The spacing option must be a number'); } }, ///# @name output ///# @description Used to validate the output option ///# @arg {string} option - The option to validate against ///# @throws {error} - If the output option that was pass was invalid output: function output(option) { if (!isString(option, 'output')) return; if (output_types.indexOf(option) !== -1 || !_path2.default.extname(option)) { return; } throw new Error('The output option must be ' + output_types.join(', ') + ', or a folder path'); }, ///# @name highlight ///# @description Used to validate the highlight option ///# @arg {boolean} option - The option to validate against ///# @throws {error} - If the highlight option that was pass was invalid highlight: function highlight(option) { if (!_toJs.is.boolean(option)) { throw new Error('The highlight option must be a boolean'); } }, ///# @name limit ///# @description Used to validate the limit option ///# @arg {number} option - The option to validate against ///# @throws {error} - If the limit option that was pass was invalid limit: function limit(option) { if (!_toJs.is.number(option)) { throw new Error('The limit option must be a number'); } }, ///# @name archive ///# @description Used to validate the archive option ///# @arg {boolean} option - The option to validate against ///# @throws {error} - If the archive option that was pass was invalid archive: function archive(option, _ref6) { var output = _ref6.output; if (!_toJs.is.string(option)) { throw new Error('The archive option must be a string'); } // there's no archive file specified if (!option.length) return; if (option && ['return', 'console'].indexOf(output) !== -1) { throw new Error('You can\'t have an archive file when you have the output option set to ' + output); } else if (_path2.default.extname(option) !== '.zip') { throw new Error('The archive file must have a file extention of `.zip`'); } }, ///# @name server ///# @description Used to validate the server option ///# @arg {string} option - The option to validate against ///# @arg {object} options - The other options for that are being validated ///# @throws {error} - If the server option that was pass was invalid server: function server(option, _ref7) { var output = _ref7.output, archive = _ref7.archive; // ignore this validation if the output isn't one of these if (!isServer(output)) return; if (archive === true) { throw new Error('The archive option can\'t be used with ' + option); } isString(option, 'server'); }, ///# @name bucket ///# @description Used to validate the bucket option ///# @arg {string} option - The option to validate against ///# @arg {object} options - The other options for that are being validated ///# @throws {error} - If the bucket option that was pass was invalid bucket: function bucket(option, _ref8) { var output = _ref8.output; // ignore this validation if the output isn't one of these if (!isServer(output)) return; isString(option, 'bucket'); }, ///# @name username ///# @description Used to validate the username option ///# @arg {string} option - The option to validate against ///# @arg {object} options - The other options for that are being validated ///# @throws {error} - If the username option that was pass was invalid username: function username(option) { if (!_toJs.is.string(option)) { throw new Error('The username option must be a string'); } }, ///# @name password ///# @description Used to validate the password option ///# @arg {string} option - The option to validate against ///# @arg {object} options - The other options for that are being validated ///# @throws {error} - If the password option that was pass was invalid password: function password(option) { if (!_toJs.is.string(option)) { throw new Error('The password option must be a string'); } }, ///# @name limit ///# @description Used to validate the limit option ///# @arg {number} option - The option to validate against ///# @throws {error} - If the limit option that was pass was invalid timeout: function timeout(option) { if (!_toJs.is.number(option)) { throw new Error('The timeout option must be a number'); } }, ///# @name useStreams ///# @description Used to validate the useStreams option ///# @arg {boolean} option - The option to validate against ///# @throws {error} - If the useStreams option that was pass was invalid useStreams: function useStreams(option) { if (!_toJs.is.boolean(option)) { throw new Error('The useStreams option must be a boolean'); } }, ///# @name highWaterMark ///# @description Used to validate the highWaterMark option ///# @arg {number} option - The option to validate against ///# @throws {error} - If the highWaterMark option that was pass was invalid highWaterMark: function highWaterMark(option) { if (!_toJs.is.number(option)) { throw new Error('The highWaterMark option must be a number'); } } }; /// @name isServer /// @description This is used to check if the output is `sync-gateway` or `couchbase` /// @arg {string} output - The output that's being used /// @returns {boolean} - If true the output option is a server function isServer(output) { return ['sync-gateway', 'couchbase'].indexOf(output) !== -1; } /// @name isString /// @description This is used to check if an option is a string and that it has a length /// @arg {*} option - The option that's passed /// @arg {string} name - The name of the validate function that this is called in /// @returns {boolean} - If true the option that was passed is a string and has a length. /// @throws {error} - If the option isn't a string /// @throws {error} - If the option is a string and doesn't have a length function isString(option) { var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; if (!!name) { name = ' ' + name + ' '; } if (!_toJs.is.string(option)) { throw new Error('The' + name + 'option must be a string'); } else if (_toJs.is.string(option) && !option.length) { throw new Error('The' + name + 'option must have a length'); } return true; }