diff --git a/lib/LoggerHelpers.ts b/lib/LoggerHelpers.ts new file mode 100644 index 0000000..9cc74a5 --- /dev/null +++ b/lib/LoggerHelpers.ts @@ -0,0 +1,17 @@ +export namespace LoggerHelpers { + function getLogger(persistor, logger) { + return logger || persistor.logger; + } + + export function debug(persistor, logger, logObj, message) { + getLogger(persistor, logger).debug(logObj, message); + } + + export function error(persistor, logger, logObj, message) { + getLogger(persistor, logger).error(logObj, message); + } + + export function info(persistor, logger, logObj, message) { + getLogger(persistor, logger).info(logObj, message); + } +} \ No newline at end of file diff --git a/lib/api.ts b/lib/api.ts index 0e93a4a..0a9b518 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -10,7 +10,7 @@ * */ -import { PersistorTransaction, RemoteDocConnectionOptions } from './types'; +import {PersistorTransaction, RemoteDocConnectionOptions} from './types'; module.exports = function (PersistObjectTemplate, baseClassForPersist) { @@ -56,7 +56,7 @@ module.exports = function (PersistObjectTemplate, baseClassForPersist) { } } } - } + }; /** * PUBLIC INTERFACE FOR TEMPLATES @@ -67,7 +67,8 @@ module.exports = function (PersistObjectTemplate, baseClassForPersist) { this._prepareSchema(template); this._injectTemplateFunctions(template); this._injectObjectFunctions(template); - } + }; + PersistObjectTemplate._prepareSchema = function (template) { if (!this.schemaVerified) { this._verifySchema(); @@ -305,7 +306,7 @@ module.exports = function (PersistObjectTemplate, baseClassForPersist) { let deleteQuery = dbType == PersistObjectTemplate.DB_Mongo ? PersistObjectTemplate.deleteFromPersistWithMongoQuery(template, query, options.logger) : PersistObjectTemplate.deleteFromKnexByQuery(template, query, options.transaction, options.logger); - + const name = 'persistorDeleteByQuery'; return deleteQuery .then(result => { @@ -578,7 +579,7 @@ module.exports = function (PersistObjectTemplate, baseClassForPersist) { template.createProperty(closureProp + 'Persistor', { type: Object, toClient: toClient, toServer: false, persist: false, - value: { isFetched: defineProperty.autoFetch ? false : true, isFetching: false } + value: {isFetched: !defineProperty.autoFetch, isFetching: false} }); } if (!template.prototype[closureProp + 'Fetch']) @@ -919,7 +920,7 @@ module.exports = function (PersistObjectTemplate, baseClassForPersist) { configurable: true }) - + Object.defineProperty(template.prototype, 'objectTemplateName', { get: function () { return (this.constructor && this.constructor.name) || template.__name__; diff --git a/lib/knex/Helpers.ts b/lib/knex/Helpers.ts new file mode 100644 index 0000000..0e74420 --- /dev/null +++ b/lib/knex/Helpers.ts @@ -0,0 +1,32 @@ +import * as _ from 'underscore'; + +export namespace Helpers { + export function iscompatible(persistortype, pgtype) { + switch (persistortype) { + case 'String': + case 'Object': + case 'Array': + return pgtype.indexOf('text') > -1; + case 'Number': + return pgtype.indexOf('double precision') > -1; + case 'Boolean': + return pgtype.indexOf('bool') > -1; + case 'Date': + return pgtype.indexOf('timestamp') > -1; + default: + return pgtype.indexOf('text') > -1; // Typed objects have no name + } + } + + export function getPropsRecursive(template, map?) { + map = map || {}; + _.map(template.getProperties(), function (val, prop) { + map[prop] = val + }); + template = template.__children__; + template.forEach(function (template) { + getPropsRecursive(template, map); + }); + return map; + } +} \ No newline at end of file diff --git a/lib/knex/commit/IdentifyChanges.ts b/lib/knex/commit/IdentifyChanges.ts new file mode 100644 index 0000000..3d0f162 --- /dev/null +++ b/lib/knex/commit/IdentifyChanges.ts @@ -0,0 +1,107 @@ +// Identifies changes for change tracking purposes + +import {ChangeTracking, ObjectChanges, PropertyChanges} from '../../types'; + +export namespace IdentifyChanges { + + // Entrance from Mappers + export function generateChanges(obj, action: string, changeTracking: ChangeTracking, notifyChanges) { + + if (notifyChanges && isChangeTrackingEnabled(obj)) { + const templateName = obj.__template__.__name__; + let objChanges: ObjectChanges = { + table: obj.__template__.__table__, + primaryKey: obj._id, + action: action, + properties: [] + }; + + changeTracking = changeTracking || {}; + changeTracking[templateName] = changeTracking[templateName] || []; + + if (action === 'update' || action === 'delete') { + const props = obj.__template__.getProperties(); + for (var prop in props) { + if (!isArrayOrPersistorShadowProp(props, prop)) { + generatePropertyChanges(props, objChanges, prop, obj); + } + } + } + + // Pushing changes into changeTracking for postSave + changeTracking[templateName].push(objChanges); + } + } + + function isChangeTrackingEnabled(obj) { + return !!(obj.__template__ && obj.__template__.__schema__ && obj.__template__.__schema__.enableChangeTracking); + } + + // This is a confusing function, however, I've decoded it. + // Prop[propName] here, is the property definition of a property within a class, and not the actual instance itself + // For example props[propName] for homeAddress field could be {toClient: true} or {getType: () => Array }, etc. + // However, we also have persistor shadow properties to hold metadata (fancy word for junk) about the original property. + // So homeAddressPersistor will have the isFetched, id fields as well. + // We don't want to then generate property changes for any of these shadow props, or even for the Array refs, + // which we handle at a later time (I suppose) + function isArrayOrPersistorShadowProp(props, propName) { + const propertyDefinition = props[propName]; + const isArrayOrObjectTemplate = propertyDefinition.type === Array && propertyDefinition.of.isObjectTemplate; + // @TODO: This may be buggy as propName.match(/Persistor$/) used to be prop.match(/Persistor$/), but prop is not in this scope + const isPersistorObject = propName.match(/Persistor$/) && typeof props[propName.replace(/Persistor$/, '')] === 'object'; + return isArrayOrObjectTemplate || isPersistorObject; + } + + function generatePropertyChanges(props, objChanges, prop, obj) { + // When the property type is not an object template, need to compare the values. + // for date and object types, need to compare the stringified values. + let newValue; + let changedProperties: PropertyChanges = {}; + const oldKey = `_ct_org_${prop}`; + const oldValue = obj[oldKey]; + const propertyDefinition = props[prop]; + + if (!propertyDefinition.type.isObjectTemplate) { + newValue = obj[prop]; + if (oldValue !== newValue || (dateOrObject(propertyDefinition.type) && !isStringifiesEqual(oldValue, newValue))) { + changedProperties = { + name: prop, + originalValue: oldValue, + newValue: newValue, + columnName: prop + }; + } + } else { + newValue = obj[`${prop}Persistor`]; + if (newValue && oldValue !== newValue.id) { + changedProperties = { + name: prop, + originalValue: oldValue, // @TODO: why is this oldValue and not oldValue.id? + newValue: newValue.id, // @TODO: Why is this newValue and not newValue.id? + columnName: getColumnName(prop, obj) + }; + } + } + + if (!(Object.entries(changedProperties).length === 0 && changedProperties.constructor === Object)) { + objChanges.properties.push(changedProperties); + } + } + + function dateOrObject(type) { + return type === Date || type === Object; + } + + function isStringifiesEqual(oldValue, newValue) { + return JSON.stringify(oldValue) === JSON.stringify(newValue) + } + + + function getColumnName(prop, obj): string { + let schema = obj.__template__.__schema__; + if (!schema || !schema.parents || !schema.parents[prop] || !schema.parents[prop].id) { + throw new Error(`${obj.__template__.__name__}.${prop} is missing a parents schema entry`); + } + return schema.parents[prop].id; + } +} \ No newline at end of file diff --git a/lib/knex/commit/Mappers.ts b/lib/knex/commit/Mappers.ts new file mode 100644 index 0000000..c52ff11 --- /dev/null +++ b/lib/knex/commit/Mappers.ts @@ -0,0 +1,46 @@ +import {DeleteQuery, PersistorTransaction} from '../../types/PersistorTransaction'; +import {IdentifyChanges} from './IdentifyChanges'; +import {ChangeTracking, Objects} from '../../types'; +// Mappers +export namespace Mappers { + + export async function saveMapper(obj, dirtyObjects: Objects, changeTracking: ChangeTracking, notifyChanges, txn: PersistorTransaction, logger?) { + delete dirtyObjects[obj.__id__]; // Once scheduled for update remove it. + + if (hasSchema(obj)) { // replace callSave; + await obj.persistSave(txn, logger); + } + + let action: string = ''; + if (obj.__version__ === 1) { // insert + action = 'insert'; + } else { + action = 'update'; + } + return IdentifyChanges.generateChanges(obj, action, changeTracking, notifyChanges); + } + + + export async function deleteMapper(obj, deletedObjects: Objects, changeTracking: ChangeTracking, notifyChanges, txn: PersistorTransaction, logger?) { + delete deletedObjects[obj.__id__]; + + if (hasSchema(obj)) { + await obj.persistDelete(txn, logger); // replace callDelete + } + + return IdentifyChanges.generateChanges(obj, 'delete', changeTracking, notifyChanges); + } + + // Persistor Def is typeof Persistor + export async function deleteQueryMapper(persistorDef, obj: DeleteQuery, deleteQueries: Objects, txn: PersistorTransaction, logger?) { + delete deleteQueries[obj.__name__]; // Once scheduled for update remove it. + + if (hasSchema(obj)) { + await persistorDef.deleteFromKnexQuery(obj.__template__, obj.queryOrChains, txn, logger); + } + } + + function hasSchema(obj): boolean { + return !!(obj.__template__ && obj.__template__.__schema__); + } +} \ No newline at end of file diff --git a/lib/knex/commit/RollbackS3.ts b/lib/knex/commit/RollbackS3.ts new file mode 100644 index 0000000..a649116 --- /dev/null +++ b/lib/knex/commit/RollbackS3.ts @@ -0,0 +1,37 @@ +import {RemoteDocService} from '../../remote-doc/RemoteDocService'; +import {LoggerHelpers} from '../../LoggerHelpers'; +import {PersistorTransaction} from '../../types'; + +// Rollback S3 Changes +export namespace RollbackS3 { + + // Persistor Def is typeof Persistor + export async function rollbackS3(persistorDef, logger, txn: PersistorTransaction) { + LoggerHelpers.info(persistorDef, logger, { + component: 'persistor', + module: 'api', + activity: 'end' + }, `Rolling back transaction of remote keys`); + const remoteDocService = RemoteDocService.new(persistorDef.environment); + const toDeletePromiseArr = []; + + // create our `delete functions` to be run later. + // also put them in one place => toDeletePromiseArr. + + for (const key of txn.remoteObjects) { // @TODO: how does this work right now? If doesn't work on sets + toDeletePromiseArr.push(rollbackS3Key(persistorDef, logger, key, remoteDocService)); + } + + // fire off our delete requests in parallel + await Promise.all(toDeletePromiseArr); + } + + async function rollbackS3Key(persistorDef, logger, key, remoteDocService: RemoteDocService) { + try { + await remoteDocService.deleteDocument(key, persistorDef.bucketName); + } catch (e) { + const newLogObj = {component: 'persistor', module: 'api', activity: 'end', error: e}; + LoggerHelpers.error(persistorDef, logger, newLogObj, `Unable to rollback remote document with key: ${key} and bucket: ${persistorDef.bucketName}`); + } + } +} \ No newline at end of file diff --git a/lib/knex/commit/Transaction.ts b/lib/knex/commit/Transaction.ts new file mode 100644 index 0000000..ed208f5 --- /dev/null +++ b/lib/knex/commit/Transaction.ts @@ -0,0 +1,147 @@ +import {Mappers} from './Mappers'; +import {LoggerHelpers} from '../../LoggerHelpers'; +import {RollbackS3} from './RollbackS3'; +import {ChangeTracking, DeleteQueries, Objects, PersistorTransaction} from '../../types'; +import _ = require("underscore"); + +// Main Transaction executor +export namespace Transaction { + + + // Wrapper for transaction function + + export async function transaction(persistorDef, notifyChanges, txn: PersistorTransaction, knexTxn, logger): Promise { + const {dirtyObjects, touchObjects, savedObjects, deletedObjects, deleteQueries} = txn; + let changeTracking = {}; + + txn.knex = knexTxn; + try { + await preSave(txn, logger); + await saves(dirtyObjects, changeTracking, notifyChanges, txn, logger); + await deletes(deletedObjects, changeTracking, notifyChanges, txn, logger); + await deletesQueries(persistorDef, deleteQueries, txn, logger); + await touches(touchObjects, savedObjects, txn, logger); + await postSave(txn, changeTracking, logger); + await commit(persistorDef, txn, knexTxn); + } catch (err) { + return await rollback(persistorDef, logger, txn, knexTxn, err); + } + } + + // Processor Handlers + + async function preSave(txn: PersistorTransaction, logger) { + if (txn.preSave) { + return txn.preSave(txn, logger); + } else { + return true; + } + } + + async function saves(dirtyObjects: Objects, changeTracking: ChangeTracking, notifyChanges, txn: PersistorTransaction, logger) { + + // Walk through the dirty objects + const dirtyObjectsArray = _.toArray(dirtyObjects); //@TODO: replace with Object.values + await Promise.all(dirtyObjectsArray.map((obj) => + Mappers.saveMapper(obj, dirtyObjects, changeTracking, notifyChanges, txn, logger))); + + const refreshedDirtyArray = _.toArray(dirtyObjects); + if (refreshedDirtyArray.length > 0) { + return saves(dirtyObjects, changeTracking, notifyChanges, txn, logger); + } + } + + async function deletes(deletedObjects: Objects, changeTracking: ChangeTracking, notifyChanges, txn: PersistorTransaction, logger) { + const deletedObjectsArray = _.toArray(deletedObjects); + await Promise.all(deletedObjectsArray.map((obj) => + Mappers.deleteMapper(obj, deletedObjects, changeTracking, notifyChanges, txn, logger))); + + const refreshedDeletedArray = _.toArray(deletedObjects); + if (refreshedDeletedArray.length > 0) { + return deletes(deletedObjects, changeTracking, notifyChanges, txn, logger); + } + } + + async function deletesQueries(persistorDef, deleteQueries: Objects, txn: PersistorTransaction, logger) { + const deleteQueriesArray: DeleteQueries = _.toArray(deleteQueries); // @TODO: Is this needed? This is already an array + + await Promise.all(deleteQueriesArray.map((obj) => + Mappers.deleteQueryMapper(persistorDef, obj, deleteQueries, txn, logger))); + + const refreshedDeleteQueriesArray = _.toArray(deleteQueries); + if (refreshedDeleteQueriesArray.length > 0) { + return deletesQueries(persistorDef, deleteQueries, txn, logger); + } + } + + // Walk through the touched objects + async function touches(touchObjects: Objects, savedObjects: Objects, txn: PersistorTransaction, logger?) { + const touchObjectsArray = _.toArray(touchObjects); + + return Promise.all(touchObjectsArray.map(async (obj: any) => { + if (obj.__template__ && obj.__template__.__schema__ && !savedObjects[obj.__id]) { + return obj.persistTouch(txn, logger); + } + })); + } + + async function postSave(txn: PersistorTransaction, changeTracking: ChangeTracking, logger) { + if (txn.postSave) { + return txn.postSave(txn, logger, changeTracking); + } + } + + // And we are done with everything. Commit or throw an update conflict if seen + async function commit(persistorDef, txn: PersistorTransaction, knexTxn) { + + // Reset global state, @TODO: remove this global state + persistorDef.dirtyObjects = {}; + persistorDef.savedObjects = {}; + + // Set through persistSaveKnex -> SaveKnexPojo -> checkUpdateResults + if (txn.updateConflict) { + throw 'Update Conflict'; + } + + // commit knex transaction + return knexTxn.commit(); + } + + // rollback if there's an error while processing any stage of this + // including just generating the SQL queries / checking the versions + // or even at the commit step + + // @returns innerError + async function rollback(persistorDef, logger, txn: PersistorTransaction, knexTxn, err: Error): Promise { + const deadlock = err.toString().match(/deadlock detected$/i); + txn.innerError = err; + let innerError; + + if (deadlock) { + innerError = new Error('Update Conflict'); + } else { + innerError = err; + } + + // @TODO: What if knex rollback fails? But S3 Works out? + if (txn.remoteObjects && txn.remoteObjects.size > 0) { + await RollbackS3.rollbackS3(persistorDef, logger, txn); + } + + await knexTxn.rollback(innerError); + const newLogObject = { + component: 'persistor', + module: 'api', + activity: 'end' + }; + + let fromDeadlock = ''; + if (deadlock) { + fromDeadlock = ' from deadlock'; + } + + LoggerHelpers.debug(persistorDef, logger, newLogObject, `Transaction rolled back ${innerError.message}${fromDeadlock}`); + + return innerError; + } +} \ No newline at end of file diff --git a/lib/knex/db.ts b/lib/knex/db.ts index c0129de..82fdd10 100644 --- a/lib/knex/db.ts +++ b/lib/knex/db.ts @@ -1,4 +1,10 @@ -import {RemoteDocService} from "../remote-doc/RemoteDocService"; +import {DeleteQueries, PersistorTransaction} from '../types'; +import {LoggerHelpers} from '../LoggerHelpers'; +import {Transaction} from './commit/Transaction'; +import {MongoQuery} from './mongoQuery/MongoQuery'; +import {Indexes} from './synchronize/Indexes'; +import {Helpers} from './Helpers'; + module.exports = function (PersistObjectTemplate) { @@ -37,7 +43,7 @@ module.exports = function (PersistObjectTemplate) { if (typeof(queryOrChains) == 'function') queryOrChains(select); else if (queryOrChains) - select = this.convertMongoQueryToChains(tableName, select, queryOrChains); + select = MongoQuery.convertMongoQueryToChains(tableName, select, queryOrChains); // Convert mongo style sort if (options && options.sort) { @@ -101,12 +107,12 @@ module.exports = function (PersistObjectTemplate) { template = template.__parent__; asStandard(template, this.dealias(template.__table__)); - _.each(getPropsRecursive(template), function (defineProperties, prop) { + _.each(Helpers.getPropsRecursive(template), function (defineProperties, prop) { as(template, this.dealias(template.__table__), prop, defineProperties) }.bind(this)); _.each(joins, function (join) { asStandard(join.template, join.alias); - _.each(getPropsRecursive(join.template), function (defineProperties, prop) { + _.each(Helpers.getPropsRecursive(join.template), function (defineProperties, prop) { as(join.template, join.alias, prop, defineProperties) }) }.bind(this)); @@ -136,18 +142,6 @@ module.exports = function (PersistObjectTemplate) { } cols.push(prefix + '.' + prop + ' as ' + (prefix ? prefix + '___' : '') + prop); } - - function getPropsRecursive(template, map?) { - map = map || {}; - _.map(template.getProperties(), function (val, prop) { - map[prop] = val - }); - template = template.__children__; - template.forEach(function (template) { - getPropsRecursive(template, map); - }); - return map; - } } }; /** @@ -166,7 +160,7 @@ module.exports = function (PersistObjectTemplate) { if (typeof(queryOrChains) == 'function') queryOrChains(knex); else if (queryOrChains) - (this.convertMongoQueryToChains)(tableName, knex, queryOrChains); + MongoQuery.convertMongoQueryToChains(tableName, knex, queryOrChains); return knex.count('_id').then(function (ret) { return ret[0].count * 1; @@ -244,18 +238,21 @@ module.exports = function (PersistObjectTemplate) { if (typeof(queryOrChains) == 'function') queryOrChains(knex); else if (queryOrChains) - (this.convertMongoQueryToChains)(tableName, knex, queryOrChains); + (MongoQuery.convertMongoQueryToChains)(tableName, knex, queryOrChains); return knex.delete(); }; - PersistObjectTemplate.deleteFromKnexByQuery = async function (template, queryOrChains, txn, _logger) { + PersistObjectTemplate.deleteFromKnexByQuery = async function (template, queryOrChains, txn: PersistorTransaction, _logger) { if (!txn) { return PersistObjectTemplate.deleteFromKnexQuery(template, queryOrChains, txn, _logger); } - var deleteQueries = txn ? txn.deleteQueries : this.deleteQueries; - var deleteQuery = {name: template.__name__, template: template, queryOrChains: queryOrChains}; - deleteQueries[template.__name__] = deleteQuery; + var deleteQueries: DeleteQueries = txn ? txn.deleteQueries : this.deleteQueries; + deleteQueries[template.__name__] = { + __name__: template.__name__, + __template__: template, + queryOrChains: queryOrChains + }; txn.deleteQueries = deleteQueries; }; @@ -390,7 +387,7 @@ module.exports = function (PersistObjectTemplate) { throw new Error(template.__name__ + ' is missing a schema entry'); } - var props = getPropsRecursive(template); + var props = Helpers.getPropsRecursive(template); var knex = this.getDB(this.getDBAlias(template.__table__)).connection; var schema = template.__schema__; var _newFields = {}; @@ -398,7 +395,7 @@ module.exports = function (PersistObjectTemplate) { return Promise.resolve() .then(buildTable.bind(this)) .then(addComments.bind(this, tableName)) - .then(synchronizeIndexes.bind(this, tableName, template)); + .then(() => Indexes.sync(this, tableName, template)); function buildTable() { return knex.schema.hasTable(tableName).then(function (exists) { @@ -567,7 +564,7 @@ module.exports = function (PersistObjectTemplate) { _newFields[prop] = props[prop]; } else { - if (!iscompatible(props[prop].type.name, info[propToColumnName(prop)].type)) { + if (!Helpers.iscompatible(props[prop].type.name, info[propToColumnName(prop)].type)) { throw new Error('Changing the type of ' + prop + ' on ' + table + ', changing types for the fields is not allowed, please use scripts to make these changes'); } @@ -602,254 +599,6 @@ module.exports = function (PersistObjectTemplate) { } } - function synchronizeIndexes(tableName, template) { - - var aliasedTableName = template.__table__; - tableName = this.dealias(aliasedTableName); - - while (template.__parent__) { - template = template.__parent__; - } - - if (!template.__table__) { - throw new Error(template.__name__ + ' is missing a schema entry'); - } - - var knex = this.getDB(this.getDBAlias(template.__table__)).connection; - var schema = this._schema; - - var _dbschema; - var _changes = {}; - var schemaTable = 'index_schema_history'; - var schemaField = 'schema'; - - - var loadSchema = function (tableName) { - - if (!!_dbschema) { - //@ts-ignore - return (_dbschema, tableName); - } - - return knex.schema.hasTable(schemaTable).then(function(exists) { - if (!exists) { - return knex.schema.createTable(schemaTable, function(table) { - table.increments('sequence_id').primary(); - table.text(schemaField); - table.timestamps(); - }) - } - }).then(function () { - return knex(schemaTable) - .orderBy('sequence_id', 'desc') - .limit(1); - }).then(function (record) { - var response; - if (!record[0]) { - response = {}; - } - else { - response = JSON.parse(record[0][schemaField]); - } - _dbschema = response; - return [response, template.__name__]; - }) - }; - - var loadTableDef = function(dbschema, tableName) { - if (!dbschema[tableName]) - dbschema[tableName] = {}; - return [dbschema, schema, tableName]; - }; - - var diffTable = function(dbschema, schema, tableName) { - var dbTableDef = dbschema[tableName]; - var memTableDef = schema[tableName]; - var track = {add: [], change: [], delete: []}; - _diff(dbTableDef, memTableDef, 'delete', false, function (_dbIdx, memIdx) { - return !memIdx; - }, _diff(memTableDef, dbTableDef, 'change', false, function (memIdx, dbIdx) { - return memIdx && dbIdx && !_.isEqual(memIdx, dbIdx); - }, _diff(memTableDef, dbTableDef, 'add', true, function (_memIdx, dbIdx) { - return !dbIdx; - }, track))); - _changes[tableName] = _changes[tableName] || {}; - - _.map(_.keys(track), function(key) { - _changes[tableName][key] = _changes[tableName][key] || []; - _changes[tableName][key].push.apply(_changes[tableName][key], track[key]); - }); - - function _diff(masterTblSchema, shadowTblSchema, opr, addMissingTable, addPredicate, diffs) { - - if (!!masterTblSchema && !!masterTblSchema.indexes && masterTblSchema.indexes instanceof Array && !!shadowTblSchema) { - (masterTblSchema.indexes || []).forEach(function (mstIdx) { - var shdIdx = _.findWhere(shadowTblSchema.indexes, {name: mstIdx.name}); - - if (addPredicate(mstIdx, shdIdx)) { - diffs[opr] = diffs[opr] || []; - diffs[opr].push(mstIdx); - } - }); - } else if (addMissingTable && !!masterTblSchema && !!masterTblSchema.indexes) { - diffs[opr] = diffs[opr] || []; - diffs[opr].push.apply(diffs[opr], masterTblSchema.indexes); - } - return diffs; - } - }; - - var generateChanges = function (localtemplate, _value) { - return _.reduce(localtemplate.__children__, function (_curr, o) { - return Promise.resolve() - .then(loadTableDef.bind(this, _dbschema, o.__name__)) - .spread(diffTable) - .then(generateChanges.bind(this, o)); - }, {}); - }; - - var getFilteredTarget = function(src, target) { - return _.filter(target, function(o, _filterkey) { - var currName = _.reduce(o.def.columns, function (name, col) { - return name + '_' + col; - }, 'idx_' + tableName); - return !_.find(src, function(cached) { - var cachedName = _.reduce(cached.def.columns, function (name, col) { - return name + '_' + col; - }, 'idx_' + tableName); - return (cachedName.toLowerCase() === currName.toLowerCase()) - }) - }); - }; - - var mergeChanges = function() { - var dbChanges = {add: [], change: [], delete: []}; - _.map(dbChanges, function(_object, key) { - _.each(_changes, function(change) { - var uniqChanges = _.uniq(change[key], function(o) { - return o.name; - }); - var filtered = getFilteredTarget(dbChanges[key], uniqChanges); - dbChanges[key].push.apply(dbChanges[key], filtered); - }) - }); - - return dbChanges; - }; - - var applyTableChanges = function(dbChanges) { - function syncIndexesForHierarchy (operation, diffs, table) { - _.map(diffs[operation], (function (object, _key) { - var type = object.def.type; - var columns = object.def.columns; - if (type !== 'unique' && type !== 'index') - throw new Error('index type can be only "unique" or "index"'); - - var name = _.reduce(object.def.columns, function (name, col) { - return name + '_' + col; - }, 'idx_' + tableName); - - name = name.toLowerCase(); - if (operation === 'add') { - table[type](columns, name); - } - else if (operation === 'delete') { - type = type.replace(/index/, 'Index'); - type = type.replace(/unique/, 'Unique'); - table['drop' + type]([], name); - } - else - table[type](columns, name); - - })); - } - - - return knex.transaction(function (trx) { - return trx.schema.table(tableName, function (table) { - syncIndexesForHierarchy('delete', dbChanges, table); - syncIndexesForHierarchy('add', dbChanges, table); - syncIndexesForHierarchy('change', dbChanges, table); - }) - }) - }; - - var isSchemaChanged = function(object) { - return (object.add.length || object.change.length || object.delete.length) - }; - - var makeSchemaUpdates = function () { - var chgFound = _.reduce(_changes, function (curr, change) { - return curr || !!isSchemaChanged(change); - }, false); - - if (!chgFound) return; - - return knex(schemaTable) - .orderBy('sequence_id', 'desc') - .limit(1).then(function (record) { - var response = {}, sequence_id; - if (!record[0]) { - sequence_id = 1; - } - else { - response = JSON.parse(record[0][schemaField]); - sequence_id = ++record[0].sequence_id; - } - _.each(_changes, function (_o, chgKey) { - response[chgKey] = schema[chgKey]; - }); - - return knex(schemaTable).insert({ - sequence_id: sequence_id, - schema: JSON.stringify(response) - }); - }) - }; - - return Promise.resolve() - .then(loadSchema.bind(this, tableName)) - .spread(loadTableDef) - .spread(diffTable) - .then(generateChanges.bind(this, template)) - .then(mergeChanges) - .then(applyTableChanges) - .then(makeSchemaUpdates) - .catch(function(e) { - throw e; - }) - } - - - - function iscompatible(persistortype, pgtype) { - switch (persistortype) { - case 'String': - case 'Object': - case 'Array': - return pgtype.indexOf('text') > -1; - case 'Number': - return pgtype.indexOf('double precision') > -1; - case 'Boolean': - return pgtype.indexOf('bool') > -1; - case 'Date': - return pgtype.indexOf('timestamp') > -1; - default: - return pgtype.indexOf('text') > -1; // Typed objects have no name - } - } - - function getPropsRecursive(template, map?) { - map = map || {}; - _.map(template.getProperties(), function (val, prop) { - map[prop] = val - }); - template = template.__children__; - template.forEach(function (template) { - getPropsRecursive(template, map); - }); - return map; - } PersistObjectTemplate.persistTouchKnex = function(obj, txn, logger) { (logger || this.logger).debug({component: 'persistor', module: 'db.persistTouchKnex', activity: 'pre', @@ -873,7 +622,7 @@ module.exports = function (PersistObjectTemplate) { collection = collection || template.__table__; var tableName = this.dealias(collection); return PersistObjectTemplate._createKnexTable(template, collection) - .then(synchronizeIndexes.bind(this, tableName, template)) + .then(() => Indexes.sync(this, tableName, template)) }; /** @@ -954,393 +703,38 @@ module.exports = function (PersistObjectTemplate) { return knex.schema.dropTableIfExists(tableName); }; - /** - * Take a query object like {$or: [{type: 'foo'}, {x: {$gt: 4}, y: {$lte: 6}}]} - * which could also be expressed as: {$or: [{type: 'foo'}, {$and: [{x: {$gt: 4}}, {y: {$lte: 6}}]}]} - * and append to a knex statement like knex('table').select('*') these chains ... - * .where('type', '=', 'foo').orWhere(function () { - * this.where(x, '>', 4).andWhere(y, '<=', 6) - * }); - * - * {$or: [{type: 'foo', subtype: 'bar'}, {$or:[{x: {$gt: 4}}, {x: 9}], y: {$lte: 6}}]} - * .where('type', '=', 'foo').orWhere(function () { - * this.where(function () { - * this.where(x, '>', 4).orWhere(x, '=' 9) - * }).andWhere(y, '<=', 6) - * }); * - * @param {string} alias db alias name used when setting the database client object - * @param {string} statement knex query - * @param {object} query mongo style query object - * @returns {*} - */ - PersistObjectTemplate.convertMongoQueryToChains = function (alias, statement, query) { - - /** - * Traverse an object and produce a promise chain of where and andWhere - * @param {object} statement knex query - * @param {object} query mongo style query object - * @returns {*} - */ - function traverse(statement, query) { - var firstProp = true; - for (var prop in query) { - var params = processProp(statement, prop, query[prop]); - statement = firstProp ? - (params.length > 1 ? statement.where(params[0], params[1], params[2]) : - statement.where(params[0])) : - (params.length > 1 ? statement.andWhere(params[0], params[1], params[2]) : - statement.andWhere(params[0])); - firstProp = false; - } - return statement; - } - - function processProp(_statement, prop, value) { - if (value instanceof Array) - return processArrayProp(prop, value); - else - return processNonArrayProp(prop, value) - } - - function processArrayProp(prop, value) { - return [function () { - var firstProp; - var statement = this; - if (prop.toLowerCase() == '$and') { - firstProp = true; - _.each(value, function (obj) { - var params = processObject(statement, obj); - statement = firstProp ? - (params.length > 1 ? statement.where(params[0], params[1], params[2]) : - statement.where(params[0])) : - (params.length > 1 ? statement.andWhere(params[0], params[1], params[2]) : - statement.andWhere(params[0])); - firstProp = false; - }); - } else if (prop.toLowerCase() == '$or') { - firstProp = true; - _.each(value, function (obj) { - var params = processObject(statement, obj); - statement = firstProp ? - (params.length > 1 ? statement.where(params[0], params[1], params[2]) : - statement.where(params[0])) : - (params.length > 1 ? statement.orWhere(params[0], params[1], params[2]) : - statement.andWhere(params[0])); - firstProp = false - }); - } else if (prop.toLowerCase() == '$in') - statement = statement.whereIn(value); - else if (prop.toLowerCase() == '$nin') - statement = statement.whereNotIn(value); - else - throw 'Don\'t support ' + prop + ':' + JSON.stringify(value) - }]; - } - - /** - * Process an array element of a $or or $and. This will result in either three parameters in - * the form of prop, compare operator, value or a single parameter which is a function that - * will chain together a nested expression. - * @param {object} statement knex query object - * @param {object} obj object of supertype - * @returns {Function} - */ - function processObject(statement, obj) { - var propCount = 0; - var singleProp; - - // Do we have more than one prop - for (var prop in obj) { - singleProp = prop; - ++propCount; - } - - // If so fetch the 3 parameters for a where, orWhere or andWhere chain - // Otherwise return a function that will chain sub-ordinate clauses - if (propCount == 1) - return processProp(statement, singleProp, obj[singleProp]); - else - return [function () { - traverse(statement, obj) - }] - } - - function processNonArrayProp(prop, value) { - var params = []; - if (value instanceof Date || typeof(value) == 'string' || typeof(value) == 'number') { - params[0] = alias + '.' + prop; - params[1] = '='; - params[2] = value; - } else - for (var subProp in value) { - params[0] = alias + '.' + prop; - params[2] = value[subProp]; - if (subProp.toLowerCase() == '$eq') - params[1] = '='; - else if (subProp.toLowerCase() == '$gt') - params[1] = '>'; - else if (subProp.toLowerCase() == '$gte') - params[1] = '>='; - else if (subProp.toLowerCase() == '$lt') - params[1] = '<'; - else if (subProp.toLowerCase() == '$lte') - params[1] = '<='; - else if (subProp.toLowerCase() == '$ne') - params[1] = '!='; - else if (subProp.toLowerCase() == '$in') { - (function () { - var attr = params[0]; - var values = params[2]; - params = [function () { - this.whereIn(attr, values) - }]; - })() - } - else if (subProp.toLowerCase() == '$nin') - (function () { - var attr = params[0]; - var values = params[2]; - params = [function () { - this.whereNotIn(attr, values) - }]; - })() - else if (subProp.toLowerCase() == '$regex') { - params[1] = value.$options && value.$options.match(/i/) ? '~*' : '~'; - delete value['$options'] - if (params[2] && params[2].source) - params[2] = params[2].source; - } else - throw 'Can\'t handle ' + prop + ':' + JSON.stringify((value)); - } - return params; - } - - return traverse(statement, query) - } - - - PersistObjectTemplate._commitKnex = function _commitKnex(persistorTransaction, logger, notifyChanges) { + // Start the knex transaction + // We generate SQLs to save and to Delete and touches + // Each save / delete is done in 2 stages + // 1) We iterate through the objects and check to see if the version of any dirty / deleted objects are outdated + // if so, we set an update conflict flag to `True` on the transaction. @TODO: Perhaps should throw an error + // instead so we can stop generating random SQLS and end early + // 2) As we iterate through the objects in the first step, we generate SQL statements / attach them to the knex + // transaction + // 3) We identify which properties are changed, for change tracking purposes + // 4) We commit / finish the transaction + PersistObjectTemplate._commitKnex = async function _commitKnex(txn: PersistorTransaction, logger, notifyChanges) { logger.debug({component: 'persistor', module: 'api', activity: 'commit'}, 'end of transaction '); - var knex = _.findWhere(this._db, {type: PersistObjectTemplate.DB_Knex}).connection; - var dirtyObjects = persistorTransaction.dirtyObjects; - var touchObjects = persistorTransaction.touchObjects; - var savedObjects = persistorTransaction.savedObjects; - var deletedObjects = persistorTransaction.deletedObjects; - var deleteQueries = persistorTransaction.deleteQueries; - var innerError; - var changeTracking; - - // Start the knext transaction - return knex.transaction(function(knexTransaction) { - persistorTransaction.knex = knexTransaction; - - - Promise.resolve(true) - .then(processPreSave.bind(this)) - .then(processSaves.bind(this)) - .then(processDeletes.bind(this)) - .then(processDeleteQueries.bind(this)) - .then(processTouches.bind(this)) - .then(processPostSave.bind(this)) - .then(processCommit.bind(this)) - .catch(rollback.bind(this)); - - function processPreSave() { - return persistorTransaction.preSave - ? persistorTransaction.preSave.call(persistorTransaction, persistorTransaction, logger) - : true - } - - // Walk through the dirty objects - function processSaves() { - return Promise.map(_.toArray(dirtyObjects), function (obj) { - delete dirtyObjects[obj.__id__]; // Once scheduled for update remove it. - return callSave(obj).then(generateChanges.bind(this, obj, obj.__version__ === 1 ? 'insert' : 'update')); - }.bind(this), {concurrency: PersistObjectTemplate.concurrency}).then (function () { - if (_.toArray(dirtyObjects). length > 0) { - return processSaves.call(this); - } - }); - - function callSave(obj) { - return (obj.__template__ && obj.__template__.__schema__ - ? obj.persistSave(persistorTransaction, logger) - : Promise.resolve(true)); - } - } - - - function processDeletes() { - return Promise.map(_.toArray(deletedObjects), function (obj) { - delete deletedObjects[obj.__id__]; // Once scheduled for update remove it. - return callDelete(obj).then(generateChanges.bind(this, obj, 'delete')); - }.bind(this), {concurrency: PersistObjectTemplate.concurrency}).then (function () { - if (_.toArray(deletedObjects). length > 0) { - return processDeletes.call(this); - } - }); - - function callDelete(obj) { - return (obj.__template__ && obj.__template__.__schema__ - ? obj.persistDelete(persistorTransaction, logger) - : Promise.resolve(true)) - } - } - - function processDeleteQueries() { - return Promise.map(_.toArray(deleteQueries), function (obj) { - delete deleteQueries[obj.name]; // Once scheduled for update remove it. - return (obj.template && obj.template.__schema__ - ? PersistObjectTemplate.deleteFromKnexQuery(obj.template, obj.queryOrChains, persistorTransaction, logger) - : true) - }.bind(this), {concurrency: PersistObjectTemplate.concurrency}).then (function () { - if (_.toArray(deleteQueries). length > 0) { - return processDeleteQueries.call(this); - } - }); - } - - - function processPostSave() { - return persistorTransaction.postSave ? - persistorTransaction.postSave(persistorTransaction, logger, changeTracking) : - true; - } - - // And we are done with everything - function processCommit() { - this.dirtyObjects = {}; - this.savedObjects = {}; - if (persistorTransaction.updateConflict) { - throw 'Update Conflict'; - } - return knexTransaction.commit(); - } - - // Walk through the touched objects - function processTouches() { - return Promise.map(_.toArray(touchObjects), function (obj) { - return (obj.__template__ && obj.__template__.__schema__ && !savedObjects[obj.__id__] - ? obj.persistTouch(persistorTransaction, logger) - : true) - }.bind(this)) - } - - async function rollback (err) { - const deadlock = err.toString().match(/deadlock detected$/i); - persistorTransaction.innerError = err; - innerError = deadlock ? new Error('Update Conflict') : err; - - if (persistorTransaction.remoteObjects && persistorTransaction.remoteObjects.size > 0) { - (logger || this.logger).info({ - component: 'persistor', - module: 'api', - activity: 'end' - }, - `Rolling back transaction of remote keys`); - - let remoteDocService = RemoteDocService.new(this.environment); - - let toDeletePromiseArr = []; - - // create our `delete functions` to be run later. - // also put them in one place => toDeletePromiseArr. - for (const key of persistorTransaction.remoteObjects) { - toDeletePromiseArr.push(async () => { - try { - await remoteDocService.deleteDocument(key, this.bucketName); - } catch (e) { - (logger || this.logger).error({ - component: 'persistor', - module: 'api', - activity: 'end', - error: e}, - 'unable to rollback remote document with key:' + key + ' and bucket: ', this.bucketName); - } - }); - } - - // fire off our delete requests in parallel - await Promise.all(toDeletePromiseArr); - } - - return knexTransaction.rollback(innerError).then(() => { - (logger || this.logger).debug({ - component: 'persistor', - module: 'api', - activity: 'end'}, - 'transaction rolled back ' + innerError.message + (deadlock ? ' from deadlock' : '')); - }); - } - - function generateChanges(obj, action) { - var objChanges; - - if (notifyChanges && obj.__template__ && obj.__template__.__schema__ && obj.__template__.__schema__.enableChangeTracking) { - changeTracking = changeTracking || {}; - changeTracking[obj.__template__.__name__] = changeTracking[obj.__template__.__name__] || []; - changeTracking[obj.__template__.__name__].push(objChanges = { - table: obj.__template__.__table__, - primaryKey: obj._id, - action: action, - properties: [] - }); - if (action === 'update' || action === 'delete') { - var props = obj.__template__.getProperties(); - for (var prop in props) { - var propType = props[prop]; - if (isOnetoManyRelationsOrPersistorProps(prop, propType)) { - continue; - } - generatePropertyChanges(prop, obj); - } - } - } - - function isOnetoManyRelationsOrPersistorProps(propName, propType) { - return (propType.type === Array && propType.of.isObjectTemplate) || - (prop.match(/Persistor$/) && typeof props[propName.replace(/Persistor$/, '')] === 'object'); - } - - function generatePropertyChanges(prop, obj) { - //When the property type is not an object template, need to compare the values. - //for date and object types, need to compare the stringified values. - var oldKey = '_ct_org_' + prop; - if (!props[prop].type.isObjectTemplate && (obj[oldKey] !== obj[prop] || ((props[prop].type === Date || props[prop].type === Object) && - JSON.stringify(obj[oldKey]) !== JSON.stringify(obj[prop])))) { - addChanges(prop, obj[oldKey], obj[prop], prop); - } - //For one to one relations, we need to check the ids associated to the parent record. - else if (props[prop].type.isObjectTemplate && obj[prop + 'Persistor'] && obj['_ct_org_' + prop] !== obj[prop + 'Persistor'].id) { - addChanges(prop, obj[oldKey], obj[prop + 'Persistor'].id, getColumnName(prop, obj)); - } - } - - function getColumnName(prop, obj) { - var schema = obj.__template__.__schema__; - if (!schema || !schema.parents || !schema.parents[prop] || !schema.parents[prop].id) - throw new Error(obj.__template__.__name__ + '.' + prop + ' is missing a parents schema entry'); - return schema.parents[prop].id; - } - - function addChanges(prop, originalValue, newValue, columnName) { - objChanges.properties.push({ - name: prop, - originalValue: originalValue, - newValue: newValue, - columnName: columnName - }); - } - } - }.bind(this)).then(function () { - (logger || this.logger).debug({component: 'persistor', module: 'api'}, 'end - transaction completed'); + const knex = _.findWhere(this._db, {type: PersistObjectTemplate.DB_Knex}).connection; + let innerError; + + // Apparently it seems like Knex takes an async callback, and implicitly waits for it to trigger knex.commit. + // This is confusing behavior + try { + innerError = await knex.transaction((knexTxn) => Transaction.transaction(this, notifyChanges, txn, knexTxn, logger)); // @TODO: Is Knex.transaction async? + LoggerHelpers.debug(this, logger, {component: 'persistor', module: 'api'}, 'End - transaction completed'); return true; - }.bind(this)).catch(function (e) { - var err = e || innerError; + } catch (e) { + const err = e || innerError; if (err && err.message && err.message != 'Update Conflict') { - (logger || this.logger).error({component: 'persistor', module: 'api', activity: 'end', error: err.message + err.stack}, 'transaction ended with error'); - } //@TODO: Why throw error in all cases but log only in some cases - throw (e || innerError); - }.bind(this)) + LoggerHelpers.error(this, logger, { + component: 'persistor', + module: 'api', + activity: 'end', + error: err.message + err.stack + }, 'Transaction ended with error'); + } + throw err; + } } }; \ No newline at end of file diff --git a/lib/knex/mongoQuery/MongoQuery.ts b/lib/knex/mongoQuery/MongoQuery.ts new file mode 100644 index 0000000..310d882 --- /dev/null +++ b/lib/knex/mongoQuery/MongoQuery.ts @@ -0,0 +1,199 @@ +import {QueryBuilder} from 'knex'; +import * as _ from 'underscore'; + +/** + * Take a query object like {$or: [{type: 'foo'}, {x: {$gt: 4}, y: {$lte: 6}}]} + * which could also be expressed as: {$or: [{type: 'foo'}, {$and: [{x: {$gt: 4}}, {y: {$lte: 6}}]}]} + * and append to a knex statement like knex('table').select('*') these chains ... + * .where('type', '=', 'foo').orWhere(function () { + * this.where(x, '>', 4).andWhere(y, '<=', 6) + * }); + * + * {$or: [{type: 'foo', subtype: 'bar'}, {$or:[{x: {$gt: 4}}, {x: 9}], y: {$lte: 6}}]} + * .where('type', '=', 'foo').orWhere(function () { + * this.where(function () { + * this.where(x, '>', 4).orWhere(x, '=' 9) + * }).andWhere(y, '<=', 6) + * }); * + * @param {string} alias db alias name used when setting the database client object + * @param {string} statement knex query + * @param {object} query mongo style query object + * @returns {*} + */ +export namespace MongoQuery { + + export function convertMongoQueryToChains (alias: string, statement: QueryBuilder, query): QueryBuilder { + return traverse(statement, query, alias) + } + + /** + * Traverse an object and produce a promise chain of where and andWhere + * @param {object} statement knex query + * @param {object} query mongo style query object + * @param alias + * @returns {*} + */ + function traverse(statement: QueryBuilder, query, alias: string) { + var firstProp = true; + for (var prop in query) { + var params = processProp(statement, prop, query[prop], alias); + + if (firstProp) { + if (params.length > 1) { + statement = statement.where(params[0], params[1], params[2]); + } + else { + statement = statement.where(params[0]); + } + } + else { + if (params.length > 1) { + statement = statement.andWhere(params[0], params[1], params[2]); + } + else { + statement = statement.andWhere(params[0]); + } + } + + firstProp = false; + } + return statement; + } + + function processProp(statement: QueryBuilder, prop, value, alias: string) { + if (value instanceof Array) + return processArrayProp(prop, value, alias); + else + return processNonArrayProp(prop, value, alias) + } + + function processArrayProp(prop, value, alias: string) { + return [innerFunc(prop, value, alias)]; + } + + function innerFunc(prop: string, value: any, alias: string) { + return function boundInnerFunc () { + var firstProp; + var statement = this; + + if (prop.toLowerCase() == '$and') { + firstProp = true; + _.each(value, function (obj) { + var params = processObject(statement, obj, alias); + statement = andOrStatementBuilder(statement, params, firstProp, 'and'); + firstProp = false; + }); + } else if (prop.toLowerCase() == '$or') { + firstProp = true; + _.each(value, function (obj) { + var params = processObject(statement, obj, alias); + statement = andOrStatementBuilder(statement, params, firstProp, 'or'); + firstProp = false + }); + } else if (prop.toLowerCase() == '$in') + statement = statement.whereIn(value); + else if (prop.toLowerCase() == '$nin') + statement = statement.whereNotIn(value); + else + throw `Don't support ${prop}:${JSON.stringify(value)}`; + } + } + + function andOrStatementBuilder(statement: QueryBuilder, params: any, firstProp: boolean, andOrOr: 'and' | 'or') { + if (firstProp) { + if (params.length > 1) { + return statement.where(params[0], params[1], params[2]); + } + else { + return statement.where(params[0]); + } + } else { + if (params.length > 1) { + if (andOrOr === 'or') { + return statement.orWhere(params[0], params[1], params[2]); + } + else { + return statement.andWhere(params[0], params[1], params[2]); + } + } + else { + return statement.andWhere(params[0]); + } + } + } + + /** + * Process an array element of a $or or $and. This will result in either three parameters in + * the form of prop, compare operator, value or a single parameter which is a function that + * will chain together a nested expression. + * @param {object} statement knex query object + * @param {object} obj object of supertype + * @returns {Function} + */ + function processObject(statement: QueryBuilder, obj, alias: string) { + var propCount = 0; + var singleProp; + + // Do we have more than one prop + for (var prop in obj) { + singleProp = prop; + ++propCount; + } + + // If so fetch the 3 parameters for a where, orWhere or andWhere chain + // Otherwise return a function that will chain sub-ordinate clauses + if (propCount == 1) + return processProp(statement, singleProp, obj[singleProp], alias); + else + return [function () { + traverse(statement, obj, alias) + }] + } + + // Params is either a Function or a set of 3 values ex. [key name, op, value] + function processNonArrayProp(prop: string, value, alias: string): Array { + var params: Array = []; + if (value instanceof Date || typeof(value) == 'string' || typeof(value) == 'number') { + params = [`${alias}.${prop}`, '=', value]; + } else + for (var subProp in value) { + params = [`${alias}.${prop}`, undefined, value[subProp]]; + const lowerCase = subProp.toLowerCase(); + if (lowerCase == '$eq') + params[1] = '='; + else if (lowerCase == '$gt') + params[1] = '>'; + else if (lowerCase == '$gte') + params[1] = '>='; + else if (lowerCase == '$lt') + params[1] = '<'; + else if (lowerCase == '$lte') + params[1] = '<='; + else if (lowerCase == '$ne') + params[1] = '!='; + else if (lowerCase == '$in') { + const attr = params[0]; + const values = params[2]; + params = [function () { + this.whereIn(attr, values) + }]; + } + else if (lowerCase == '$nin') { + const attr = params[0]; + const values = params[2]; + params = [function () { + this.whereNotIn(attr, values) + }]; + } + else if (lowerCase == '$regex') { + params[1] = value.$options && value.$options.match(/i/) ? '~*' : '~'; + delete value['$options'] + if (params[2] && params[2].source) + params[2] = params[2].source; + } else + throw `Can't handle ${prop}:${JSON.stringify(value)}`; + } + return params; + } + +} \ No newline at end of file diff --git a/lib/knex/synchronize/Indexes.ts b/lib/knex/synchronize/Indexes.ts new file mode 100644 index 0000000..9fc4474 --- /dev/null +++ b/lib/knex/synchronize/Indexes.ts @@ -0,0 +1,231 @@ +import * as Knex from 'knex'; +import * as _ from 'underscore'; + +export namespace Indexes { + export async function sync (persistor, tableName, template) { + var aliasedTableName = template.__table__; + tableName = persistor.dealias(aliasedTableName); + + while (template.__parent__) { + template = template.__parent__; + } + + if (!template.__table__) { + throw new Error(`${template.__name__} is missing a schema entry`); + } + const knex = persistor.getDB(persistor.getDBAlias(template.__table__)).connection; + let schema = persistor._schema; + + var _changes = {}; + const schemaTable = 'index_schema_history'; + const schemaField = 'schema'; + + try { + // Loading the Schema definition + const loadRes = await loadSchema(tableName, undefined, knex, schemaTable, schemaField, template); + let _dbschema = loadRes._dbschema; + let name = loadRes.name && loadRes.name; + + // Loading Table Definition + let res = loadTableDef(_dbschema, schema, name); + _dbschema = res._dbschema; + name = res.name; + schema = res.schema; + + diffTable(_dbschema, schema, name, _changes); + + generateChanges(template, undefined, tableName, _changes, _dbschema); + + const dbChanges = mergeChanges(_changes, tableName); + + await applyTableChanges(dbChanges, knex, tableName); + + return await makeSchemaUpdates(_changes, knex, schemaTable, schemaField, schema); + } + catch (err) { + throw err; + } + } + + async function loadSchema (tableName: string, _dbschema, knex: Knex, schemaTable: string, schemaField: string, template) { + + if (!!_dbschema) { + //@ts-ignore + return {_dbschema: tableName}; + } + + const exists = await knex.schema.hasTable(schemaTable); + + // create + if (!exists) { + await knex.schema.createTable(schemaTable, (table) => { // @TODO: need to issue a PR to knex for bad type. This is ASYNC + table.increments('sequence_id').primary(); + table.text(schemaField); + table.timestamps(); + }) + } + + const record = knex(schemaTable).orderBy('sequence_id', 'desc').limit(1); + + if(!record[0]) { + return {_dbschema: {}, name: template.__name__}; + } + else { + const parsedSchema = JSON.parse(record[0][schemaField]); + return {_dbschema: parsedSchema, name: template.__name__}; + } + } + + // Check to see if Table Definition exists + function loadTableDef(dbschema, schema, tableName) { + if (!dbschema[tableName]) + dbschema[tableName] = {}; + return {_dbschema: dbschema, schema: schema, name: tableName}; + } + + // Wizardry @TODO: ask Ravi + function diffTable (_dbSchema, schema, tableName: string, _changes) { + const dbTableDef = _dbSchema[tableName]; + const memTableDef = schema[tableName]; + const track = {add: [], change: [], delete: []}; + + const firstDiffs = diff(memTableDef, dbTableDef, 'add', true, function (_memIdx, dbIdx) { + return !dbIdx; + }, track); + + const secondDiffs = diff(memTableDef, dbTableDef, 'change', false, function (memIdx, dbIdx) { + return memIdx && dbIdx && !_.isEqual(memIdx, dbIdx); + }, firstDiffs); + + const thirdDiffs = diff(dbTableDef, memTableDef, 'delete', false, function (_dbIdx, memIdx) { + return !memIdx; + }, secondDiffs); + + _changes[tableName] = _changes[tableName] || {}; + + _.map(_.keys(track), function(key) { + _changes[tableName][key] = _changes[tableName][key] || []; + _changes[tableName][key].push.apply(_changes[tableName][key], track[key]); + }); + } + + function generateChanges(localTemplate, _value, tableName, _changes, _dbSchema) { + const children = localTemplate.__children__; + for (let index = 0; index < children.length; index++) { + const child = children[index]; + + const res = loadTableDef(_dbSchema, child, tableName); + diffTable(res._dbschema, res.schema, res.name, _changes); + generateChanges(child, _value, tableName, _changes, _dbSchema); + } + } + + function mergeChanges(_changes, tableName) { + const dbChanges = {add: [], change: [], delete: []}; + _.map(dbChanges, function(_object, key) { + _.each(_changes, function(change) { + var uniqChanges = _.uniq(change[key], (o: any) => o.name); + const filtered = getFilteredTarget(dbChanges[key], uniqChanges, tableName); + dbChanges[key].push.apply(dbChanges[key], filtered); + }) + }); + + return dbChanges; + } + + async function applyTableChanges(dbChanges, knex: Knex, tableName: string) { + return await knex.transaction(async function (trx) { + return await trx.schema.table(tableName, function (table) { + syncIndexesForHierarchy('delete', dbChanges, table, tableName); + syncIndexesForHierarchy('add', dbChanges, table, tableName); + syncIndexesForHierarchy('change', dbChanges, table, tableName); + }) + }) + } + + async function makeSchemaUpdates(_changes, knex: Knex, schemaTable: string, schemaField: string, schema): Promise { + const chgFound = _.reduce(_changes, (curr, change) => curr || !!isSchemaChanged(change), false); + + if (!chgFound) return; + + const record = await knex(schemaTable).orderBy('sequence_id', 'desc').limit(1); + let response = {}, sequence_id; + if (!record[0]) { + sequence_id = 1; + } else { + response = JSON.parse(record[0][schemaField]); + sequence_id = ++record[0].sequence_id; + } + + _.each(_changes, (_o, chgKey) => response[chgKey] = schema[chgKey]); + + return knex(schemaTable).insert({ + sequence_id: sequence_id, + schema: JSON.stringify(response) + }); + } + + + // Helpers + + function diff(masterTblSchema, shadowTblSchema, opr, addMissingTable, addPredicate, diffs) { + + if (!!masterTblSchema && !!masterTblSchema.indexes && masterTblSchema.indexes instanceof Array && !!shadowTblSchema) { + if (masterTblSchema.indexes) { + masterTblSchema.indexes.forEach((mstIdx) => { + var shdIdx = _.findWhere(shadowTblSchema.indexes, {name: mstIdx.name}); + + if (addPredicate(mstIdx, shdIdx)) { + diffs[opr] = diffs[opr] || []; + diffs[opr].push(mstIdx); + } + }); + } + } else if (addMissingTable && !!masterTblSchema && !!masterTblSchema.indexes) { + diffs[opr] = diffs[opr] || []; + diffs[opr].push.apply(diffs[opr], masterTblSchema.indexes); + } + return diffs; + } + + function getFilteredTarget(src, target, tableName) { + return _.filter(target, function iterator(o: any, _filterkey) { + var currName: string = _.reduce(o.def.columns, (name, col) => `${name}_${col}`, `idx_${tableName}`); + + return !_.find(src, function(cached: any) { + var cachedName = _.reduce(cached.def.columns, (name, col) => `${name}_${col}`, `idx_${tableName}`); + return cachedName.toLowerCase() === currName.toLowerCase() + }) + }); + } + + function syncIndexesForHierarchy (operation, diffs, table, tableName) { + _.map(diffs[operation], function (object: any, _key) { + var type = object.def.type; + var columns = object.def.columns; + if (type !== 'unique' && type !== 'index') + throw new Error('index type can be only "unique" or "index"'); + + var name = _.reduce(object.def.columns, function (name, col) { + return `${name}_${col}`; + }, `idx_${tableName}`); + + name = name.toLowerCase(); + if (operation === 'add') { + table[type](columns, name); + } + else if (operation === 'delete') { + type = type.replace(/index/, 'Index'); + type = type.replace(/unique/, 'Unique'); + table[`drop${type}`]([], name); + } + else + table[type](columns, name); + + }); + } + + function isSchemaChanged(object) { + return (object.add.length || object.change.length || object.delete.length); + } +} \ No newline at end of file diff --git a/lib/knex/synchronize/Tables.ts b/lib/knex/synchronize/Tables.ts new file mode 100644 index 0000000..e69de29 diff --git a/lib/knex/update.ts b/lib/knex/update.ts index 629acf9..0e01c35 100644 --- a/lib/knex/update.ts +++ b/lib/knex/update.ts @@ -1,5 +1,5 @@ -import { RemoteDocService } from '../remote-doc/RemoteDocService'; -import { PersistorTransaction } from '../types/PersistorTransaction'; +import {RemoteDocService} from '../remote-doc/RemoteDocService'; +import {PersistorTransaction} from '../types'; import * as uuidv4 from 'uuid/v4'; module.exports = function (PersistObjectTemplate) { @@ -31,7 +31,7 @@ module.exports = function (PersistObjectTemplate) { var template = obj.__template__; var schema = template.__schema__; var templateName = template.__name__; - var isDocumentUpdate = obj.__version__ ? true : false; + var isDocumentUpdate = !!obj.__version__; var props = template.getProperties(); var promises = []; var dataSaved = {}; @@ -115,7 +115,7 @@ module.exports = function (PersistObjectTemplate) { referencedObj.setDirty(txn); } } - }) + }); if (!referencedObj._id) referencedObj._id = this.createPrimaryKey(referencedObj); }.bind(this)); @@ -140,8 +140,12 @@ module.exports = function (PersistObjectTemplate) { value.setDirty(txn); } - pojo[foreignKey] = value ? value._id : null - updatePersistorProp(obj, prop + 'Persistor', {isFetching: false, id: value ? value._id : null, isFetched: true}) + pojo[foreignKey] = value ? value._id : null; + updatePersistorProp(obj, prop + 'Persistor', { + isFetching: false, + id: value ? value._id : null, + isFetched: true + }); dataSaved[foreignKey] = pojo[foreignKey] || 'null'; @@ -166,7 +170,7 @@ module.exports = function (PersistObjectTemplate) { if(txn.remoteObjects) { txn.remoteObjects.add(objectKey); } else { - txn.remoteObjects = new Set(objectKey); + txn.remoteObjects = new Set(objectKey); // @TODO: Ask Nick if this works as intended } } @@ -202,7 +206,7 @@ module.exports = function (PersistObjectTemplate) { pojo[prop] = obj[prop] ? obj[prop] : null; log(defineProperty, pojo, prop); } else if (defineProperty.type == Boolean) { - pojo[prop] = obj[prop] == null ? null : (obj[prop] ? true : false); + pojo[prop] = obj[prop] == null ? null : !!obj[prop]; log(defineProperty, pojo, prop); } else { pojo[prop] = obj[prop]; @@ -241,4 +245,4 @@ module.exports = function (PersistObjectTemplate) { obj[prop] = copyProps(obj[prop]); } } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/lib/mongo/db.ts b/lib/mongo/db.ts index 5d88447..766ff33 100644 --- a/lib/mongo/db.ts +++ b/lib/mongo/db.ts @@ -1,3 +1,4 @@ + module.exports = function (PersistObjectTemplate) { /* Mongo implementation of save */ @@ -12,21 +13,7 @@ module.exports = function (PersistObjectTemplate) { collection.update(origVer ? {__version__: origVer, _id: updateID} : {_id: updateID}, pojo, {w:1}) : collection.save(pojo, {w:1}) ); - // ).then (function (error, count) { - // if (error instanceof Array) - // count = error[0]; // Don't know why things are returned this way - // if (updateID && count == 0) { - // obj.__version__ = origVer; - // if (txn && txn.onUpdateConflict) { - // txn.onUpdateCoxnflict(pojo) - // txn.updateConflict = new Error("Update Conflict"); - // } else - // throw new Error("Update Conflict"); - // } - // (logger || this.logger).debug({component: 'persistor', module: 'db', activity: 'write'}, 'saved ' + obj.__template__.__name__ + " to " + obj.__template__.__collection__); - // return true; - // }.bind(this)); - } + }; /** * Removes documents based on a query diff --git a/lib/types/Helpers.ts b/lib/types/Helpers.ts new file mode 100644 index 0000000..4f7382e --- /dev/null +++ b/lib/types/Helpers.ts @@ -0,0 +1,4 @@ +export type PropertyChanges = { name: string, originalValue: string, newValue: string, columnName: string } | {}; +export type ObjectChanges = { table: string, primaryKey: string, action: string, properties: PropertyChanges[] } | {}; +export type ChangeTracking = { [name: string]: ObjectChanges[] }; +export type Objects = { [obj: string]: any }; \ No newline at end of file diff --git a/lib/types/PersistorTransaction.ts b/lib/types/PersistorTransaction.ts index 2062763..ae94321 100644 --- a/lib/types/PersistorTransaction.ts +++ b/lib/types/PersistorTransaction.ts @@ -1,9 +1,18 @@ export type PersistorTransaction = { - id: number, - dirtyObjects: object, - savedObjects: object, - touchObjects: object, - deletedObjects: object, - remoteObjects: Set // identifiers for objects not stored directly in our db - deleteQueries: {} -}; \ No newline at end of file + updateConflict?: boolean; + id: number; + dirtyObjects: object; + savedObjects: object; + touchObjects: object; + deletedObjects: object; + remoteObjects: Set; // identifiers for objects not stored directly in our db + deleteQueries: DeleteQueries | {}; + postSave?: (txn: PersistorTransaction, logger: any, changeTracking: any) => Promise; + innerError?: Error; + knex?: any; + preSave?: (txn: PersistorTransaction, logger: any) => Promise +}; + +export type DeleteQueries = Array; + +export type DeleteQuery = { __name__: string, __template__: any, queryOrChains: any }; \ No newline at end of file diff --git a/lib/types/index.ts b/lib/types/index.ts index 20d7cf3..3c95437 100644 --- a/lib/types/index.ts +++ b/lib/types/index.ts @@ -1,2 +1,3 @@ -export { PersistorTransaction } from './PersistorTransaction'; +export {PersistorTransaction, DeleteQueries} from './PersistorTransaction'; export { RemoteDocConnectionOptions } from './RemoteDocConnectionOptions' +export {ChangeTracking, ObjectChanges, PropertyChanges, Objects} from './Helpers'; diff --git a/package-lock.json b/package-lock.json index 488278b..d20a9f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -178,9 +178,9 @@ } }, "@types/bluebird": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.20.tgz", - "integrity": "sha512-Wk41MVdF+cHBfVXj/ufUHJeO3BlIQr1McbHZANErMykaCWeDSZbH5erGjNBw2/3UlRdSxZbLfSuQTzFmPOYFsA==", + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.29.tgz", + "integrity": "sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==", "dev": true }, "@types/chai": { @@ -196,9 +196,9 @@ "dev": true }, "@types/node": { - "version": "7.0.56", - "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.56.tgz", - "integrity": "sha512-NgjN3xPyqbAXSIpznNAR5Cisx5uKqJWxcS9kefzSFEX/9J7O01/FHyfnvPI7SztBf9p6c8mqOn3olZWJx3ja6g==", + "version": "7.10.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-7.10.9.tgz", + "integrity": "sha512-usSpgoUsRtO5xNV5YEPU8PPnHisFx8u0rokj1BPVn/hDF7zwUDzVLiuKZM38B7z8V2111Fj6kd4rGtQFUZpNOw==", "dev": true }, "@types/q": { @@ -217,9 +217,9 @@ } }, "@types/underscore": { - "version": "1.8.8", - "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.8.8.tgz", - "integrity": "sha512-EquzRwzAAs04anQ8/6MYXFKvHoD+MIlF+gu87EDda7dN9zrKvQYHsc9VFAPB1xY4tUHQVvBMtjsHrvof2EE1Mg==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.9.4.tgz", + "integrity": "sha512-CjHWEMECc2/UxOZh0kpiz3lEyX2Px3rQS9HzD20lxMvx571ivOBQKeLnqEjxUY0BMgp6WJWo/pQLRBwMW5v4WQ==", "dev": true }, "acorn": { @@ -279,6 +279,12 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "arg": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz", + "integrity": "sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -351,40 +357,24 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, "aws-sdk": { - "version": "2.513.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.513.0.tgz", - "integrity": "sha512-hwI4c0MV7SrN5EOa0pXjiInWpNxBfMQFfPh3XDi9fj+KtPjgRWQUTaKF7pUg6RJ+Su++62kp1yJqT2WWBoNFMA==", - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "dependencies": { - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "version": "2.580.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.580.0.tgz", + "integrity": "sha512-YUn/LgaSjWuFDCAIOiOvyXbuRpNEzTPLbwRs3GpEmrP1hJrOChXh0p7GH61sTZdeJZarCSETUOWU5ngjpCOjKA==", + "requires": { + "buffer": "^4.9.1", + "events": "^1.1.1", + "ieee754": "^1.1.13", + "jmespath": "^0.15.0", + "querystring": "^0.2.0", + "sax": "^1.2.1", + "url": "^0.10.3", + "uuid": "^3.3.2", + "xml2js": "^0.4.19" } }, "balanced-match": { @@ -440,11 +430,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -454,9 +439,9 @@ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "brace-expansion": { "version": "1.1.11", @@ -507,9 +492,9 @@ "integrity": "sha512-D8zmlb46xfuK2gGvKmUjIklQEouN2nQ0LEHHeZ/NoHM2LDiMk2EYzZ5Ntw/Urk+bgMDosOZxaRzXxvhI5TcAVQ==" }, "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -665,6 +650,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, "requires": { "color-name": "^1.1.1" } @@ -672,7 +658,13 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colorette": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz", + "integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==" }, "commander": { "version": "2.15.1", @@ -681,9 +673,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "concat-map": { "version": "0.0.1", @@ -715,11 +707,6 @@ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -770,6 +757,14 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -804,11 +799,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -833,9 +823,9 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" }, "diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", "dev": true }, "doctrine": { @@ -848,6 +838,33 @@ "isarray": "^1.0.0" } }, + "es-abstract": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.2.tgz", + "integrity": "sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es5-ext": { "version": "0.10.41", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.41.tgz", @@ -927,7 +944,8 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "escope": { "version": "3.6.0", @@ -1160,11 +1178,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -1216,20 +1229,20 @@ } }, "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "requires": { "detect-file": "^1.0.0", - "is-glob": "^3.1.0", + "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" } }, "fined": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", - "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "requires": { "expand-tilde": "^2.0.2", "is-plain-object": "^2.0.3", @@ -1239,9 +1252,9 @@ } }, "flagged-respawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", - "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" }, "flat-cache": { "version": "1.3.0", @@ -1291,6 +1304,11 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "generate-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", @@ -1311,6 +1329,11 @@ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, + "getopts": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", + "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -1399,6 +1422,14 @@ } } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -1411,7 +1442,13 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "has-value": { "version": "1.0.0", @@ -1449,17 +1486,17 @@ "dev": true }, "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "requires": { "parse-passwd": "^1.0.0" } }, "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "ignore": { "version": "3.3.7", @@ -1515,9 +1552,9 @@ } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.0.0.tgz", + "integrity": "sha512-e0/LknJ8wpMMhTiWcjivB+ESwIuvHnBSlBbmP/pSb8CQJldoj1p2qv7xGZ/+BtbTziYRFSz8OsvdbiX45LtYQA==" }, "invariant": { "version": "2.2.4", @@ -1543,6 +1580,16 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-buffer": { @@ -1550,14 +1597,34 @@ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -1595,11 +1662,11 @@ } }, "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "^2.1.1" } }, "is-my-ip-valid": { @@ -1627,6 +1694,16 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-path-cwd": { @@ -1667,6 +1744,14 @@ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", "dev": true }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "^1.0.1" + } + }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", @@ -1681,6 +1766,14 @@ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", @@ -1784,84 +1877,59 @@ "dev": true }, "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" }, "knex": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/knex/-/knex-0.15.2.tgz", - "integrity": "sha1-YFm4dIlgX0zIdZmm0qnSZXCek0A=", - "requires": { - "babel-runtime": "^6.26.0", - "bluebird": "^3.5.1", - "chalk": "2.3.2", - "commander": "^2.16.0", - "debug": "3.1.0", - "inherits": "~2.0.3", - "interpret": "^1.1.0", - "liftoff": "2.5.0", - "lodash": "^4.17.10", - "minimist": "1.2.0", + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.20.3.tgz", + "integrity": "sha512-zzYO34pSCCYVqRTbCp8xL+Z7fvHQl5anif3Oacu6JaHFDubB7mFGWRRJBNSO3N8Ql4g4CxUgBctaPiliwoOsNA==", + "requires": { + "bluebird": "^3.7.1", + "colorette": "1.1.0", + "commander": "^4.0.1", + "debug": "4.1.1", + "getopts": "2.2.5", + "inherits": "~2.0.4", + "interpret": "^2.0.0", + "liftoff": "3.1.0", + "lodash": "^4.17.15", "mkdirp": "^0.5.1", - "pg-connection-string": "2.0.0", - "tarn": "^1.1.4", - "tildify": "1.2.0", - "uuid": "^3.3.2", - "v8flags": "^3.1.1" + "pg-connection-string": "2.1.0", + "tarn": "^2.0.0", + "tildify": "2.0.0", + "uuid": "^3.3.3", + "v8flags": "^3.1.3" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, "commander": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", - "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.0.1.tgz", + "integrity": "sha512-IPF4ouhCP+qdlcmCedhxX4xiGBPyigb8v5NeUp+0LyhwLgxMqyp3S0vl7TAPfS/hiP7FC3caI/PB9lTmP8r1NA==" }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "pg-connection-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.0.0.tgz", - "integrity": "sha1-Pu/lmX4G2Ugh5NUC5CtqHHP434I=" + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "^3.0.0" - } + "pg-connection-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.1.0.tgz", + "integrity": "sha512-bhlV7Eq09JrRIvo1eKngpwuqKtJnNhZdpdOlvrPrA4dxqXPjxSrbNrfnIDmTpwMyRszrcV4kU5ZA4mMsQUrjdg==" } } }, @@ -1876,12 +1944,12 @@ } }, "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", "requires": { "extend": "^3.0.0", - "findup-sync": "^2.0.0", + "findup-sync": "^3.0.0", "fined": "^1.0.1", "flagged-respawn": "^1.0.0", "is-plain-object": "^2.0.4", @@ -1893,8 +1961,7 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lolex": { "version": "1.1.0", @@ -1912,9 +1979,9 @@ } }, "make-error": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", - "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", "dev": true }, "make-iterator": { @@ -1923,13 +1990,6 @@ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "requires": { "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "map-cache": { @@ -1963,13 +2023,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "minimatch": { @@ -1981,11 +2034,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -2148,13 +2196,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "natural-compare": { @@ -2216,13 +2257,13 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "resolved": false, "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "append-transform": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "resolved": false, "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", "dev": true, "requires": { @@ -2231,25 +2272,25 @@ }, "archy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "resolved": false, "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "arrify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "resolved": false, "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { @@ -2259,13 +2300,13 @@ }, "builtin-modules": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "resolved": false, "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, "caching-transform": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", + "resolved": false, "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", "dev": true, "requires": { @@ -2276,7 +2317,7 @@ "dependencies": { "md5-hex": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", + "resolved": false, "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", "dev": true, "requires": { @@ -2287,31 +2328,31 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "commondir": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "resolved": false, "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "convert-source-map": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "resolved": false, "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", "dev": true }, "cross-spawn": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "resolved": false, "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { @@ -2321,7 +2362,7 @@ }, "debug": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "resolved": false, "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { @@ -2330,19 +2371,19 @@ }, "debug-log": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "resolved": false, "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "resolved": false, "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "default-require-extensions": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "resolved": false, "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", "dev": true, "requires": { @@ -2351,7 +2392,7 @@ "dependencies": { "strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "resolved": false, "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } @@ -2359,7 +2400,7 @@ }, "error-ex": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "resolved": false, "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { @@ -2368,7 +2409,7 @@ }, "execa": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "resolved": false, "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { @@ -2383,7 +2424,7 @@ "dependencies": { "cross-spawn": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "resolved": false, "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { @@ -2396,7 +2437,7 @@ }, "find-cache-dir": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "resolved": false, "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { @@ -2407,7 +2448,7 @@ }, "find-up": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "resolved": false, "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { @@ -2416,7 +2457,7 @@ }, "foreground-child": { "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "resolved": false, "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { @@ -2426,25 +2467,25 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "get-caller-file": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "resolved": false, "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": false, "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, "glob": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "resolved": false, "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { @@ -2458,31 +2499,31 @@ }, "graceful-fs": { "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "resolved": false, "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "resolved": false, "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "hosted-git-info": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", + "resolved": false, "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "resolved": false, "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { @@ -2492,25 +2533,25 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "invert-kv": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "resolved": false, "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "resolved": false, "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-builtin-module": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": false, "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -2519,31 +2560,31 @@ }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "resolved": false, "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "resolved": false, "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "resolved": false, "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "istanbul-lib-coverage": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz", + "resolved": false, "integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==", "dev": true }, "istanbul-lib-hook": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.0.tgz", + "resolved": false, "integrity": "sha512-qm3dt628HKpCVtIjbdZLuQyXn0+LO8qz+YHQDfkeXuSk5D+p299SEV5DrnUUnPi2SXvdMmWapMYWiuE75o2rUQ==", "dev": true, "requires": { @@ -2552,7 +2593,7 @@ }, "istanbul-lib-report": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.0.tgz", + "resolved": false, "integrity": "sha512-RiELmy9oIRYUv36ITOAhVum9PUvuj6bjyXVEKEHNiD1me6qXtxfx7vSEJWnjOGk2QmYw/GRFjLXWJv3qHpLceQ==", "dev": true, "requires": { @@ -2563,7 +2604,7 @@ }, "istanbul-lib-source-maps": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.0.tgz", + "resolved": false, "integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==", "dev": true, "requires": { @@ -2576,7 +2617,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "resolved": false, "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -2584,7 +2625,7 @@ }, "istanbul-reports": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.0.tgz", + "resolved": false, "integrity": "sha512-HeZG0WHretI9FXBni5wZ9DOgNziqDCEwetxnme5k1Vv5e81uTqcsy3fMH99gXGDGKr1ea87TyGseDMa2h4HEUA==", "dev": true, "requires": { @@ -2593,13 +2634,13 @@ }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "resolved": false, "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "lcid": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "resolved": false, "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { @@ -2608,7 +2649,7 @@ }, "locate-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "resolved": false, "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { @@ -2618,7 +2659,7 @@ "dependencies": { "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "resolved": false, "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true } @@ -2626,7 +2667,7 @@ }, "lru-cache": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "resolved": false, "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { @@ -2636,7 +2677,7 @@ }, "make-dir": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "resolved": false, "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { @@ -2645,7 +2686,7 @@ "dependencies": { "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "resolved": false, "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true } @@ -2653,7 +2694,7 @@ }, "md5-hex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", + "resolved": false, "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", "dev": true, "requires": { @@ -2662,13 +2703,13 @@ }, "md5-o-matic": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", + "resolved": false, "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", "dev": true }, "mem": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "resolved": false, "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { @@ -2677,7 +2718,7 @@ }, "merge-source-map": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "resolved": false, "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { @@ -2686,7 +2727,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "resolved": false, "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -2694,13 +2735,13 @@ }, "mimic-fn": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "resolved": false, "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { @@ -2709,13 +2750,13 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -2724,13 +2765,13 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "normalize-package-data": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "resolved": false, "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { @@ -2742,7 +2783,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "resolved": false, "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { @@ -2751,13 +2792,13 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { @@ -2766,13 +2807,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "resolved": false, "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { @@ -2783,13 +2824,13 @@ }, "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "resolved": false, "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", "dev": true, "requires": { @@ -2798,7 +2839,7 @@ }, "p-locate": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "resolved": false, "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { @@ -2807,25 +2848,25 @@ }, "p-try": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "resolved": false, "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "resolved": false, "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "pkg-dir": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "resolved": false, "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { @@ -2834,31 +2875,31 @@ }, "pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "resolved": false, "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "resolved": false, "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "resolved": false, "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "resolved": false, "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "rimraf": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "resolved": false, "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { @@ -2867,19 +2908,19 @@ }, "semver": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "resolved": false, "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "resolved": false, "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { @@ -2888,25 +2929,25 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "resolved": false, "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "slide": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "resolved": false, "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, "spawn-wrap": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", + "resolved": false, "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", "dev": true, "requires": { @@ -2920,7 +2961,7 @@ }, "spdx-correct": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "resolved": false, "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { @@ -2930,13 +2971,13 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "resolved": false, "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "resolved": false, "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { @@ -2946,13 +2987,13 @@ }, "spdx-license-ids": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "resolved": false, "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, "string-width": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "resolved": false, "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { @@ -2962,7 +3003,7 @@ }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "resolved": false, "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -2971,13 +3012,13 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "supports-color": { "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "resolved": false, "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { @@ -2986,7 +3027,7 @@ }, "test-exclude": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.2.tgz", + "resolved": false, "integrity": "sha512-2kTGf+3tykCfrWVREgyTR0bmVO0afE6i7zVXi/m+bZZ8ujV89Aulxdcdv32yH+unVFg3Y5o6GA8IzsHnGQuFgQ==", "dev": true, "requires": { @@ -2998,7 +3039,7 @@ "dependencies": { "load-json-file": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "resolved": false, "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { @@ -3010,7 +3051,7 @@ }, "parse-json": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "resolved": false, "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { @@ -3020,7 +3061,7 @@ }, "path-type": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "resolved": false, "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { @@ -3029,13 +3070,13 @@ }, "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "resolved": false, "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "read-pkg": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "resolved": false, "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { @@ -3046,7 +3087,7 @@ }, "read-pkg-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "resolved": false, "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { @@ -3056,7 +3097,7 @@ }, "strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "resolved": false, "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } @@ -3064,7 +3105,7 @@ }, "validate-npm-package-license": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "resolved": false, "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { @@ -3074,7 +3115,7 @@ }, "which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "resolved": false, "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { @@ -3083,13 +3124,13 @@ }, "which-module": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "resolved": false, "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": false, "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -3099,13 +3140,13 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { @@ -3114,7 +3155,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -3125,7 +3166,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -3136,13 +3177,13 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write-file-atomic": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "resolved": false, "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", "dev": true, "requires": { @@ -3153,19 +3194,19 @@ }, "y18n": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "resolved": false, "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "resolved": false, "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "resolved": false, "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { @@ -3185,13 +3226,13 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "resolved": false, "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, "cliui": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "resolved": false, "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { @@ -3202,7 +3243,7 @@ }, "yargs-parser": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "resolved": false, "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { @@ -3213,7 +3254,7 @@ }, "yargs-parser": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "resolved": false, "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { @@ -3222,7 +3263,7 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "resolved": false, "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } @@ -3252,9 +3293,27 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } } } }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -3274,6 +3333,15 @@ "isobject": "^3.0.0" } }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, "object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", @@ -3302,7 +3370,7 @@ }, "onetime": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", "dev": true }, @@ -3347,7 +3415,8 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true }, "packet-reader": { "version": "0.3.1", @@ -3387,9 +3456,9 @@ "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-root": { "version": "0.1.1", @@ -3590,11 +3659,6 @@ "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", "dev": true }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -3605,9 +3669,9 @@ } }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" }, "repeat-string": { "version": "1.6.1", @@ -3642,11 +3706,11 @@ } }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", + "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-dir": { @@ -3733,9 +3797,9 @@ "dev": true }, "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "semver": { "version": "5.5.0", @@ -3869,11 +3933,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -3883,6 +3942,16 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "requires": { "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "source-map": { @@ -3903,11 +3972,12 @@ } }, "source-map-support": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.4.tgz", - "integrity": "sha512-PETSPG6BjY1AHs2t64vS2aqAgu6dMIMXJULWFBGbh2Gr8nVLbCFDo6i/RMMvviIQ2h1Z8+5gQhVKSn2je9nmdg==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { + "buffer-from": "^1.0.0", "source-map": "^0.6.0" }, "dependencies": { @@ -3976,6 +4046,24 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", @@ -4059,9 +4147,9 @@ } }, "tarn": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.4.tgz", - "integrity": "sha512-j4samMCQCP5+6Il9/cxCqBd3x4vvlLeVdoyGex0KixPKl4F8LpNbDSC6NDhjianZgUngElRr9UI1ryZqJDhwGg==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-2.0.0.tgz", + "integrity": "sha512-7rNMCZd3s9bhQh47ksAQd92ADFcJUjjbyOvyFjNLwTPpGieFHMC84S+LOzw0fx1uh6hnDz/19r8CPMnIjJlMMA==" }, "text-table": { "version": "0.2.0", @@ -4075,12 +4163,9 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", - "requires": { - "os-homedir": "^1.0.0" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" }, "to-fast-properties": { "version": "2.0.0", @@ -4094,6 +4179,16 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "to-regex": { @@ -4123,52 +4218,23 @@ "dev": true }, "ts-node": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-5.0.1.tgz", - "integrity": "sha512-XK7QmDcNHVmZkVtkiwNDWiERRHPyU8nBqZB1+iv2UhOG0q3RQ9HsZ2CMqISlFbxjrYFGfG2mX7bW4dAyxBVzUw==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", + "integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==", "dev": true, "requires": { - "arrify": "^1.0.0", - "chalk": "^2.3.0", - "diff": "^3.1.0", + "arg": "^4.1.0", + "diff": "^4.0.1", "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.3", - "yn": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "source-map-support": "^0.5.6", + "yn": "^3.0.0" } }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, "tv4": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", @@ -4196,9 +4262,9 @@ "dev": true }, "typescript": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", - "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", + "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", "dev": true }, "uglify-js": { @@ -4234,9 +4300,9 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" }, "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" }, "union-value": { "version": "1.0.1", @@ -4335,23 +4401,32 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, "uuid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" }, "v8flags": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz", - "integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", + "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", "requires": { "homedir-polyfill": "^1.0.1" } }, "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { "isexe": "^2.0.0" } @@ -4378,18 +4453,19 @@ } }, "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", "requires": { "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" } }, "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, "xtend": { "version": "4.0.1", @@ -4397,9 +4473,9 @@ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true } } diff --git a/package.json b/package.json index 3b29bbe..eba3b76 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,15 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "dependencies": { - "aws-sdk": "2.x", - "bluebird": "x", - "knex": "0.15.2", + "aws-sdk": "^2.580.0", + "bluebird": "^3.7.2", + "knex": "^0.20.3", "mongodb-bluebird": "x", "pg": "7.4.1", "q": "1.x", + "tslib": "^1.10.0", "tv4": "^1.2.7", - "underscore": "1.x", + "underscore": "^1.9.1", "uuid": "3.3.3" }, "peerDependencies": { @@ -21,22 +22,22 @@ }, "devDependencies": { "@havenlife/supertype": "3.x", + "@types/bluebird": "^3.5.29", + "@types/chai": "^3.4.34", + "@types/mocha": "^2.2.39", + "@types/node": "^7.10.9", + "@types/q": "*", + "@types/underscore": "^1.9.4", "chai": "3.x", "chai-as-promised": "^5.1.0", - "nyc": "13.0.0", + "eslint": "3.7.x", "mocha": "5.2.0", + "mock-fs": "3.6.x", + "nyc": "13.0.0", "sinon": "1.15.x", "sinon-chai": "2.8.x", - "mock-fs": "3.6.x", - "eslint": "3.7.x", - "@types/chai": "^3.4.34", - "@types/mocha": "^2.2.39", - "@types/node": "^7.0.5", - "@types/q": "*", - "@types/underscore": "*", - "@types/bluebird": "*", - "typescript": "*", - "ts-node": "*" + "ts-node": "^8.5.4", + "typescript": "^3.7.2" }, "directories": {}, "engines": { diff --git a/test/persist_newapi_tests.js b/test/persist_newapi_tests.js index 63a2f6d..e711d5c 100644 --- a/test/persist_newapi_tests.js +++ b/test/persist_newapi_tests.js @@ -429,6 +429,7 @@ describe('persistor transaction checks', function () { expect(Object.keys(changes.Employee[0])).to.contain('primaryKey'); expect(changes.Employee[0].properties[0].name).to.equal('homeAddress'); expect(changes.Employee[0].properties[1].name).to.equal('dob'); + expect(changes.Employee[0].properties.length).to.equal(4); var empNew = new Employee(); empNew.setDirty(txn); }; diff --git a/tsconfig.json b/tsconfig.json index 34d03d3..6adbddc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,9 @@ { "compilerOptions": { "outDir": "./dist", - "rootDir": "./" + "rootDir": "./", + "downlevelIteration": true, + "importHelpers": true }, "extends": "./tsconfig.base.json", "include": [