<commit_before>import EventEmitter from 'events';
import uniqueId from 'lodash.uniqueid';
import isObject from 'lodash.isobject';
import isFunction from 'lodash.isfunction';
import isUndefined from 'lodash.isundefined';
import uuidV4 from 'uuid/v4';

/**
 * Model identities
 */
export const identities = new Map();
/**
 * Flags for controlling mutation.
 * Flag index n must have value 2^n.
 * @example
 * this.set('active', value, UNSET_IF_FALSE);
 * this.set('active', value, UNSET_IF_FALSE + SET_SILENT);
 */
export const SET_SILENT = 1; // Don't dispatch event when setting.
export const UNSET_IF_FALSE = 2; // If value evaluates to Boolean False, unset property.
export const SOFT_UPDATE = 4; // During update, if no setter or model found, use set() silent.
export const RESET_REFERENCE = 8; // Reset this._data or this._items references in reset().
/**
 * Helper for checking flags, e.g. for Model.set().
 * @param {Integer} dec Sum of flags.
 * @param {Integer} flag Flag to check.
 * @return {boolean} True if flag is set.
 */
export function flagIsSet(dec, flag) {
    const binStr = (dec >>> 0).toString(2);
    const flagIndex = binStr.length - (flag >>> 0).toString(2).length;
    return binStr[flagIndex] === '1';
}
/**
 * Model
 */
export default class Model extends EventEmitter {
    /**
     * Model.constructor
     * @param {Object} data JSON serializable object.
     * @param {...} args Arguments passed to _getDefaults().
     */
    constructor(data = {}, ...args) {
        super();
        // Update with defaults
        this._withDefaults(data, ...args);
        // Validate data
        this._validate(data);
        // Valid, set
        this._data = data;
        // Store previous
        this._previousData = {};
        // Store modified
        this._modified = undefined;
        // Client id
        this._cid = this._getUniqueClientId();
    }
    /**
     * Get client id. Not persisted.
     * @return {String}
     */
    get cid() {
        return this._cid;
    }
    /**
     * Get uuid.
     * @return {String}
     */
    get uuid() {
        return this.get('uuid');
    }
    /**
     * Underlying data object for model.
     * @return {String} Model polymorphic identity.
     */
    getModelIdentity() {
        return this.get('identity');
    }
    /**
     * Underlying data object for model.
     * @return {Object} JSON serializable object.
     */
    getModelData() {
        return this._data;
    }
    /**
     * Get value of data.property.
     * @param {String} property Name of property.
     * @param {*} defaultValue Default value to return if property is undefined.
     * @return {*}
     */
    get(property, defaultValue) {
        return this.has(property) ? this._data[property] : defaultValue;
    }
    /**
     * Return previous value of property.
     * @param {String} property Name of property.
     * @return {*}
     */
    getPrevious(property) {
        return this._previousData[property];
    }
    /**
     * Check if property is set in data.
     * @param {String} property Name of property.
     * @return {boolean} True if set.
     */
    has(property) {
        return this._data.hasOwnProperty(property);
    }
    /**
     * Check if previous value of property is same
     * as current.
     * @param {list of strings} properties Names of properties.
     * @return {boolean} True if any of them has changed.
     */
    hasChanged(...properties) {
        for (let prop of properties) {
            if (this._previousData[prop] !== this._data[prop]) {
                return true;
            }
        }
        return false;
    }
    /**
     * Set value of data.property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    set(property, value, flags = 0) {
        // Unset?
        if (flagIsSet(flags, UNSET_IF_FALSE) && Boolean(value) === false) {
            this.unset(property, flags);
            return;
        }
        // Previous value
        this._previousData[property] = this._data[property];
        // If property not set or value different
        if (!this.has(property) || this._data[property] !== value) {
            // Set new value
            this._data[property] = value;
            // Set modified
            this.updateModified();
        }
        // Dispatch change event, if not silent
        if (this.hasChanged(property) && !flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange(property, value, this._previousData[property]);
        }
        // Return
        return this;
    }
    /**
     * Toggle boolean property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    toggle(property, flags = 0) {
        const current = this.get(property, false); // False if not set
        return this.set(property, !current, flags); // Set to !current
    }
    /**
     * Unset value of data.property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {boolean} True if property found and unset.
     */
    unset(property, flags = 0) {
        // Previous value
        this._previousData[property] = this._data[property];
        // Present in _data
        const present = this._data.hasOwnProperty(property);
        // Delete from data
        delete this._data[property];
        // Has changed?
        if (this.hasChanged(property)) {
            // Set modified
            this.updateModified();
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange(property, undefined, this._previousData[property]);
            }
        }
        // True if present and deleted.
        return present;
    }
    /**
     * Delete multiple properties from data.
     * @param {list of strings} properties
     * @return {Model} The Model object.
     */
    unsetMultiple(...properties) {
        for (let prop of properties) {
            this._previousData[prop] = this._data[prop];
            delete this._data[prop];
        }
        if (this.hasChanged(...properties)) {
            this.updateModified();
        }
        // Return
        return this;
    }
    /**
     * Reset underlying data object for model.
     * @param {Object}  data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    reset(data, flags = 0) {
        data = data || {};
        // Keep identity and uuid
        const {uuid, identity} = this._data;
        Object.assign(data, {uuid, identity});
        // Update new data with defaults
        this._withDefaults(data);
        // If reset reference flag
        if (flagIsSet(flags, RESET_REFERENCE)) {
            // Reset data reference
            this._data = data;
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange();
            }
        // else, reset properties but keep this reference (not recursive)
        } else {
            // Unset properties not in data
            Object.keys(this._data).forEach(property => {
                if (isUndefined(data[property])) {
                    this.unset(property, flags);
                }
            })
            // Recursive reset or updateProperty
            Object.keys(this._data).forEach(property => {
                // Check recursiveness
                let currentVal = this[property];
                if (currentVal && isFunction(currentVal.reset)) {
                    currentVal.reset(data[property], flags);
                // Just update
                } else {
                    this.updateProperty(property, data[property], flags)
                }
            });
        }
        // Validate
        this._validate(this._data);
        // Return
        return this;
    }
    /**
     * Recursively update model properties.
     * @param {Object} data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    update(data, flags = 0) {
        // Iterate data dict
        Object.keys(data).forEach(prop => {
            this.updateProperty(prop, data[prop], flags);
        });
        // Set modified
        this.updateModified();
        // Notify if not silent. Dispatch for each property?
        if (!flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange();
        }
        // Return
        return this;
    }
    /**
     * Update single property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    updateProperty(property, value, flags = 0) {
        // Check if setter exists
        if (typeof this.__lookupSetter__(property) !== 'undefined') {
            this[property] = value;
            return this;
        }
        // No setter, check if getter returns model
        const currentVal = this[property];
        if (currentVal && isFunction(currentVal.update)) {
            // If yes, update recursively.
            currentVal.update(value);
            return this;
        }
        // Soft update
        if (flagIsSet(flags, SOFT_UPDATE)) {
            this.set(property, value, SET_SILENT);
            return this;
        }
        // If no setter or sub model, throw error.
        throw new Error('Could not update property "' + property + '" on ' + this.constructor.name + '.');
    }
    /**
     * Update modified timestamp.
     * @param {timestamp} modified Time of modification or undefined if now.
     * @return {Model} The Model object.
     */
    updateModified(modified) {
        this._modified = modified || Date.now();
        // Return
        return this;
    }
    /**
     * Return a copy of this model, with new uuids.
     * FIX: Better way to do this?
     * @return {Model} New instance of Model (or Model subclass).
     */
    copy() {
        // stringify data dict
        const jsonStr = JSON.stringify(this._data);
        // replace all uuids with new one's.
        const uuidRegexp = /"uuid":"........-....-....-....-............"/g;
        const newJsonStr = jsonStr.replace(uuidRegexp, () => {
            return '"uuid":"' + uuidV4() + '"';
        });
        // return instance of this
        const Constructor = this.constructor;
        return new Constructor(JSON.parse(newJsonStr));
    }
    /**
     * Interface for dispatching events.
     * Currently alias for EventEmitter.emit. May change.
     * @param {String} eventType Event type key.
     * @param {...} args Arguments passed to listeners.
     * @return {Model} The Model object.
     */
    dispatchEvent(eventType, ...args) {
        this.emit(eventType, ...[this].concat(args));
        // Return
        return this;
    }
    /**
     * Dispatch change events.
     * @param {String} property Name of property.
     * @param {*} newValue Anything JSON serializable.
     * @param {*} oldValue Anything JSON serializable.
     * @return {Model} The Model object.
     */
    dispatchChange(property, newValue, oldValue) {
        if (property) {
            this.dispatchEvent('change ' + property, newValue, oldValue);
        }
        return this.dispatchEvent('change', this);
    }
    /**
     * Alias for EventEmitter.addListener
     */
    addEventListener(event, listener) {
        this.addListener(event, listener);
        // Return
        return this;
    }
    /**
     * Alias for EventEmitter.removeListener
     */
    removeEventListener(event, listener) {
        this.removeListener(event, listener);
        // Return
        return this;
    }
    /**
     * Dispose model and sub models recursively.
     * Remove event listeners and delete references.
     * @return {Model} The Model object.
     */
    dispose() {
        // Remove event listeners
        this.removeAllListeners()
        // Check sub models on this, recursively
        Object.keys(this).forEach(attr => {
            if (isObject(this[attr]) && isFunction(this[attr].dispose)) {
                this[attr].dispose();
            }
        });
        // delete refs
        this._deleteReferences();
        // Return
        return this;
    }
    /**
     * Delete references set on model.
     */
    _deleteReferences() {
        delete this._data;
        delete this._previousData;
        delete this._modified;
    }
    /**
     * Check validity of data. Throw error if not valid.
     * @param {Object} data JSON serializable object.
     */
    _validate(data) {
        // Abstract
    }
    /**
     * Return default data object for new instance.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Object} Default data (JSON serializable object) for Model.
     */
    _getDefaults(...constructorArgs) {
        return {
            // Model polymorphic identity
            identity: Model.identity,
            // model uuid
            uuid: uuidV4()
        };
    }
    /**
     * Update data object with defaults.
     * @param {Object} data JSON serializable object.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Model} The Model object.
     */
    _withDefaults(data, ...constructorArgs) {
        // defaults
        const defaultData = this._getDefaults(...constructorArgs);
        // Update undefined props from defaults
        Object.keys(defaultData).forEach(prop => {
            if (isUndefined(data[prop])) {
                data[prop] = defaultData[prop];
            }
        });
        return this;
    }
    /**
     * Return unique client id.
     * @return {String} Unique string.
     */
    _getUniqueClientId() {
        return uniqueId(this.getModelIdentity());
    }

}
// Polymorphic identity
Model.identity = 'mozy.Model';
// Register Model
identities.set(Model.identity, Model);
<commit_msg>Bugfix<commit_after>import EventEmitter from 'events';
import uniqueId from 'lodash.uniqueid';
import isObject from 'lodash.isobject';
import isFunction from 'lodash.isfunction';
import isUndefined from 'lodash.isundefined';
import uuidV4 from 'uuid/v4';

/**
 * Model identities
 */
export const identities = new Map();
/**
 * Flags for controlling mutation.
 * Flag index n must have value 2^n.
 * @example
 * this.set('active', value, UNSET_IF_FALSE);
 * this.set('active', value, UNSET_IF_FALSE + SET_SILENT);
 */
export const SET_SILENT = 1; // Don't dispatch event when setting.
export const UNSET_IF_FALSE = 2; // If value evaluates to Boolean False, unset property.
export const SOFT_UPDATE = 4; // During update, if no setter or model found, use set() silent.
export const RESET_REFERENCE = 8; // Reset this._data or this._items references in reset().
/**
 * Helper for checking flags, e.g. for Model.set().
 * @param {Integer} dec Sum of flags.
 * @param {Integer} flag Flag to check.
 * @return {boolean} True if flag is set.
 */
export function flagIsSet(dec, flag) {
    const binStr = (dec >>> 0).toString(2);
    const flagIndex = binStr.length - (flag >>> 0).toString(2).length;
    return binStr[flagIndex] === '1';
}
/**
 * Model
 */
export default class Model extends EventEmitter {
    /**
     * Model.constructor
     * @param {Object} data JSON serializable object.
     * @param {...} args Arguments passed to _getDefaults().
     */
    constructor(data = {}, ...args) {
        super();
        // Update with defaults
        this._withDefaults(data, ...args);
        // Validate data
        this._validate(data);
        // Valid, set
        this._data = data;
        // Store previous
        this._previousData = {};
        // Store modified
        this._modified = undefined;
        // Client id
        this._cid = this._getUniqueClientId();
    }
    /**
     * Get client id. Not persisted.
     * @return {String}
     */
    get cid() {
        return this._cid;
    }
    /**
     * Get uuid.
     * @return {String}
     */
    get uuid() {
        return this.get('uuid');
    }
    /**
     * Underlying data object for model.
     * @return {String} Model polymorphic identity.
     */
    getModelIdentity() {
        return this.get('identity');
    }
    /**
     * Underlying data object for model.
     * @return {Object} JSON serializable object.
     */
    getModelData() {
        return this._data;
    }
    /**
     * Get value of data.property.
     * @param {String} property Name of property.
     * @param {*} defaultValue Default value to return if property is undefined.
     * @return {*}
     */
    get(property, defaultValue) {
        return this.has(property) ? this._data[property] : defaultValue;
    }
    /**
     * Return previous value of property.
     * @param {String} property Name of property.
     * @return {*}
     */
    getPrevious(property) {
        return this._previousData[property];
    }
    /**
     * Check if property is set in data.
     * @param {String} property Name of property.
     * @return {boolean} True if set.
     */
    has(property) {
        return this._data.hasOwnProperty(property);
    }
    /**
     * Check if previous value of property is same
     * as current.
     * @param {list of strings} properties Names of properties.
     * @return {boolean} True if any of them has changed.
     */
    hasChanged(...properties) {
        for (let prop of properties) {
            if (this._previousData[prop] !== this._data[prop]) {
                return true;
            }
        }
        return false;
    }
    /**
     * Set value of data.property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    set(property, value, flags = 0) {
        // Unset?
        if (flagIsSet(flags, UNSET_IF_FALSE) && Boolean(value) === false) {
            this.unset(property, flags);
            return;
        }
        // Previous value
        this._previousData[property] = this._data[property];
        // If property not set or value different
        if (!this.has(property) || this._data[property] !== value) {
            // Set new value
            this._data[property] = value;
            // Set modified
            this.updateModified();
        }
        // Dispatch change event, if not silent
        if (this.hasChanged(property) && !flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange(property, value, this._previousData[property]);
        }
        // Return
        return this;
    }
    /**
     * Toggle boolean property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    toggle(property, flags = 0) {
        const current = this.get(property, false); // False if not set
        return this.set(property, !current, flags); // Set to !current
    }
    /**
     * Unset value of data.property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {boolean} True if property found and unset.
     */
    unset(property, flags = 0) {
        // Previous value
        this._previousData[property] = this._data[property];
        // Present in _data
        const present = this._data.hasOwnProperty(property);
        // Delete from data
        delete this._data[property];
        // Has changed?
        if (this.hasChanged(property)) {
            // Set modified
            this.updateModified();
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange(property, undefined, this._previousData[property]);
            }
        }
        // True if present and deleted.
        return present;
    }
    /**
     * Delete multiple properties from data.
     * @param {list of strings} properties
     * @return {Model} The Model object.
     */
    unsetMultiple(...properties) {
        for (let prop of properties) {
            this._previousData[prop] = this._data[prop];
            delete this._data[prop];
        }
        if (this.hasChanged(...properties)) {
            this.updateModified();
        }
        // Return
        return this;
    }
    /**
     * Reset underlying data object for model.
     * @param {Object}  data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    reset(data, flags = 0) {
        data = data || {};
        // Keep identity and uuid
        const {uuid, identity} = this._data;
        Object.assign(data, {uuid, identity});
        // Update new data with defaults
        this._withDefaults(data);
        // If reset reference flag
        if (flagIsSet(flags, RESET_REFERENCE)) {
            // Reset data reference
            this._data = data;
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange();
            }
        // else, reset properties but keep this reference (not recursive)
        } else {
            // Unset properties not in data
            Object.keys(this._data).forEach(property => {
                if (isUndefined(data[property])) {
                    this.unset(property, flags);
                }
            })
            // Recursive reset or updateProperty
            Object.keys(this._data).forEach(property => {
                // Check recursiveness
                let currentVal = this[property];
                if (currentVal && isFunction(currentVal.reset)) {
                    currentVal.reset(data[property], flags);
                // Just update
                } else {
                    this.updateProperty(property, data[property], flags)
                }
            });
        }
        // Validate
        this._validate(this._data);
        // Return
        return this;
    }
    /**
     * Recursively update model properties.
     * @param {Object} data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    update(data, flags = 0) {
        // Iterate data dict
        Object.keys(data).forEach(prop => {
            this.updateProperty(prop, data[prop], flags);
        });
        // Set modified
        this.updateModified();
        // Notify if not silent. Dispatch for each property?
        if (!flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange();
        }
        // Return
        return this;
    }
    /**
     * Update single property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    updateProperty(property, value, flags = 0) {
        // Check if setter exists
        if (typeof this.__lookupSetter__(property) !== 'undefined') {
            this[property] = value;
            return this;
        }
        // No setter, check if getter returns model
        const currentVal = this[property];
        if (currentVal && isFunction(currentVal.update)) {
            // If yes, update recursively.
            currentVal.update(value, flags);
            return this;
        }
        // Soft update
        if (flagIsSet(flags, SOFT_UPDATE)) {
            return this.set(property, value, flags);
        }
        // If no setter or sub model, throw error.
        throw new Error('Could not update property "' + property + '" on ' + this.constructor.name + '.');
    }
    /**
     * Update modified timestamp.
     * @param {timestamp} modified Time of modification or undefined if now.
     * @return {Model} The Model object.
     */
    updateModified(modified) {
        this._modified = modified || Date.now();
        // Return
        return this;
    }
    /**
     * Return a copy of this model, with new uuids.
     * FIX: Better way to do this?
     * @return {Model} New instance of Model (or Model subclass).
     */
    copy() {
        // stringify data dict
        const jsonStr = JSON.stringify(this._data);
        // replace all uuids with new one's.
        const uuidRegexp = /"uuid":"........-....-....-....-............"/g;
        const newJsonStr = jsonStr.replace(uuidRegexp, () => {
            return '"uuid":"' + uuidV4() + '"';
        });
        // return instance of this
        const Constructor = this.constructor;
        return new Constructor(JSON.parse(newJsonStr));
    }
    /**
     * Interface for dispatching events.
     * Currently alias for EventEmitter.emit. May change.
     * @param {String} eventType Event type key.
     * @param {...} args Arguments passed to listeners.
     * @return {Model} The Model object.
     */
    dispatchEvent(eventType, ...args) {
        this.emit(eventType, ...[this].concat(args));
        // Return
        return this;
    }
    /**
     * Dispatch change events.
     * @param {String} property Name of property.
     * @param {*} newValue Anything JSON serializable.
     * @param {*} oldValue Anything JSON serializable.
     * @return {Model} The Model object.
     */
    dispatchChange(property, newValue, oldValue) {
        if (property) {
            this.dispatchEvent('change ' + property, newValue, oldValue);
        }
        return this.dispatchEvent('change', this);
    }
    /**
     * Alias for EventEmitter.addListener
     */
    addEventListener(event, listener) {
        this.addListener(event, listener);
        // Return
        return this;
    }
    /**
     * Alias for EventEmitter.removeListener
     */
    removeEventListener(event, listener) {
        this.removeListener(event, listener);
        // Return
        return this;
    }
    /**
     * Dispose model and sub models recursively.
     * Remove event listeners and delete references.
     * @return {Model} The Model object.
     */
    dispose() {
        // Remove event listeners
        this.removeAllListeners()
        // Check sub models on this, recursively
        Object.keys(this).forEach(attr => {
            if (isObject(this[attr]) && isFunction(this[attr].dispose)) {
                this[attr].dispose();
            }
        });
        // delete refs
        this._deleteReferences();
        // Return
        return this;
    }
    /**
     * Delete references set on model.
     */
    _deleteReferences() {
        delete this._data;
        delete this._previousData;
        delete this._modified;
    }
    /**
     * Check validity of data. Throw error if not valid.
     * @param {Object} data JSON serializable object.
     */
    _validate(data) {
        // Abstract
    }
    /**
     * Return default data object for new instance.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Object} Default data (JSON serializable object) for Model.
     */
    _getDefaults(...constructorArgs) {
        return {
            // Model polymorphic identity
            identity: Model.identity,
            // model uuid
            uuid: uuidV4()
        };
    }
    /**
     * Update data object with defaults.
     * @param {Object} data JSON serializable object.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Model} The Model object.
     */
    _withDefaults(data, ...constructorArgs) {
        // defaults
        const defaultData = this._getDefaults(...constructorArgs);
        // Update undefined props from defaults
        Object.keys(defaultData).forEach(prop => {
            if (isUndefined(data[prop])) {
                data[prop] = defaultData[prop];
            }
        });
        return this;
    }
    /**
     * Return unique client id.
     * @return {String} Unique string.
     */
    _getUniqueClientId() {
        return uniqueId(this.getModelIdentity());
    }

}
// Polymorphic identity
Model.identity = 'mozy.Model';
// Register Model
identities.set(Model.identity, Model);
<|endoftext|>


<commit_before>function Model(def){
	if(isPlainObject(def)) return Model[OBJECT](def);

	var model = function(obj) {
		obj = defaultTo(model[DEFAULT], obj);
		model[VALIDATE](obj);
		return obj;
	};

	initModel(model, def, Model);
	return model;
}

setConstructorProto(Model, Function[PROTO]);
var ModelProto = Model[PROTO];

ModelProto.toString = function(stack){
	return parseDefinition(this[DEFINITION]).map(function(d){
		return toString(d, stack);
	}).join(" or ");
};

ModelProto[ASSERTIONS] = [];

ModelProto[VALIDATE] = function(obj, errorCollector){
	this[VALIDATOR](obj, null, [], this[ERROR_STACK]);
	this[UNSTACK](errorCollector);
};

ModelProto[TEST] = function(obj){
	var errorStack = [];
	this[VALIDATOR](obj, null, [], errorStack);
	return !errorStack.length;
};

ModelProto[EXTEND] = function(){
	var def, proto,
		assertions = cloneArray(this[ASSERTIONS]),
		args = cloneArray(arguments);

	if(is(Model[OBJECT], this)){
		def = {};
		proto = {};
		merge(def, this[DEFINITION]);
		merge(proto, this[PROTO], false, true);
		args.forEach(function(arg){
			if(is(Model, arg)){
				merge(def, arg[DEFINITION], true);
			}
			if(isFunction(arg)){
				merge(proto, arg[PROTO], true, true);
			}
			if(isObject(arg)) {
				merge(def, arg, true, true);
			}
		})
	} else {
		def = args
			.reduce(function(def, ext){
				return def.concat(parseDefinition(ext));
			}, parseDefinition(this[DEFINITION]))
			.filter(function(value, index, self) {
				return self.indexOf(value) === index; // remove duplicates
			});
	}

	args.forEach(function(arg){
		if(is(Model, arg)){
			assertions = assertions.concat(arg[ASSERTIONS]);
		}
	});

	var submodel = new this[CONSTRUCTOR](def);
	setConstructorProto(submodel, this[PROTO]);
	merge(submodel[PROTO], proto);
	submodel[ASSERTIONS] = assertions;
	submodel[ERROR_COLLECTOR] = this[ERROR_COLLECTOR];
	return submodel;
};

ModelProto.assert = function(assertion, description){
	description = description || toString(assertion);
	var onFail = isFunction(description) ? description : function (assertionResult, value) {
		return 'assertion "' + description + '" returned ' + toString(assertionResult) + ' for value ' + toString(value);
	};
	define(assertion, ON_FAIL, onFail);
	this[ASSERTIONS] = this[ASSERTIONS].concat(assertion);
	return this;
};

ModelProto.defaultTo = function(val){
	this[DEFAULT] = val;
	return this;
}

ModelProto[ERROR_COLLECTOR] = function(errors){
	var e = new TypeError(errors.map(function(e){ return e[MESSAGE]; }).join('\n'));
	if(e.stack){
		e.stack = e.stack.replace(STACKTRACE_BLACKBOX_MATCHER, "");
	}
	throw e;
};

Model[CONVENTION_CONSTANT] = function(key){ return key.toUpperCase() === key };
Model[CONVENTION_PRIVATE] = function(key){ return key[0] === "_" };

// private methods
define(ModelProto, VALIDATOR, function(obj, path, callStack, errorStack){
	checkDefinition(obj, this[DEFINITION], path, callStack, errorStack);
	checkAssertions(obj, this, errorStack);
});

// throw all errors collected
define(ModelProto, UNSTACK, function(errorCollector){
	if(!this[ERROR_STACK].length){
		return;
	}
	if(!errorCollector){
		errorCollector = this[ERROR_COLLECTOR];
	}
	var errors = this[ERROR_STACK].map(function(err){
		if(!err[MESSAGE]){
			var def = is(Array, err[EXPECTED]) ? err[EXPECTED] : [err[EXPECTED]];
			err[MESSAGE] = ("expecting " + (err[PATH] ? err[PATH] + " to be " : "")
			+ def.map(function(d){ return toString(d); }).join(" or ")
			+ ", got " + (err[RECEIVED] != null ? bettertypeof(err[RECEIVED]) + " " : "")
			+ toString(err[RECEIVED]))
		}
		return err;
	});
	this[ERROR_STACK] = [];
	errorCollector.call(this, errors);
})

function initModel(model, def, constructor){
	setConstructor(model, constructor);
	model[DEFINITION] = def;
	model[ASSERTIONS] = model[ASSERTIONS].slice(); // clone from Model.prototype
	define(model, ERROR_STACK, []);
}

function parseDefinition(def){
	if(!isPlainObject(def)){
		if(!is(Array, def)) return [def];
		if(def.length === 1) return def.concat(undefined, null);
	} else {
		Object.keys(def).forEach(function(key) {
			def[key] = parseDefinition(def[key]);
		});
	}
	return def;
}

function checkDefinition(obj, def, path, callStack, errorStack){
	if(is(Model, def)){
		var indexFound = callStack.indexOf(def);
		if(indexFound !== -1 && callStack.slice(indexFound+1).indexOf(def) !== -1){
			return; //if found twice in call stack, cycle detected, skip validation
		}
		return def[VALIDATOR](obj, path, callStack.concat(def), errorStack);
	}
	if(isPlainObject(def)) {
		Object.keys(def).forEach(function (key) {
			var val = obj != null ? obj[key] : undefined;
			checkDefinition(val, def[key], path ? path + '.' + key : key, callStack, errorStack);
		});
	} else {
		var pdef = parseDefinition(def);
		for(var i=0, l=pdef.length; i<l; i++){
			if(checkDefinitionPart(obj, pdef[i], path, callStack)){
				return;
			}
		}
		var err = {};
		err[EXPECTED] = def;
		err[RECEIVED] = obj;
		err[PATH] = path;
		errorStack.push(err);
	}
}

function checkDefinitionPart(obj, def, path, callStack){
	if(obj == null){
		return obj === def;
	}
	if(isPlainObject(def) || is(Model, def)){ // object or model as part of union type
		var errorStack = [];
		checkDefinition(obj, def, path, callStack, errorStack);
		return !errorStack.length;
	}
	if(is(RegExp, def)){
		return def[TEST](obj);
	}
	if(def === Number || def === Date){
		return obj[CONSTRUCTOR] === def && !isNaN(obj)
	}

	return obj === def
		|| (isFunction(def) && is(def, obj))
		|| obj[CONSTRUCTOR] === def;
}

function checkAssertions(obj, model, errorStack){
	if(errorStack === undefined){
		errorStack = model[ERROR_STACK];
	}
	for(var i=0, l=model[ASSERTIONS].length; i<l ; i++ ){
		var assert = model[ASSERTIONS][i],
			assertionResult;
		try {
			assertionResult = assert.call(model, obj);
		} catch(err){
			assertionResult = err;
		}
		if(assertionResult !== true){
			var err = {};
			err[MESSAGE] = assert[ON_FAIL].call(model, assertionResult, obj)
			errorStack.push(err);
		}
	}
}

function autocast(obj, defNode){
	var def = parseDefinition(defNode || []),
	    suitableModels = [];

	for(var i=0, l=def.length; i<l; i++){
		var defPart = def[i];
		if(is(Model, defPart)){
			if(is(defPart, obj)){
				return obj;
			}
			if(defPart.test(obj)){
				suitableModels.push(defPart);
			}
		}
	}

	var nbSuitableModels = suitableModels.length;
	if(nbSuitableModels === 1) {
		return suitableModels[0](obj); // automatically cast to the suitable model when explicit
	}
	if(nbSuitableModels > 1){
		console.warn("Ambiguous model for value " + toString(obj)
			+ ", could be " + suitableModels.join(" or "));
	}

	return obj;
}<commit_msg>use constant TEST when appropriate<commit_after>function Model(def){
	if(isPlainObject(def)) return Model[OBJECT](def);

	var model = function(obj) {
		obj = defaultTo(model[DEFAULT], obj);
		model[VALIDATE](obj);
		return obj;
	};

	initModel(model, def, Model);
	return model;
}

setConstructorProto(Model, Function[PROTO]);
var ModelProto = Model[PROTO];

ModelProto.toString = function(stack){
	return parseDefinition(this[DEFINITION]).map(function(d){
		return toString(d, stack);
	}).join(" or ");
};

ModelProto[ASSERTIONS] = [];

ModelProto[VALIDATE] = function(obj, errorCollector){
	this[VALIDATOR](obj, null, [], this[ERROR_STACK]);
	this[UNSTACK](errorCollector);
};

ModelProto[TEST] = function(obj){
	var errorStack = [];
	this[VALIDATOR](obj, null, [], errorStack);
	return !errorStack.length;
};

ModelProto[EXTEND] = function(){
	var def, proto,
		assertions = cloneArray(this[ASSERTIONS]),
		args = cloneArray(arguments);

	if(is(Model[OBJECT], this)){
		def = {};
		proto = {};
		merge(def, this[DEFINITION]);
		merge(proto, this[PROTO], false, true);
		args.forEach(function(arg){
			if(is(Model, arg)){
				merge(def, arg[DEFINITION], true);
			}
			if(isFunction(arg)){
				merge(proto, arg[PROTO], true, true);
			}
			if(isObject(arg)) {
				merge(def, arg, true, true);
			}
		})
	} else {
		def = args
			.reduce(function(def, ext){
				return def.concat(parseDefinition(ext));
			}, parseDefinition(this[DEFINITION]))
			.filter(function(value, index, self) {
				return self.indexOf(value) === index; // remove duplicates
			});
	}

	args.forEach(function(arg){
		if(is(Model, arg)){
			assertions = assertions.concat(arg[ASSERTIONS]);
		}
	});

	var submodel = new this[CONSTRUCTOR](def);
	setConstructorProto(submodel, this[PROTO]);
	merge(submodel[PROTO], proto);
	submodel[ASSERTIONS] = assertions;
	submodel[ERROR_COLLECTOR] = this[ERROR_COLLECTOR];
	return submodel;
};

ModelProto.assert = function(assertion, description){
	description = description || toString(assertion);
	var onFail = isFunction(description) ? description : function (assertionResult, value) {
		return 'assertion "' + description + '" returned ' + toString(assertionResult) + ' for value ' + toString(value);
	};
	define(assertion, ON_FAIL, onFail);
	this[ASSERTIONS] = this[ASSERTIONS].concat(assertion);
	return this;
};

ModelProto.defaultTo = function(val){
	this[DEFAULT] = val;
	return this;
}

ModelProto[ERROR_COLLECTOR] = function(errors){
	var e = new TypeError(errors.map(function(e){ return e[MESSAGE]; }).join('\n'));
	if(e.stack){
		e.stack = e.stack.replace(STACKTRACE_BLACKBOX_MATCHER, "");
	}
	throw e;
};

Model[CONVENTION_CONSTANT] = function(key){ return key.toUpperCase() === key };
Model[CONVENTION_PRIVATE] = function(key){ return key[0] === "_" };

// private methods
define(ModelProto, VALIDATOR, function(obj, path, callStack, errorStack){
	checkDefinition(obj, this[DEFINITION], path, callStack, errorStack);
	checkAssertions(obj, this, errorStack);
});

// throw all errors collected
define(ModelProto, UNSTACK, function(errorCollector){
	if(!this[ERROR_STACK].length){
		return;
	}
	if(!errorCollector){
		errorCollector = this[ERROR_COLLECTOR];
	}
	var errors = this[ERROR_STACK].map(function(err){
		if(!err[MESSAGE]){
			var def = is(Array, err[EXPECTED]) ? err[EXPECTED] : [err[EXPECTED]];
			err[MESSAGE] = ("expecting " + (err[PATH] ? err[PATH] + " to be " : "")
			+ def.map(function(d){ return toString(d); }).join(" or ")
			+ ", got " + (err[RECEIVED] != null ? bettertypeof(err[RECEIVED]) + " " : "")
			+ toString(err[RECEIVED]))
		}
		return err;
	});
	this[ERROR_STACK] = [];
	errorCollector.call(this, errors);
})

function initModel(model, def, constructor){
	setConstructor(model, constructor);
	model[DEFINITION] = def;
	model[ASSERTIONS] = model[ASSERTIONS].slice(); // clone from Model.prototype
	define(model, ERROR_STACK, []);
}

function parseDefinition(def){
	if(!isPlainObject(def)){
		if(!is(Array, def)) return [def];
		if(def.length === 1) return def.concat(undefined, null);
	} else {
		Object.keys(def).forEach(function(key) {
			def[key] = parseDefinition(def[key]);
		});
	}
	return def;
}

function checkDefinition(obj, def, path, callStack, errorStack){
	if(is(Model, def)){
		var indexFound = callStack.indexOf(def);
		if(indexFound !== -1 && callStack.slice(indexFound+1).indexOf(def) !== -1){
			return; //if found twice in call stack, cycle detected, skip validation
		}
		return def[VALIDATOR](obj, path, callStack.concat(def), errorStack);
	}
	if(isPlainObject(def)) {
		Object.keys(def).forEach(function (key) {
			var val = obj != null ? obj[key] : undefined;
			checkDefinition(val, def[key], path ? path + '.' + key : key, callStack, errorStack);
		});
	} else {
		var pdef = parseDefinition(def);
		for(var i=0, l=pdef.length; i<l; i++){
			if(checkDefinitionPart(obj, pdef[i], path, callStack)){
				return;
			}
		}
		var err = {};
		err[EXPECTED] = def;
		err[RECEIVED] = obj;
		err[PATH] = path;
		errorStack.push(err);
	}
}

function checkDefinitionPart(obj, def, path, callStack){
	if(obj == null){
		return obj === def;
	}
	if(isPlainObject(def) || is(Model, def)){ // object or model as part of union type
		var errorStack = [];
		checkDefinition(obj, def, path, callStack, errorStack);
		return !errorStack.length;
	}
	if(is(RegExp, def)){
		return def.test(obj);
	}
	if(def === Number || def === Date){
		return obj[CONSTRUCTOR] === def && !isNaN(obj)
	}

	return obj === def
		|| (isFunction(def) && is(def, obj))
		|| obj[CONSTRUCTOR] === def;
}

function checkAssertions(obj, model, errorStack){
	if(errorStack === undefined){
		errorStack = model[ERROR_STACK];
	}
	for(var i=0, l=model[ASSERTIONS].length; i<l ; i++ ){
		var assert = model[ASSERTIONS][i],
			assertionResult;
		try {
			assertionResult = assert.call(model, obj);
		} catch(err){
			assertionResult = err;
		}
		if(assertionResult !== true){
			var err = {};
			err[MESSAGE] = assert[ON_FAIL].call(model, assertionResult, obj)
			errorStack.push(err);
		}
	}
}

function autocast(obj, defNode){
	var def = parseDefinition(defNode || []),
	    suitableModels = [];

	for(var i=0, l=def.length; i<l; i++){
		var defPart = def[i];
		if(is(Model, defPart)){
			if(is(defPart, obj)){
				return obj;
			}
			if(defPart[TEST](obj)){
				suitableModels.push(defPart);
			}
		}
	}

	var nbSuitableModels = suitableModels.length;
	if(nbSuitableModels === 1) {
		return suitableModels[0](obj); // automatically cast to the suitable model when explicit
	}
	if(nbSuitableModels > 1){
		console.warn("Ambiguous model for value " + toString(obj)
			+ ", could be " + suitableModels.join(" or "));
	}

	return obj;
}<|endoftext|>


<commit_before>define(["./frame"], function (Frame) {
    "use strict";

    var Graph = function () {
        this._nodeIds = {};
        this._nodes = [];
        this.edges = [];
    };

    Graph.prototype.addNode = function (node) {
        var id = node.getId();

        if (id) {
            this._nodeIds[id] = node;
        }

        this._nodes.push(node);
    };

    Graph.prototype.getNode = function (id) {
        return this._nodeIds[id];
    };

    Graph.prototype.getNodes = function () {
        return this._nodes;
    };

    Graph.prototype.addEdge = function (edge) {
        this.edges.push(edge);
    };

    Graph.prototype.renderIn = function (elem) {
        return new Frame(elem, this);
    };

    return Graph;
});
<commit_msg>Enable Graph chaining<commit_after>define(["./frame"], function (Frame) {
    "use strict";

    var Graph = function () {
        this._nodeIds = {};
        this._nodes = [];
        this.edges = [];
    };

    Graph.prototype.addNode = function (node) {
        var id = node.getId();

        if (id) {
            this._nodeIds[id] = node;
        }

        this._nodes.push(node);

        return this;
    };

    Graph.prototype.getNode = function (id) {
        return this._nodeIds[id];
    };

    Graph.prototype.getNodes = function () {
        return this._nodes;
    };

    Graph.prototype.addEdge = function (edge) {
        this.edges.push(edge);

        return this;
    };

    Graph.prototype.renderIn = function (elem) {
        return new Frame(elem, this);
    };

    return Graph;
});
<|endoftext|>


<commit_before>var React = require('react');
var ReactDOM = require('react-dom');

var ColP = React.createClass({
    propTypes: {
        lg: React.PropTypes.number,
        slg: React.PropTypes.number,
        md: React.PropTypes.number,
        smd: React.PropTypes.number,
        sm: React.PropTypes.number,
        ssm: React.PropTypes.number,
        xs: React.PropTypes.number,
        sxs: React.PropTypes.number,
    },
    componentDidMount: function() {
        window.addEventListener("resize", this.handleResize)
    },
    componentWillUnmount: function() {
        window.removeEventListener("resize", this.handleResize)
    },
    handleResize: function(e) {
        this.forceUpdate();
    },
    getDefaultProps: function() {
        return {
            sxs: 12,
        };
    },
    render: function() {
        var size = 12; // default
        var width = 0;
        var values = {
            "sxs": this.props.sxs,
            "xs": this.props.xs,
            "ssm": this.props.ssm,
            "sm": this.props.sm,
            "smd": this.props.smd,
            "md": this.props.md,
            "slg": this.props.slg,
            "lg": this.props.lg,
        };
        // inherit from smaller values if undefined
        if(values["xs"] == undefined) {
            values["xs"] = values["sxs"]
        }
        if(values["ssm"] == undefined) {
            values["ssm"] = values["xs"]
        }
        if(values["sm"] == undefined) {
            values["sm"] = values["ssm"]
        }
        if(values["smd"] == undefined) {
            values["smd"] = values["sm"]
        }
        if(values["md"] == undefined) {
            values["md"] = values["smd"]
        }
        if(values["slg"] == undefined) {
            values["slg"] = values["md"]
        }
        if(values["lg"] == undefined) {
            values["lg"] = values["slg"]
        }

        var myDiv = ReactDOM.findDOMNode(this.refs.colp)
        if(myDiv != null) width = myDiv.parentNode.getBoundingClientRect().width

        if(width <= 320) {
            size = values["sxs"]
        } else if(width <= 480) {
            size = values["xs"]
        } else if(width <= 624) {
            size = values["ssm"]
        } else if(width <= 768) {
            size = values["sm"]
        } else if(width <= 896) {
            size = values["smd"]
        } else if(width <= 1024) {
            size = values["md"]
        } else if(width <= 1232) {
            size = values["slg"]
        } else {
            size = values["lg"]
        }

        var style = (100.0 * size/12.0).toString() + "%"
        return (

                {this.props.children}

        );
    }
})

module.exports.ColP = ColP
<commit_msg>Fixed ColP warnings.<commit_after>var React = require('react');
var ReactDOM = require('react-dom');

var ColP = React.createClass({
    propTypes: {
        lg: React.PropTypes.number,
        slg: React.PropTypes.number,
        md: React.PropTypes.number,
        smd: React.PropTypes.number,
        sm: React.PropTypes.number,
        ssm: React.PropTypes.number,
        xs: React.PropTypes.number,
        sxs: React.PropTypes.number,
    },
    getInitialState: () => {
        return {
            width: 0,
        }
    },
    updateWidth: function() {
        var myDiv = ReactDOM.findDOMNode(this.refs.colp)
        if(myDiv != null) {
            this.setState({width: myDiv.parentNode.getBoundingClientRect().width})
        }
    },
    componentDidMount: function() {
        window.addEventListener("resize", this.handleResize)
        this.updateWidth();
    },
    componentWillUnmount: function() {
        window.removeEventListener("resize", this.handleResize)
    },
    handleResize: function(e) {
        this.updateWidth();
        this.forceUpdate();
    },
    getDefaultProps: function() {
        return {
            sxs: 12,
        };
    },
    render: function() {
        var size = 12; // default
        var width = 0;
        var values = {
            "sxs": this.props.sxs,
            "xs": this.props.xs,
            "ssm": this.props.ssm,
            "sm": this.props.sm,
            "smd": this.props.smd,
            "md": this.props.md,
            "slg": this.props.slg,
            "lg": this.props.lg,
        };
        // inherit from smaller values if undefined
        if(values["xs"] == undefined) {
            values["xs"] = values["sxs"]
        }
        if(values["ssm"] == undefined) {
            values["ssm"] = values["xs"]
        }
        if(values["sm"] == undefined) {
            values["sm"] = values["ssm"]
        }
        if(values["smd"] == undefined) {
            values["smd"] = values["sm"]
        }
        if(values["md"] == undefined) {
            values["md"] = values["smd"]
        }
        if(values["slg"] == undefined) {
            values["slg"] = values["md"]
        }
        if(values["lg"] == undefined) {
            values["lg"] = values["slg"]
        }

        if(this.state.width <= 320) {
            size = values["sxs"]
        } else if(width <= 480) {
            size = values["xs"]
        } else if(width <= 624) {
            size = values["ssm"]
        } else if(width <= 768) {
            size = values["sm"]
        } else if(width <= 896) {
            size = values["smd"]
        } else if(width <= 1024) {
            size = values["md"]
        } else if(width <= 1232) {
            size = values["slg"]
        } else {
            size = values["lg"]
        }

        var style = (100.0 * size/12.0).toString() + "%"
        return (

                {this.props.children}

        );
    }
})

module.exports.ColP = ColP
<|endoftext|>


<commit_before>import 'babel-polyfill';
import inquirer from 'inquirer';
const ArgumentParser = require('argparse').ArgumentParser;
import { arrayify, isPositional, isRequired,
        getCommandArgs, loadConfig } from './utils';
import micromatch from 'micromatch';
import winston from 'winston';
import * as c from './const';
import { requireFn, names, pattern, LOCAL_FOLDERS, configObject, binEntryPoint,
        BASE_CONFIG, GLOBAL_CONFIG_FILE, CONFIG_FILE } from './config';
import complete from './complete';

let commandsClasses;
LOCAL_FOLDERS.forEach((name) => {
  commandsClasses = {
    ...commandsClasses,
    ...requireFn(name),
  };
});

micromatch(names, pattern).forEach((name) => {
  try {
    winston.debug(`Load command class: ${name}`);
    commandsClasses[name.split('-').pop()] = requireFn(name);
  } catch (e) {
    winston.error(`Error while loading command class: ${name}`);
  }
});

function mapInquirer(id, cfg, config) {
  let ret = {
    name: id[0],
    message: cfg.message || `Select ${cfg.help}`,
    ...(cfg.typeFunction && { filter: cfg.typeFunction }),
  };

  if ((cfg.nargs === '*' || cfg.nargs === '+') && cfg.promptChoices) {
    ret = {
      ...ret,
      type: 'checkbox',
      choices: Array.isArray(cfg.promptChoices) ?
        cfg.promptChoices : cfg.promptChoices.bind(null, config),
    };
  } if (cfg.promptRaw && cfg.promptChoices) {
    ret = {
      ...ret,
      type: 'rawList',
      choices: Array.isArray(cfg.promptChoices) ?
        cfg.promptChoices : cfg.promptChoices.bind(null, config),
    };
  } else if (cfg.promptChoices) {
    ret = {
      ...ret,
      type: 'list',
      choices: Array.isArray(cfg.promptChoices) ?
        cfg.promptChoices : cfg.promptChoices.bind(null, config),
    };
  } else if (cfg.isPassword) {
    ret = {
      ...ret,
      type: 'password',
      message: cfg.message || `Provide ${cfg.help || cfg.dest}`,
    };
  } else if (cfg.action === 'storeTrue') {
    ret = {
      ...ret,
      type: 'confirm',
      message: cfg.message || `Confirm ${cfg.help || cfg.dest}`,
    };
  } else {
    ret = {
      ...ret,
      type: 'input',
      message: cfg.message || `Provide ${cfg.help || cfg.dest}`,
    };
  }
  return ret;
}

function argsSelector(cfg) {
  return new Promise((resolveSelector) => {
    inquirer.prompt(cfg).then((answers) => {
      resolveSelector(answers);
    });
  });
}

function checkArgs(cmd, args, config) {
  const cfg = [];
  for (const param of getCommandArgs(cmd)) {
    if (isRequired(param.id, param.cfg) || param.cfg.isPassword) {
      const revealedParam = isPositional(param.id) ?
        parser._getPositional(param.id, param.cfg) :
        parser._getOptional(param.id, param.cfg);

      param.cfg.typeFunction = parser._registryGet('type', param.cfg.type, param.cfg.type);
      let val = args[revealedParam.dest];

      if ((val === null && !param.cfg.isPassword) ||
          (param.cfg.isPassword && val === c.EMPTY_PASSWORD)) {
        const promptConfig = mapInquirer(param.id, revealedParam, config);
        winston.debug(`map inquirer: ${param.id} -> `, promptConfig);
        cfg.push(promptConfig);
      }
    }
  }

  return argsSelector(cfg)
    .then(answers => ({
      ...args,
      ...answers,
    }));
}

function defineTopCommand(name, classes, parentParser) {
  const subparsers = parentParser.addSubparsers({
    title: '',
    dest: name,
  });

  return Object.keys(classes).reduce(
    (mem, cmdName) => {
      const cmd = defineCommand(subparsers, cmdName, classes[cmdName]);
      arrayify([cmdName, ...(cmd.aliases || [])]).forEach(alias => (mem[alias] = cmd));

      return mem;
    },
    {}
  );
}

function defineCommand(parentParser, cmdName, CmdCls) {
  let command;
  const cmdParserCfg = { addHelp: true };

  if (typeof CmdCls === 'function') {
    command = new CmdCls();
    command.isCommand = true;

    if (typeof command.aliases !== 'undefined') {
      cmdParserCfg.aliases = arrayify(command.aliases);
    }

    const cmdParser = parentParser.addParser(cmdName, cmdParserCfg);

    for (const param of getCommandArgs(command)) {
      cmdParser.addArgument(param.id, param.cfg);
    }
  } else {
    const cmdParser = parentParser.addParser(cmdName, cmdParserCfg);
    command = defineTopCommand(cmdName, CmdCls, cmdParser);
  }

  return command;
}

const parser = new ArgumentParser({
  version: configObject.version,
  addHelp: true,
  description: `${configObject.name} // ${configObject.description}`,
});

parser.addArgument(['-g', '--global'], {
  action: 'storeTrue',
  help: 'Use globals only, ignore project configs',
  defaultValue: false,
});

const commands = { root: defineTopCommand('root', commandsClasses, parser) };

if (!complete(binEntryPoint, commands, parser)) {
  let args = parser.parseArgs();
  const cmdPath = ['root'];
  let i = 'root';
  let command = commands[i];
  while (!command.isCommand) {
    i = args[i];
    cmdPath.push(i);
    command = command[i];
  }

  const config = loadConfig(args.global, BASE_CONFIG, GLOBAL_CONFIG_FILE, CONFIG_FILE);

  let resolvedArgs = args;

  if (typeof command.getArgs === 'function' || Array.isArray(command.args)) {
    resolvedArgs = config.then((cfg) => checkArgs(command, args, cfg));
  }

  Promise.all([
    Promise.resolve(resolvedArgs),
    config,
  ]).then((result) => {
    args = result[0];
    const cfg = result[1];

    Promise.resolve(command.exec(args, cfg))
      .then(results => {
        if (typeof command.print === 'function') {
          command.print(results, args, cfg);
        }
      })
      .catch(err => {
        if (typeof command.catch === 'function') {
          command.catch(err, args, cfg);
        } else {
          process.stderr.write(`Error while executing command: ${err}\n`);
        }
      });
  });
}
<commit_msg>Replaced version with --version, added -v verbose param<commit_after>import 'babel-polyfill';
import inquirer from 'inquirer';
const ArgumentParser = require('argparse').ArgumentParser;
import { arrayify, isPositional, isRequired,
        getCommandArgs, loadConfig } from './utils';
import micromatch from 'micromatch';
import winston from 'winston';
import * as c from './const';
import { requireFn, names, pattern, LOCAL_FOLDERS, configObject, binEntryPoint,
        BASE_CONFIG, GLOBAL_CONFIG_FILE, CONFIG_FILE } from './config';
import complete from './complete';

let commandsClasses;
LOCAL_FOLDERS.forEach((name) => {
  commandsClasses = {
    ...commandsClasses,
    ...requireFn(name),
  };
});

micromatch(names, pattern).forEach((name) => {
  try {
    winston.debug(`Load command class: ${name}`);
    commandsClasses[name.split('-').pop()] = requireFn(name);
  } catch (e) {
    winston.error(`Error while loading command class: ${name}`);
  }
});

function mapInquirer(id, cfg, config) {
  let ret = {
    name: id[0],
    message: cfg.message || `Select ${cfg.help}`,
    ...(cfg.typeFunction && { filter: cfg.typeFunction }),
  };

  if ((cfg.nargs === '*' || cfg.nargs === '+') && cfg.promptChoices) {
    ret = {
      ...ret,
      type: 'checkbox',
      choices: Array.isArray(cfg.promptChoices) ?
        cfg.promptChoices : cfg.promptChoices.bind(null, config),
    };
  } if (cfg.promptRaw && cfg.promptChoices) {
    ret = {
      ...ret,
      type: 'rawList',
      choices: Array.isArray(cfg.promptChoices) ?
        cfg.promptChoices : cfg.promptChoices.bind(null, config),
    };
  } else if (cfg.promptChoices) {
    ret = {
      ...ret,
      type: 'list',
      choices: Array.isArray(cfg.promptChoices) ?
        cfg.promptChoices : cfg.promptChoices.bind(null, config),
    };
  } else if (cfg.isPassword) {
    ret = {
      ...ret,
      type: 'password',
      message: cfg.message || `Provide ${cfg.help || cfg.dest}`,
    };
  } else if (cfg.action === 'storeTrue') {
    ret = {
      ...ret,
      type: 'confirm',
      message: cfg.message || `Confirm ${cfg.help || cfg.dest}`,
    };
  } else {
    ret = {
      ...ret,
      type: 'input',
      message: cfg.message || `Provide ${cfg.help || cfg.dest}`,
    };
  }
  return ret;
}

function argsSelector(cfg) {
  return new Promise((resolveSelector) => {
    inquirer.prompt(cfg).then((answers) => {
      resolveSelector(answers);
    });
  });
}

function checkArgs(cmd, args, config) {
  const cfg = [];
  for (const param of getCommandArgs(cmd)) {
    if (isRequired(param.id, param.cfg) || param.cfg.isPassword) {
      const revealedParam = isPositional(param.id) ?
        parser._getPositional(param.id, param.cfg) :
        parser._getOptional(param.id, param.cfg);

      param.cfg.typeFunction = parser._registryGet('type', param.cfg.type, param.cfg.type);
      let val = args[revealedParam.dest];

      if ((val === null && !param.cfg.isPassword) ||
          (param.cfg.isPassword && val === c.EMPTY_PASSWORD)) {
        const promptConfig = mapInquirer(param.id, revealedParam, config);
        winston.debug(`map inquirer: ${param.id} -> `, promptConfig);
        cfg.push(promptConfig);
      }
    }
  }

  return argsSelector(cfg)
    .then(answers => ({
      ...args,
      ...answers,
    }));
}

function defineTopCommand(name, classes, parentParser) {
  const subparsers = parentParser.addSubparsers({
    title: '',
    dest: name,
  });

  return Object.keys(classes).reduce(
    (mem, cmdName) => {
      const cmd = defineCommand(subparsers, cmdName, classes[cmdName]);
      arrayify([cmdName, ...(cmd.aliases || [])]).forEach(alias => (mem[alias] = cmd));

      return mem;
    },
    {}
  );
}

function defineCommand(parentParser, cmdName, CmdCls) {
  let command;
  const cmdParserCfg = { addHelp: true };

  if (typeof CmdCls === 'function') {
    command = new CmdCls();
    command.isCommand = true;

    if (typeof command.aliases !== 'undefined') {
      cmdParserCfg.aliases = arrayify(command.aliases);
    }

    const cmdParser = parentParser.addParser(cmdName, cmdParserCfg);

    for (const param of getCommandArgs(command)) {
      cmdParser.addArgument(param.id, param.cfg);
    }
  } else {
    const cmdParser = parentParser.addParser(cmdName, cmdParserCfg);
    command = defineTopCommand(cmdName, CmdCls, cmdParser);
  }

  return command;
}

const parser = new ArgumentParser({
  addHelp: true,
  description: `${configObject.name} // ${configObject.description}`,
});

parser.addArgument(['-g', '--global'], {
  action: 'storeTrue',
  help: 'Use globals only, ignore project configs',
  defaultValue: false,
});

parser.addArgument(['--version'], {
  action: 'version',
  version: `%(prog)s ${configObject.version}`,
});

parser.addArgument(['--verbose', '-v'], {
  action: 'count',
});

const commands = { root: defineTopCommand('root', commandsClasses, parser) };

if (!complete(binEntryPoint, commands, parser)) {
  let args = parser.parseArgs();
  const cmdPath = ['root'];
  let i = 'root';
  let command = commands[i];
  while (!command.isCommand) {
    i = args[i];
    cmdPath.push(i);
    command = command[i];
  }

  const config = loadConfig(args.global, BASE_CONFIG, GLOBAL_CONFIG_FILE, CONFIG_FILE);

  let resolvedArgs = args;

  if (typeof command.getArgs === 'function' || Array.isArray(command.args)) {
    resolvedArgs = config.then((cfg) => checkArgs(command, args, cfg));
  }

  Promise.all([
    Promise.resolve(resolvedArgs),
    config,
  ]).then((result) => {
    args = result[0];
    const cfg = result[1];

    Promise.resolve(command.exec(args, cfg))
      .then(results => {
        if (typeof command.print === 'function') {
          command.print(results, args, cfg);
        }
      })
      .catch(err => {
        if (typeof command.catch === 'function') {
          command.catch(err, args, cfg);
        } else {
          process.stderr.write(`Error while executing command: ${err}\n`);
        }
      });
  });
}
<|endoftext|>


<commit_before>import datastore from '@google-cloud/datastore';
import makeDebug from 'debug';
import Proto from 'uberproto';
import { NotFound } from 'feathers-errors';
const debug = makeDebug('feathers-datastore');

const MAX_INDEX_SIZE = 1500;

class Datastore {
  constructor(options = {}) {
    this.store = datastore({ projectId: options.projectId });

    this.id = options.id || 'id';
    this.kind = options.kind;
    this.events = options.events;
    this.autoIndex = options.autoIndex || false;

    // NOTE: This isn't nice, but it's the only way to give internal methods full
    //  unrestricted (no hooks) access to all methods
    [
      'find',
      'get',
      'create',
      'update',
      'patch',
      'remove'
    ].forEach(method => {
      this[method] = (...args) => this[`_${method}`](...args);
    });
  }

  extend(obj) {
    return Proto.extend(obj, this);
  }

  _get(id, params) {
    let key = this.makeKey(id, params);
    return this.store.get(key)
      .then(([ entity ]) => entity)
      .then(entity => this.entityToPlain(entity, true))
      .then(entity => {
        if (!entity) {
          throw new NotFound(`No record found for id '${id}'`);
        }

        return entity;
      });
  }

  _create(data, params = {}) {
    let entities,
        key;

    if (data.hasOwnProperty(this.id)) {
      key = this.makeKey(data[this.id], params);
    } else {
      key = this.makeKey(undefined, params);
    }

    entities = { key, data };

    // Normalize
    if (Array.isArray(data)) {
      entities = data.map(data => ({ key, data }));
    }

    // Convert entities to explicit format, to allow for indexing
    entities = this.makeExplicitEntity(entities, params);

    return this.store.insert(entities)
      .then(() => entities)
      .then(entity => this.entityToPlain(entity));
  }

  _update(id, data, params = {}) {
    let key = this.makeKey(id, params),
        entity = { key, data },
        { query = {} } = params,
        method = query.create ? 'upsert' : 'update';

    entity = this.makeExplicitEntity(entity, params);

    return this.store[method](entity)
      .then(() => entity)
      .then(entity => this.entityToPlain(entity))
      .catch(err => {
        // NOTE: Updating a not found entity will result in a bad request, rather than
        //  a not found, this gets around that, though in future should be made more
        //  secure
        if (err.code === 400 && err.message === 'no entity to update') {
          throw new NotFound(`No record found for id \'${id}'`);
        }

        throw err;
      });
  }

  _patch(id, data, params) {

    return Promise.resolve()
      .then(() => id ? this._get(id, params) : this._find(params))
      .then(results => {
        let entities,
            makeNewEntity = (current, update) => {
              return {
                key: this.makeKey(current[ this.id ], params),
                data: Object.assign({}, current, update)
              };
            };

        if (Array.isArray(results)) {
          entities = results.map(current => makeNewEntity(current, data));
        } else {
          entities = makeNewEntity(results, data);
        }

        entities = this.makeExplicitEntity(entities, params);

        return this.store.update(entities)
          .then(() => entities);
      })
      .then(entity => this.entityToPlain(entity));
  }

  _find(params = {}) {
    params.query = params.query || {};

    let { ancestor, namespace, kind = this.kind, ...query } = params.query,
        dsQuery = this.store.createQuery(namespace, kind),
        filters;

    if (ancestor) {
      let ancestorKey = this.makeKey(ancestor, params);
      dsQuery = dsQuery.hasAncestor(ancestorKey);
    }

    filters = Object.entries(query)
      .reduce((filters, [key, value]) => {
        const opMap = {
          $gt: '>',
          $gte: '>=',
          $lt: '<',
          $lte: '<=',
          '=': '='
        };

        let special;

        // Normalize
        if (typeof value !== 'object' || value instanceof this.store.key().constructor || value === null) {
          value = { '=': value };
        }

        special = Object.entries(value)
          .filter(([ op ]) => opMap[op])
          .map(([ op, val ]) => {
            // Try convert it into a number
            if (typeof val === 'string') {
              let valAsNum = parseFloat(val);

              if (!isNaN(valAsNum)) {
                // Its a number, assign it to original val
                val = valAsNum;
              }
            }

            return [ key, opMap[op], val ];
          });

        return [...filters, ...special];
      }, []);

    dsQuery = filters.reduce((q, filter) => q.filter(...filter), dsQuery);

    return dsQuery.run()
      .then(([ e ]) => e)
      .then(entity => this.entityToPlain(entity, true))
      .then(data => {
        if (ancestor) {
          return data.filter(({ id }) => id !== ancestor);
        }

        return data;
      });
  }

  _remove(id, params) {
    return Promise.resolve()
      .then(() => id ? this._get(id, params) : this._find(params))
      .then(results => {
        let keys;

        if (Array.isArray(results)) {
          keys = results.map(({ [ this.id ]: id }) => this.makeKey(id, params));
        } else {
          keys = this.makeKey(results[ this.id ], params);
        }

        return this.store.delete(keys)
          .then(() => results);
      });
  }

  makeKey(id, params = {}) {
    let { query = {} } = params,
        key;

    if (Array.isArray(id) || typeof id === 'object') {
      key = this.store.key(id);
    } else {
      // Try fetching a number
      let idAsNum = parseInt(id);
      if (!isNaN(idAsNum)) {
        id = idAsNum;
      }

      key = this.store.key([ this.kind, id ]);
    }

    if (query.namespace) {
      key.namespace = query.namespace;
    }

    return key;
  }

  entityToPlain(entity, alreadyFlat = false) {
    const ID_PROP = this.id;
    let data;

    if (Array.isArray(entity)) {
      return entity.map(e => this.entityToPlain(e, alreadyFlat));
    }

    if (!entity) {
      return entity;
    }

    data = alreadyFlat ? entity : entity.data;

    if (Array.isArray(data)) {
      // In explicit syntax, should deconstruct
      data = data.reduce((flat, { name, value }) => {
        flat[name] = value;
        return flat;
      }, {});
    }

    return Object.assign({}, data, { [ ID_PROP ]: Datastore.getKey(entity).path.slice(-1)[0] });
  }

  makeExplicitEntity(entity, options = {}) {
    const { dontIndex = [], autoIndex = this.autoIndex } = options.query || {};

    function isBig(value) {
      let valueType = typeof value;

      if (valueType === 'string' || value instanceof Buffer) {
        return Buffer.from(value).length > MAX_INDEX_SIZE;
      } else if (valueType === 'object' && value !== null) {
        // Must be an object, recursively build response
        return Object.keys(value)
          .map(key => value[key])
          .some(isBig);
      }

      // Number, boolean, undefined and null we either don't care about or are
      //  guaranteed < 1500
      return false;
    }

    function expandData(data) {
      const toBasicResponse = (name) => ({ name, value: data[name] }),
            addExclusions = (response) => {
              if (dontIndex.includes(response.name)) {
                response.excludeFromIndexes = true;
              } else if (autoIndex) {
                response.excludeFromIndexes = isBig(response.value);
              }

              return response;
            };

      return Object.keys(data)
        .map(toBasicResponse)
        .map(addExclusions);
    }

    if (Array.isArray(entity)) {
      return entity.map(this.makeExplicitEntity, this);
    }

    return {
      key: Datastore.getKey(entity),
      data: expandData(entity.data)
    };
  }

  static getKey(entity) {
    return entity[datastore.KEY] || entity.key;
  }
}

export default function init(options) {
  debug('Initializing feathers-datastore plugin');
  return new Datastore(options);
}

init.Service = Datastore;
<commit_msg>remove and patch methods should internally call own prototypes methods, rather than potential descendant prototype<commit_after>import datastore from '@google-cloud/datastore';
import makeDebug from 'debug';
import Proto from 'uberproto';
import { NotFound } from 'feathers-errors';
const debug = makeDebug('feathers-datastore');

const MAX_INDEX_SIZE = 1500;

class Datastore {
  constructor(options = {}) {
    this.store = datastore({ projectId: options.projectId });

    this.id = options.id || 'id';
    this.kind = options.kind;
    this.events = options.events;
    this.autoIndex = options.autoIndex || false;

    // NOTE: This isn't nice, but it's the only way to give internal methods full
    //  unrestricted (no hooks) access to all methods
    [
      'find',
      'get',
      'create',
      'update',
      'patch',
      'remove'
    ].forEach(method => {
      this[method] = (...args) => this[`_${method}`](...args);
    });
  }

  extend(obj) {
    return Proto.extend(obj, this);
  }

  _get(id, params) {
    let key = this.makeKey(id, params);
    return this.store.get(key)
      .then(([ entity ]) => entity)
      .then(entity => this.entityToPlain(entity, true))
      .then(entity => {
        if (!entity) {
          throw new NotFound(`No record found for id '${id}'`);
        }

        return entity;
      });
  }

  _create(data, params = {}) {
    let entities,
        key;

    if (data.hasOwnProperty(this.id)) {
      key = this.makeKey(data[this.id], params);
    } else {
      key = this.makeKey(undefined, params);
    }

    entities = { key, data };

    // Normalize
    if (Array.isArray(data)) {
      entities = data.map(data => ({ key, data }));
    }

    // Convert entities to explicit format, to allow for indexing
    entities = this.makeExplicitEntity(entities, params);

    return this.store.insert(entities)
      .then(() => entities)
      .then(entity => this.entityToPlain(entity));
  }

  _update(id, data, params = {}) {
    let key = this.makeKey(id, params),
        entity = { key, data },
        { query = {} } = params,
        method = query.create ? 'upsert' : 'update';

    entity = this.makeExplicitEntity(entity, params);

    return this.store[method](entity)
      .then(() => entity)
      .then(entity => this.entityToPlain(entity))
      .catch(err => {
        // NOTE: Updating a not found entity will result in a bad request, rather than
        //  a not found, this gets around that, though in future should be made more
        //  secure
        if (err.code === 400 && err.message === 'no entity to update') {
          throw new NotFound(`No record found for id \'${id}'`);
        }

        throw err;
      });
  }

  _patch(id, data, params) {
    const get = Datastore.prototype._get.bind(this),
          find = Datastore.prototype._find.bind(this);

    return Promise.resolve()
      .then(() => id ? get(id, params) : find(params))
      .then(results => {
        let entities,
            makeNewEntity = (current, update) => {
              return {
                key: this.makeKey(current[ this.id ], params),
                data: Object.assign({}, current, update)
              };
            };

        if (Array.isArray(results)) {
          entities = results.map(current => makeNewEntity(current, data));
        } else {
          entities = makeNewEntity(results, data);
        }

        entities = this.makeExplicitEntity(entities, params);

        return this.store.update(entities)
          .then(() => entities);
      })
      .then(entity => this.entityToPlain(entity));
  }

  _find(params = {}) {
    params.query = params.query || {};

    let { ancestor, namespace, kind = this.kind, ...query } = params.query,
        dsQuery = this.store.createQuery(namespace, kind),
        filters;

    if (ancestor) {
      let ancestorKey = this.makeKey(ancestor, params);
      dsQuery = dsQuery.hasAncestor(ancestorKey);
    }

    filters = Object.entries(query)
      .reduce((filters, [key, value]) => {
        const opMap = {
          $gt: '>',
          $gte: '>=',
          $lt: '<',
          $lte: '<=',
          '=': '='
        };

        let special;

        // Normalize
        if (typeof value !== 'object' || value instanceof this.store.key().constructor || value === null) {
          value = { '=': value };
        }

        special = Object.entries(value)
          .filter(([ op ]) => opMap[op])
          .map(([ op, val ]) => {
            // Try convert it into a number
            if (typeof val === 'string') {
              let valAsNum = parseFloat(val);

              if (!isNaN(valAsNum)) {
                // Its a number, assign it to original val
                val = valAsNum;
              }
            }

            return [ key, opMap[op], val ];
          });

        return [...filters, ...special];
      }, []);

    dsQuery = filters.reduce((q, filter) => q.filter(...filter), dsQuery);

    return dsQuery.run()
      .then(([ e ]) => e)
      .then(entity => this.entityToPlain(entity, true))
      .then(data => {
        if (ancestor) {
          return data.filter(({ id }) => id !== ancestor);
        }

        return data;
      });
  }

  _remove(id, params) {
    const get = Datastore.prototype._get.bind(this),
          find = Datastore.prototype._find.bind(this);

    return Promise.resolve()
      .then(() => id ? get(id, params) : find(params))
      .then(results => {
        let keys;

        if (results === null) {
          return null;
        }

        if (Array.isArray(results)) {
          keys = results.map(({ [ this.id ]: id }) => this.makeKey(id, params));
        } else {
          keys = this.makeKey(results[ this.id ], params);
        }

        return this.store.delete(keys)
          .then(() => results);
      });
  }

  makeKey(id, params = {}) {
    let { query = {} } = params,
        key;

    if (Array.isArray(id) || typeof id === 'object') {
      key = this.store.key(id);
    } else {
      // Try fetching a number
      let idAsNum = parseInt(id);
      if (!isNaN(idAsNum)) {
        id = idAsNum;
      }

      key = this.store.key([ this.kind, id ]);
    }

    if (query.namespace) {
      key.namespace = query.namespace;
    }

    return key;
  }

  entityToPlain(entity, alreadyFlat = false) {
    const ID_PROP = this.id;
    let data;

    if (Array.isArray(entity)) {
      return entity.map(e => this.entityToPlain(e, alreadyFlat));
    }

    if (!entity) {
      return entity;
    }

    data = alreadyFlat ? entity : entity.data;

    if (Array.isArray(data)) {
      // In explicit syntax, should deconstruct
      data = data.reduce((flat, { name, value }) => {
        flat[name] = value;
        return flat;
      }, {});
    }

    return Object.assign({}, data, { [ ID_PROP ]: Datastore.getKey(entity).path.slice(-1)[0] });
  }

  makeExplicitEntity(entity, options = {}) {
    const { dontIndex = [], autoIndex = this.autoIndex } = options.query || {};

    function isBig(value) {
      let valueType = typeof value;

      if (valueType === 'string' || value instanceof Buffer) {
        return Buffer.from(value).length > MAX_INDEX_SIZE;
      } else if (valueType === 'object' && value !== null) {
        // Must be an object, recursively build response
        return Object.keys(value)
          .map(key => value[key])
          .some(isBig);
      }

      // Number, boolean, undefined and null we either don't care about or are
      //  guaranteed < 1500
      return false;
    }

    function expandData(data) {
      const toBasicResponse = (name) => ({ name, value: data[name] }),
            addExclusions = (response) => {
              if (dontIndex.includes(response.name)) {
                response.excludeFromIndexes = true;
              } else if (autoIndex) {
                response.excludeFromIndexes = isBig(response.value);
              }

              return response;
            };

      return Object.keys(data)
        .map(toBasicResponse)
        .map(addExclusions);
    }

    if (Array.isArray(entity)) {
      return entity.map(this.makeExplicitEntity, this);
    }

    return {
      key: Datastore.getKey(entity),
      data: expandData(entity.data)
    };
  }

  static getKey(entity) {
    return entity[datastore.KEY] || entity.key;
  }
}

export default function init(options) {
  debug('Initializing feathers-datastore plugin');
  return new Datastore(options);
}

init.Service = Datastore;
<|endoftext|>


<commit_before>import t from 'tcomb';
import debug from 'debug';
import EventEmitter3 from 'eventemitter3';
import Query from './Query';
import AvengerCache from './AvengerCache';
import AvengerInput from './AvengerInput';
import { run, fromCache, runCached,
  minimizeCache as internalMinimizeCache,
  getQueriesToSkip as internalGetQueriesToSkip,
  upset as internalUpset } from './internals';

const log = debug('Avenger');

const AllQueries = t.dict(t.Str, Query, 'AllQueries');
const Queries = t.dict(t.Str, t.Any, 'Queries');
const StateKey = t.subtype(
  t.Any,
  v => t.Str.is(v) || t.Num.is(v) || t.Bool.is(v),
  'StateKey'
);
const State = t.dict(t.Str, StateKey, 'State');

// pre computed fetch params. Used for serialization
// output of internals/minimizeCache
const FetchParams = t.dict(
  t.Str,    // qId
  t.dict(
    t.Str,  // dependency qId
    t.Any   // dependency cached value
  ),
  'FetchParams'
);

export Query from './Query';

export const QuerySetInput = t.struct({
  queries: Queries,
  state: t.maybe(State)
}, 'QuerySetInput');

export const Recipe = QuerySetInput.extend({
  fetchParams: FetchParams,
  queriesToSkip: t.list(t.Str)
}, Recipe);

// export for tests
export class QuerySet {

  constructor(allQueries, input, cache = null, fromRecipe = null) {
    this.input = QuerySetInput(input);
    this.allQueries = allQueries;

    if (process.env.NODE_ENV !== 'production') {
      Object.keys(input.queries).forEach(qId => {
        t.assert(Query.is(this.allQueries[qId]), `Invalid query id: '${qId}'`);
      });
    }

    this.emitter = new EventEmitter3();
    this.cache = cache;
    this.fromRecipe = fromRecipe;
  }

  on(...args) {
    this.emitter.on(...args);
  }

  off(...args) {
    this.emitter.off(...args);
  }

  getAvengerInput() {
    return AvengerInput({
      queries: Object.keys(this.input.queries).map(qId => ({
        query: this.allQueries[qId],
        params: this.input.state
      }))
    });
  }

  run() {
    if (this.fromRecipe) {
      log('running from recipe', this);
      // running from recipe.
      const { fetchParams, queriesToSkip } = this.fromRecipe;
      // not emitting events here for simplicity
      return runCached(this.getAvengerInput(), fetchParams, queriesToSkip);
    } else {
      log('running local', this);
      log('cache state', this.cache.state);
      // entire run is local
      const cached = fromCache(this.getAvengerInput(), this.cache);
      this.emitter.emit('change', cached);
      log('from cache', cached);

      return run(this.getAvengerInput(), this.cache).then(result => {
        this.emitter.emit('change', result);
        log('final result', result);
        log('final cache', this.cache.state);
        return result;
      });
    }
  }

  toRecipe() {
    const { queries, state } = this.input;
    const fetchParams = internalMinimizeCache(this.getAvengerInput(), this.cache);
    const queriesToSkip = internalGetQueriesToSkip(internalUpset(this.getAvengerInput()), this.cache);
    return {
      queries, state, fetchParams, queriesToSkip
    };
  }

}

export default class Avenger {

  constructor(queries = {}, cacheInitialState = {}) {
    this.queries = AllQueries(queries);
    this.cache = new AvengerCache(cacheInitialState);
  }

  querySet(input) {
    return new QuerySet(this.queries, input, this.cache);
  }

  querySetFromRecipe(recipe) {
    const { queries, state, fetchParams, queriesToSkip } = Recipe(recipe);
    const input = QuerySetInput({
      queries, state
    });
    return new QuerySet(this.queries, input, null, { fetchParams, queriesToSkip });
  }

}
<commit_msg>add cached() method to QuerySet<commit_after>import t from 'tcomb';
import debug from 'debug';
import EventEmitter3 from 'eventemitter3';
import Query from './Query';
import AvengerCache from './AvengerCache';
import AvengerInput from './AvengerInput';
import { run, fromCache, runCached,
  minimizeCache as internalMinimizeCache,
  getQueriesToSkip as internalGetQueriesToSkip,
  upset as internalUpset } from './internals';

const log = debug('Avenger');

const AllQueries = t.dict(t.Str, Query, 'AllQueries');
const Queries = t.dict(t.Str, t.Any, 'Queries');
const StateKey = t.subtype(
  t.Any,
  v => t.Str.is(v) || t.Num.is(v) || t.Bool.is(v),
  'StateKey'
);
const State = t.dict(t.Str, StateKey, 'State');

// pre computed fetch params. Used for serialization
// output of internals/minimizeCache
const FetchParams = t.dict(
  t.Str,    // qId
  t.dict(
    t.Str,  // dependency qId
    t.Any   // dependency cached value
  ),
  'FetchParams'
);

export Query from './Query';

export const QuerySetInput = t.struct({
  queries: Queries,
  state: t.maybe(State)
}, 'QuerySetInput');

export const Recipe = QuerySetInput.extend({
  fetchParams: FetchParams,
  queriesToSkip: t.list(t.Str)
}, Recipe);

// export for tests
export class QuerySet {

  constructor(allQueries, input, cache = null, fromRecipe = null) {
    this.input = QuerySetInput(input);
    this.allQueries = allQueries;

    if (process.env.NODE_ENV !== 'production') {
      Object.keys(input.queries).forEach(qId => {
        t.assert(Query.is(this.allQueries[qId]), `Invalid query id: '${qId}'`);
      });
    }

    this.emitter = new EventEmitter3();
    this.cache = cache;
    this.fromRecipe = fromRecipe;
  }

  on(...args) {
    this.emitter.on(...args);
  }

  off(...args) {
    this.emitter.off(...args);
  }

  getAvengerInput() {
    return AvengerInput({
      queries: Object.keys(this.input.queries).map(qId => ({
        query: this.allQueries[qId],
        params: this.input.state
      }))
    });
  }

  cached() {
    const cached = fromCache(this.getAvengerInput(), this.cache);
    this.emitter.emit('change', cached);
    log('from cache', cached);
  }

  run() {
    if (this.fromRecipe) {
      log('running from recipe', this);
      // running from recipe.
      const { fetchParams, queriesToSkip } = this.fromRecipe;
      // not emitting events here for simplicity
      return runCached(this.getAvengerInput(), fetchParams, queriesToSkip);
    } else {
      // entire run is local
      log('running local', this);
      log('cache state', this.cache.state);

      this.cached();

      return run(this.getAvengerInput(), this.cache).then(result => {
        this.emitter.emit('change', result);
        log('final result', result);
        log('final cache', this.cache.state);
        return result;
      });
    }
  }

  toRecipe() {
    const { queries, state } = this.input;
    const fetchParams = internalMinimizeCache(this.getAvengerInput(), this.cache);
    const queriesToSkip = internalGetQueriesToSkip(internalUpset(this.getAvengerInput()), this.cache);
    return {
      queries, state, fetchParams, queriesToSkip
    };
  }

}

export default class Avenger {

  constructor(queries = {}, cacheInitialState = {}) {
    this.queries = AllQueries(queries);
    this.cache = new AvengerCache(cacheInitialState);
  }

  querySet(input) {
    return new QuerySet(this.queries, input, this.cache);
  }

  querySetFromRecipe(recipe) {
    const { queries, state, fetchParams, queriesToSkip } = Recipe(recipe);
    const input = QuerySetInput({
      queries, state
    });
    return new QuerySet(this.queries, input, null, { fetchParams, queriesToSkip });
  }

}
<|endoftext|>


<commit_before>
/**
 * @typedef {function(FpsInfo)} fpsCallback
 * @callback fpsCallback
 * @param {FpsInfo} fps Fps info object
 */

/**
* @typedef {Object} FpsInfo
* @property {number} fps The calculated frames per second
* @property {number} jitter The absolute difference since the last calculated fps
* @property {number} elapsed Milliseconds ellapsed since the last computation
* @property {number} frames Number of frames since the last computation
* @property {number} trigger Next computation will happen at this amount of frames
*/

/**
 * FPS Meter - Returns a function that is used to compute the framerate without the overhead of updating the DOM every frame.
 * @param {fpsCallback} callback Callback fired every time the FPS is computed
 * @param {number} [refreshRate=1] Refresh rate which the fps is computed and the callback is fired (0 to compute every frame, not recommended)
 * @return {function} Returns a function that should be called on every the loop tick
 * @author Victor B - www.vitim.us - github.com/victornpb/fpsMeter
 */
export default function createFpsMeter(callback, refreshRate = 1) {
  if (typeof callback !== 'function') throw new Error('Callback is not a function');
  if (typeof refreshRate !== 'number') throw new Error('refreshRate should be a number! e.g. 2 (fps)');

  /** number of frames since last computation */
  let frames = 0;
  /** compute fps at this amount of frames (it will try to match the refresh rate) */
  let trigger = 0;

  /** previous timestamp */
  let lastTimestamp = 0;

  /** last computed fps value */
  let lastFps = 0;
  /** computed jitter */
  let jitter = 0;

  // use performance.now() or fallback to Date.now() only check on initialization
  const millis = (typeof performance === 'object' && 'now' in performance) ? performance.now.bind(performance) : Date.now.bind(Date);

  return function fpsMeterTick() {
    if (++frames > trigger) {
      const now = millis();
      if (lastTimestamp === 0) lastTimestamp = now;
      const elapsed = now - lastTimestamp;

      if (elapsed > 0) {
        // calculate fps
        const fps = 1000 / (elapsed / frames);

        // calculate jitter
        jitter = Math.abs(lastFps - fps);

        // converge the trigger value exponentialy to match the current refresh rate.
        trigger = refreshRate > 0 ? (trigger * 0.5) + ((fps / refreshRate) * 0.5) : 0;

        const info = {
          fps: fps,
          jitter: jitter,
          elapsed: elapsed,
          frames: frames,
          trigger: trigger,
        };

        // reset variables for the next measurement
        lastTimestamp = now;
        lastFps = fps;
        frames = 0;

        return callback(info);
      } else {
        // 2 frames on the same milliseconds, ramp the trigger up
        trigger *= 1.5;
      }
    }
  };
}
<commit_msg>improved validation<commit_after>
/**
 * @typedef {function(FpsInfo)} fpsCallback
 * @callback fpsCallback
 * @param {FpsInfo} fps Fps info object
 */

/**
* @typedef {Object} FpsInfo
* @property {number} fps The calculated frames per second
* @property {number} jitter The absolute difference since the last calculated fps
* @property {number} elapsed Milliseconds ellapsed since the last computation
* @property {number} frames Number of frames since the last computation
* @property {number} trigger Next computation will happen at this amount of frames
*/

/**
 * FPS Meter - Returns a function that is used to compute the framerate without the overhead of updating the DOM every frame.
 * @param {fpsCallback} callback Callback fired every time the FPS is computed
 * @param {number} [refreshRate=1] Refresh rate which the fps is computed and the callback is fired (0 to compute every frame, not recommended)
 * @return {function} Returns a function that should be called on every the loop tick
 * @author Victor B - www.vitim.us - github.com/victornpb/fpsMeter
 */
export default function createFpsMeter(callback, refreshRate = 1) {
  if (typeof callback !== 'function') throw new Error('Callback is not a function');
  if (typeof refreshRate !== 'number' || isNaN(refreshRate) || refreshRate < 0 || refreshRate===Infinity) throw new Error('refreshRate should be a positive number! e.g. 2 (fps)');

  /** number of frames since last computation */
  let frames = 0;
  /** compute fps at this amount of frames (it will try to match the refresh rate) */
  let trigger = 0;

  /** previous timestamp */
  let lastTimestamp = 0;

  /** last computed fps value */
  let lastFps = 0;
  /** computed jitter */
  let jitter = 0;

  // use performance.now() or fallback to Date.now() only check on initialization
  const millis = (typeof performance === 'object' && 'now' in performance) ? performance.now.bind(performance) : Date.now.bind(Date);

  return function fpsMeterTick() {
    if (++frames > trigger) {
      const now = millis();
      if (lastTimestamp === 0) lastTimestamp = now;
      const elapsed = now - lastTimestamp;

      if (elapsed > 0) {
        // calculate fps
        const fps = 1000 / (elapsed / frames);

        // calculate jitter
        jitter = Math.abs(lastFps - fps);

        // converge the trigger value exponentialy to match the current refresh rate.
        trigger = refreshRate > 0 ? (trigger * 0.5) + ((fps / refreshRate) * 0.5) : 0;

        const info = {
          fps: fps,
          jitter: jitter,
          elapsed: elapsed,
          frames: frames,
          trigger: trigger,
        };

        // reset variables for the next measurement
        lastTimestamp = now;
        lastFps = fps;
        frames = 0;

        return callback(info);
      } else {
        // 2 frames on the same milliseconds, ramp the trigger up
        trigger *= 1.5;
      }
    }
  };
}
<|endoftext|>


<commit_before>var sgf = require('staged-git-files')
var minimatch = require('minimatch')
var ora = require('ora')
var assign = require('object-assign')
var appRoot = require('app-root-path')
var config = require(appRoot.resolve('package.json'))
var runScript = require('./runScript')

var defaultLinters = {}
var customLinters = config['lint-staged']
var linters = assign(defaultLinters, customLinters)
var spinner = ora('Starting lint-staged').start()

sgf('ACM', function (err, results) {
    if (err) {
        console.error(err)
    }
    var filePaths = results.map(function (file) {
        return file.filename
    })
    if (filePaths.length) {
        Object.keys(linters).forEach(function (key) {
            var linter = linters[key]
            var fileList = filePaths.filter(minimatch.filter(key, { matchBase: true }))
            if (fileList.length) {
                spinner.text = 'Running ' + Array.isArray(linter) ? linter.join(' → ') : linter + '...'
                runScript(linter, fileList, config, function (error, exitCode) {
                    if (error) {
                        console.error(error)
                    }
                    if (exitCode > 0) {
                        console.log('😱  %s found some issues. Fix them and try again.', linter, exitCode)
                    }
                    spinner.stop()
                    spinner.clear()
                })
            } else {
                spinner.stop()
            }
        })
    } else {
        spinner.stop()
        console.log('\n👀  Nothing to lint. `git add` some files and try again...\n')
    }
})

<commit_msg>Incorrect condition<commit_after>var sgf = require('staged-git-files')
var minimatch = require('minimatch')
var ora = require('ora')
var assign = require('object-assign')
var appRoot = require('app-root-path')
var config = require(appRoot.resolve('package.json'))
var runScript = require('./runScript')

var defaultLinters = {}
var customLinters = config['lint-staged']
var linters = assign(defaultLinters, customLinters)
var spinner = ora('Starting lint-staged').start()

sgf('ACM', function (err, results) {
    if (err) {
        console.error(err)
    }
    var filePaths = results.map(function (file) {
        return file.filename
    })
    if (filePaths.length) {
        Object.keys(linters).forEach(function (key) {
            var linter = linters[key]
            var fileList = filePaths.filter(minimatch.filter(key, { matchBase: true }))
            if (fileList.length) {
                spinner.text = 'Running ' + (Array.isArray(linter) ? linter.join(' → ') : linter + '...')
                runScript(linter, fileList, config, function (error, exitCode) {
                    if (error) {
                        console.error(error)
                    }
                    if (exitCode > 0) {
                        console.log('😱  %s found some issues. Fix them and try again.', linter, exitCode)
                    }
                    spinner.stop()
                    spinner.clear()
                })
            } else {
                spinner.stop()
            }
        })
    } else {
        spinner.stop()
        console.log('\n👀  Nothing to lint. `git add` some files and try again...\n')
    }
})

<|endoftext|>


<commit_before>/**
 * External imports
 */
import _ from 'underscore';
import mingo from 'mingo';
import libdebug from 'debug';

// create debug logger
const debug = libdebug('storage-adapter');

export const ADAPTABLE_METHODS = [
  'skip',
  'sort',
  'find',
  'limit',
  'insert',
  'update',
  'remove',
  'aggregate',
];

function isAdaptable(storage) {
  return typeof storage === 'object'
  && _.every(ADAPTABLE_METHODS, (method) => method in storage);
}

const PROTOTYPE = {
  find(query, projection) {
    debug('received query %j', query);
    debug('received projection %j', projection);

    return mingo.find(this.storage, query, projection).all();
  },
};

export default function createAdapter(options = {}) {
  debug('passed-in options (keys only): %j', Object.keys(options));
  debug('passed-in storage (type): %j', typeof options.storage);

  if (!options.storage) throw new Error('`options.storage` is missing.');
  if (!(_.isArray(options.storage) || isAdaptable(options.storage))) {
    throw new Error('`options.storage` should be an adaptable or an array.');
  }

  return Object.create(PROTOTYPE, {
    storage: {
      value: options.storage,
    },
  });
}
<commit_msg>Update adapter find to return a promise.<commit_after>/**
 * External imports
 */
import _ from 'underscore';
import co from 'co';
import mingo from 'mingo';
import libdebug from 'debug';

// create debug logger
const debug = libdebug('storage-adapter');

export const ADAPTABLE_METHODS = [
  'skip',
  'sort',
  'find',
  'limit',
  'insert',
  'update',
  'remove',
  'aggregate',
];

function isAdaptable(storage) {
  return typeof storage === 'object'
  && _.every(ADAPTABLE_METHODS, (method) => method in storage);
}

const PROTOTYPE = {
  find(query, projection) {
    debug('received query %j', query);
    debug('received projection %j', projection);

    const adapter = this;
    return co(function* findInnerGen() {
      return mingo.find(adapter.storage, query, projection).all();
    });
  },
};

export default function createAdapter(options = {}) {
  debug('passed-in options (keys only): %j', Object.keys(options));
  debug('passed-in storage (type): %j', typeof options.storage);

  if (!options.storage) throw new Error('`options.storage` is missing.');
  if (!(_.isArray(options.storage) || isAdaptable(options.storage))) {
    throw new Error('`options.storage` should be an adaptable or an array.');
  }

  return Object.create(PROTOTYPE, {
    storage: {
      value: options.storage,
    },
  });
}
<|endoftext|>