<commit_before>(function(){
/*
CRL (Cor Runtime Library)
*/

CRL = (typeof CRL === 'undefined' ? {} : CRL);

var
hasProp     = Object.prototype.hasOwnProperty,
toString    = Object.prototype.toString,
slice       = Array.prototype.slice,

// store function that instantiate classes
// whith different quantity of arguments
instancers  = [],
nativeTypes = {
    'String'   : String,
    'Number'   : Number,
    'Boolean'  : Boolean,
    'RegExp'   : RegExp,
    'Array'    : Array,
    'Object'   : Object,
    'Function' : Function
};

// copy properties from an object to another
// returns the object which properties has been copied to
CRL.copyObj = function copyObj(from, to) {
    var name;

    for (name in from) {
        if (hasProp.call(from, name)) {
            to[name] = from[name];
        }
    }

    return to;
};

// creates an instance of a class
// CRL.create(Class, arg1, arg2, ...)
CRL.create = function create(Class) {
    if (typeof Class !== 'function') {
        throw Error('Runtime Error: trying to instanstiate no class');
    }

    var
    instancerArgs,
    args      = slice.call(arguments, 1),
    argc      = args.length,
    i         = -1,
    instancer = instancers[argc];

    if (! instancer) {
        instancerArgs = [];

        while (++i < argc) {
            instancerArgs.push('args[' + i + ']');
        }

        instancer = instancers[argc] = new Function(
            'cls',
            'args',
            'return new cls(' + instancerArgs.join(',') + ');'
        );
    }

    return instancer(Class, args);
};

// convert a class in a subclass of other class
// CRL.subclass(Subclass, Superclass)
CRL.subclass = function subclass(subClass, superClass) {
    CRL.copyObj(superClass, subClass);

    function Proto() {
        this.constructor = subClass;
    }

    Proto.prototype    = superClass.prototype;
    subClass.prototype = new Proto();
}

// extract keys from an object or array
// CRL.keys([5, 7, 3])    -> [0, 1, 2]
// CRL.keys({x: 2, y: 4}) -> ['x', 'y']
CRL.keys = function keys(obj) {
    var keys, i, len;

    // is array
    if (obj instanceof Array) {
        i    = -1;
        len  = obj.length;
        keys = [];

        while (++i < len) {
            keys.push(i);
        }

        return keys;
    }

    // if has key function
    if (typeof Object.keys === 'function') {
        return Object.keys(obj);
    }

    // otherwise polyfill it
    for (i in obj) {
        if (hasProp.call(obj, i)) {
            keys.push(i);
        }
    }
    return keys;
};

// whether a object is instance of a class or not
// CRL.assertType({}, Object)
// CRL.assertType(person, Person)
CRL.assertType = function assertType(obj, Class) {
    var type;

    if (Class === void 0) {
        return obj === void 0;
    }

    if (typeof Class !== 'function') {
        throw 'Trying to assert invalid class';
    }

    if (typeof obj === 'undefined') {
        throw 'Trying to assert undefined object';
    }

    // try with instanceof
    if (obj instanceof Class) {
        return true;
    }

    // try with finding the native type according to "Object.prototype.toString"
    type = toString.call(obj);
    type = type.substring(8, type.length - 1);
    if(hasProp.call(nativeTypes, type) && nativeTypes[type] === Class) {
        return true;
    }

    return false;
};

CRL.regex = function regex(pattern, flags) {
    return new RegExp(pattern, flags);
}

})();

(function(global) {

// Lightweight non standard compliant Promise
function Promise(resolverFn) {
    if (typeof resolverFn !== 'function') {
        throw 'provided resolver must be a function';
    }

    var p = this;

    // this.value;
    // this.reason;
    this.completed      = false;
    this.fail           = false;
    this.success        = false;
    this.thenListeners  = [];
    this.catchListeners = [];

    resolverFn(
        function resolve(value){
            Promise.doResolve(p, value);
        },
        function reject(reason) {
            Promise.doReject(p, reason);
        }
    );
}

Promise.prototype = {

    then: function(fn) {
        this.thenListeners.push(fn);
        if (this.success) {
            Promise.doResolve(this, this.value);
        }
        return this;
    },

    catch: function(fn) {
        this.catchListeners.push(fn);
        if (this.fail) {
            Promise.doReject(this, this.reason);
        }
        return this;
    }
};

Promise.doResolve = function resolve(p, value) {
    p.thenListeners.forEach(function(listener) {
        listener(value);
    })

    p.completed = true;
    p.success   = true;
    p.value     = value;
};

Promise.doReject = function reject(p, reason) {
    p.catchListeners.forEach(function(listener){
        listener(reason);
    })

    p.completed = true;
    p.fail      = true;
    p.reason    = reason;
};

Promise.all = function all(array) {
    var promise,
    i          = -1,
    numPending = 0,
    result     = [],
    len        = array.length;

    return new Promise(function(resolve) {
        while (++i < len) {
            promise = array[i];
            if (isPromise(promise)) {
                setupThen(promise, i);
            }
            else {
                result[i] = array[i];
                tryToResolve();
            }
        }

        function setupThen(promise, i) {
            numPending++;

            // default value
            result[i] = void 0;

            promise.then(function(value) {
                result[i] = value;
                numPending--;
                tryToResolve();
            })
        }

        function tryToResolve() {
            if (numPending === 0) {
                resolve(result)
            }
        }
    })
}

Promise.defer = function defer() {
    var deferred     = {};
    // use CRL.Promise
    deferred.promise = new CRL.Promise(function(resolve, reject) {
        deferred.resolve = resolve;
        deferred.reject  = reject;
    })

    return deferred;
}

CRL.Promise = Promise;

// polyfill Promise
if (typeof global.Promise !== 'function') {
    global.Promise = CRL.Promise;
}

// Coroutines
// Schedule
function schedule(fn, time) {
    if (time === void 0 && typeof global.setImmediate !== 'undefined') {
        setImmediate(fn);
    } else {
        setTimeout(fn, +time);
    }
}

function isPromise(p) {
    return p && typeof p.then === 'function';
}

function isFunction(f) {
    return typeof f === 'function';
}

function isObject(obj) {
    return obj && Object == obj.constructor;
}

function isArray(arr) {
    return Array.isArray(arr);
}

// Generator Runner
CRL.go = function go(genf, ctx) {
    var state, gen = genf.apply(ctx || {});

    return new CRL.Promise(function(resolve, reject) {
        // ensure it runs asynchronously
        schedule(next);

        function next(value) {
            if (state && state.done) {
                resolve(value);
                return;
            }

            state = gen.next(value);
            value = state.value;

            if (isPromise(value)) {
                value.then(function(value) {
                    next(value);
                })

                value.catch(function(reason) {
                    gen.throw(reason);
                })
                return;
            }

            next(value);
        }
    })
}

// convert to promise as much possible
function toPromise(obj) {
    if (isPromise(obj)) {
        return obj;
    }

    if (isArray(obj)) {
        return arrayToPromise(obj);
    }

    if (isObject(obj)) {
        return objectToPromise(obj);
    }
}

// convert array to promise
function arrayToPromise(array) {
    var promise;
    return CRL.Promise.all(array.map(function(value) {
        promise = toPromise(value);
        if (isPromise(promise)) {
            return promise;
        }

        return value;
    }));
}

// convert object to promise
function objectToPromise(obj) {
    var key, promise, ret,
    promises = [],
    result   = {},
    i        = -1,
    keys     = Object.keys(obj),
    len      = keys.length;

    ret = new CRL.Promise(function(resolve) {

        while (++i < len) {
            key     = keys[i];
            promise = toPromise(obj[key]);
            if (isPromise(promise)) {
                setupThen(promise, key);
            }
            else {
                result[key] = obj[key];
            }
        }

        CRL.Promise.all(promises).then(function() {
            resolve(result);
        })

        function setupThen(promise, key) {
            // default value
            result[key] = void 0;

            promise.then(function(value) {
                result[key] = value;
            })

            promises.push(promise);
        }

    })

    return ret;
}

// receiver
CRL.receive = function receive(obj) {
    var prom;

    if (obj && isFunction(obj.receive)) {
        return obj.receive();
    }

    prom = toPromise(obj);
    if (isPromise(prom)) {
        return prom;
    }

    return obj;
}

// sender
CRL.send = function send(obj, value) {
    if (obj && isFunction(obj.send)) {
        return obj.send(value);
    }
    throw 'unable to receive values';
}

function timeout(time) {
    if (!isNaN(time) && time !== null) {
        return new CRL.Promise(function(resolve) {
            schedule(resolve, time)
        })
    }

    throw 'Invalid time';
}

CRL.timeout = timeout;

// Buffer: simple array based buffer to use with channels
function Buffer(size) {
    this.size  = isNaN(size) ? 1 : size;
    this.array = [];
}

Buffer.prototype = {

    shift: function() {
        return this.array.shift();
    },

    push: function(value) {
        if (this.isFull()) { return false }
        this.array.push(value);
        return true;
    },

    isFull: function() {
        return !(this.array.length < this.size);
    },

    isEmpty: function() {
        return this.array.length === 0;
    }
}

// Channel: a structure to transport messages
function indentityFn(x) {return x}

function scheduledResolve(deferred, value) {
    schedule(function() { deferred.resolve(value) })
}

function Channel(buffer, transform) {
    this.buffer           = buffer;
    this.closed           = false;
    this.data             = void 0;
    this.senderPromises   = [];
    this.receiverPromises = [];
    this.transform        = transform || indentityFn;
}

Channel.prototype = {

    receive: function() {
        var data, deferred;

        // is unbuffered
        if (! this.buffer) {
            // there is data?
            if (this.data !== void 0) {
                // resume the first sender coroutine
                if (this.senderPromises[0]) {
                    scheduledResolve(this.senderPromises.shift());
                }
                // clean and return
                data      = this.data;
                this.data = void 0;
                return data;

            // if no data
            } else {
                // suspend the coroutine wanting to receive
                deferred = Promise.defer();
                this.receiverPromises.push(deferred);
                return deferred.promise;
            }
        }

        // if buffered
        // empty buffer?
        if (this.buffer.isEmpty()) {
            // suspend the coroutine wanting to receive
            deferred = Promise.defer();
            this.receiverPromises.push(deferred);
            return deferred.promise;

        // some value in the buffer?
        } else {
            // resume the first sender coroutine
            if (this.senderPromises[0]) {
                scheduledResolve(this.senderPromises.shift());
            }
            // clean and return
            return this.buffer.shift();
        }
    },

    send: function(data) {
        if (this.closed) { throw 'closed channel' }
        var deferred;

        // is unbuffered
        if (! this.buffer) {
            // some stored data?
            if (this.data !== void 0) {
                // deliver data to the first waiting coroutine
                if (this.receiverPromises[0]) {
                    scheduledResolve(this.receiverPromises.shift(), this.data);
                }

            // no stored data?
            } else {
                // pass sent data directly to the first waiting for it
                if (this.receiverPromises[0]) {
                    this.data = void 0;
                    scheduledResolve(this.receiverPromises.shift(), this.transform(data));
                    // schedule the the sender coroutine
                    return new timeout(0);
                }
            }

            // else, store the transformed data
            this.data = this.transform(data);
            deferred = Promise.defer();
            this.senderPromises.push(deferred);
            return deferred.promise;
        }

        // if buffered
        // emty buffer?
        if (! this.buffer.isFull()) {
            // TODO: optimize below code
            // store sent value in the buffer
            this.buffer.push(this.transform(data));
            // if any waiting for the data, give it
            if (this.receiverPromises[0]) {
                scheduledResolve(this.receiverPromises.shift(), this.buffer.shift());
            }
        }

        // full buffer?
        if (this.buffer.isFull()) {
            // stop until the buffer start to be drained
            deferred = Promise.defer();
            this.senderPromises.push(deferred);
            return deferred.promise;
        }
    },

    close: function() {
        this.closed         = true;
        this.senderPromises = [];
        while (this.receiverPromises.length) {
            scheduledResolve(this.receiverPromises.shift());
        }
    }
}

CRL.Channel = Channel;

CRL.chan = function chan(size, transform) {
    if (size instanceof Buffer) {
        return new Channel(size, transform);
    }

    // isNaN(null) == false  :O
    if (isNaN(size) || size === null) {
        return new Channel(null, transform);
    }

    return new Channel(new Buffer(size), transform);
}

})(this);
<commit_msg>refactor coroutines error handling<commit_after>(function(){
/*
CRL (Cor Runtime Library)
*/

CRL = (typeof CRL === 'undefined' ? {} : CRL);

var
hasProp     = Object.prototype.hasOwnProperty,
toString    = Object.prototype.toString,
slice       = Array.prototype.slice,

// store function that instantiate classes
// whith different quantity of arguments
instancers  = [],
nativeTypes = {
    'String'   : String,
    'Number'   : Number,
    'Boolean'  : Boolean,
    'RegExp'   : RegExp,
    'Array'    : Array,
    'Object'   : Object,
    'Function' : Function
};

// copy properties from an object to another
// returns the object which properties has been copied to
CRL.copyObj = function copyObj(from, to) {
    var name;

    for (name in from) {
        if (hasProp.call(from, name)) {
            to[name] = from[name];
        }
    }

    return to;
};

// creates an instance of a class
// CRL.create(Class, arg1, arg2, ...)
CRL.create = function create(Class) {
    if (typeof Class !== 'function') {
        throw Error('Runtime Error: trying to instanstiate no class');
    }

    var
    instancerArgs,
    args      = slice.call(arguments, 1),
    argc      = args.length,
    i         = -1,
    instancer = instancers[argc];

    if (! instancer) {
        instancerArgs = [];

        while (++i < argc) {
            instancerArgs.push('args[' + i + ']');
        }

        instancer = instancers[argc] = new Function(
            'cls',
            'args',
            'return new cls(' + instancerArgs.join(',') + ');'
        );
    }

    return instancer(Class, args);
};

// convert a class in a subclass of other class
// CRL.subclass(Subclass, Superclass)
CRL.subclass = function subclass(subClass, superClass) {
    CRL.copyObj(superClass, subClass);

    function Proto() {
        this.constructor = subClass;
    }

    Proto.prototype    = superClass.prototype;
    subClass.prototype = new Proto();
}

// extract keys from an object or array
// CRL.keys([5, 7, 3])    -> [0, 1, 2]
// CRL.keys({x: 2, y: 4}) -> ['x', 'y']
CRL.keys = function keys(obj) {
    var keys, i, len;

    // is array
    if (obj instanceof Array) {
        i    = -1;
        len  = obj.length;
        keys = [];

        while (++i < len) {
            keys.push(i);
        }

        return keys;
    }

    // if has key function
    if (typeof Object.keys === 'function') {
        return Object.keys(obj);
    }

    // otherwise polyfill it
    for (i in obj) {
        if (hasProp.call(obj, i)) {
            keys.push(i);
        }
    }
    return keys;
};

// whether a object is instance of a class or not
// CRL.assertType({}, Object)
// CRL.assertType(person, Person)
CRL.assertType = function assertType(obj, Class) {
    var type;

    if (Class === void 0) {
        return obj === void 0;
    }

    if (typeof Class !== 'function') {
        throw 'Trying to assert invalid class';
    }

    if (typeof obj === 'undefined') {
        throw 'Trying to assert undefined object';
    }

    // try with instanceof
    if (obj instanceof Class) {
        return true;
    }

    // try with finding the native type according to "Object.prototype.toString"
    type = toString.call(obj);
    type = type.substring(8, type.length - 1);
    if(hasProp.call(nativeTypes, type) && nativeTypes[type] === Class) {
        return true;
    }

    return false;
};

CRL.regex = function regex(pattern, flags) {
    return new RegExp(pattern, flags);
}

})();

(function(global) {

// Lightweight non standard compliant Promise
function Promise(resolverFn) {
    if (typeof resolverFn !== 'function') {
        throw 'provided resolver must be a function';
    }

    var p = this;

    // this.value;
    // this.reason;
    this.completed      = false;
    this.fail           = false;
    this.success        = false;
    this.thenListeners  = [];
    this.catchListeners = [];

    resolverFn(
        function resolve(value){
            Promise.doResolve(p, value);
        },
        function reject(reason) {
            Promise.doReject(p, reason);
        }
    );
}

Promise.prototype = {

    then: function(fnFulfill, fnReject) {
        this.thenListeners.push(fnFulfill);
        if (this.success) {
            Promise.doResolve(this, this.value);
        }
        if (fnReject) {
            this.catch(fnReject);
        }
        return this;
    },

    catch: function(fn) {
        this.catchListeners.push(fn);
        if (this.fail) {
            Promise.doReject(this, this.reason);
        }
        return this;
    }
};

Promise.doResolve = function resolve(p, value) {
    p.thenListeners.forEach(function(listener) {
        listener(value);
    })

    p.completed = true;
    p.success   = true;
    p.value     = value;
};

Promise.doReject = function reject(p, reason) {

    if (p.catchListeners.length === 0) {
        console.log('Uncaught (in promise): ' + reason);
    }

    p.catchListeners.forEach(function(listener) {
        listener(reason);
    })

    p.completed = true;
    p.fail      = true;
    p.reason    = reason;
};

Promise.all = function all(array) {
    var promise,
    i          = -1,
    numPending = 0,
    result     = [],
    len        = array.length;

    return new Promise(function(resolve) {
        while (++i < len) {
            promise = array[i];
            if (isPromise(promise)) {
                setupThen(promise, i);
            }
            else {
                result[i] = array[i];
                tryToResolve();
            }
        }

        function setupThen(promise, i) {
            numPending++;

            // default value
            result[i] = void 0;

            promise.then(function(value) {
                result[i] = value;
                numPending--;
                tryToResolve();
            })
        }

        function tryToResolve() {
            if (numPending === 0) {
                resolve(result)
            }
        }
    })
}

Promise.defer = function defer() {
    var deferred     = {};
    // use CRL.Promise
    deferred.promise = new CRL.Promise(function(resolve, reject) {
        deferred.resolve = resolve;
        deferred.reject  = reject;
    })

    return deferred;
}

CRL.Promise = Promise;

// polyfill Promise
if (typeof global.Promise !== 'function') {
    global.Promise = CRL.Promise;
}

// Coroutines
// Schedule
function schedule(fn, time) {
    if (time === void 0 && typeof global.setImmediate !== 'undefined') {
        setImmediate(fn);
    } else {
        setTimeout(fn, +time);
    }
}

function isPromise(p) {
    return p && typeof p.then === 'function';
}

function isFunction(f) {
    return typeof f === 'function';
}

function isObject(obj) {
    return obj && Object == obj.constructor;
}

function isArray(arr) {
    return Array.isArray(arr);
}

// Generator Runner
CRL.go = function go(genf, ctx) {
    var state, gen = genf.apply(ctx || {});

    return new CRL.Promise(function(resolve, reject) {
        // ensure it runs asynchronously
        schedule(next);

        function next(value) {
            if (state && state.done) {
                resolve(value);
                return;
            }

            try {
                state = gen.next(value);
                value = state.value;
            } catch (e) {
                console.error(e.stack ? '\n' + e.stack : e);
                return;
            }

            if (isPromise(value)) {
                value.then(
                    function onFulfilled(value) {
                        next(value)
                    },
                    function onRejected(reason) {
                        gen.throw(reason)
                    }
                )
                return;
            }

            next(value);
        }
    })
}

// convert to promise as much possible
function toPromise(obj) {
    if (isPromise(obj)) {
        return obj;
    }

    if (isArray(obj)) {
        return arrayToPromise(obj);
    }

    if (isObject(obj)) {
        return objectToPromise(obj);
    }
}

// convert array to promise
function arrayToPromise(array) {
    var promise;
    return CRL.Promise.all(array.map(function(value) {
        promise = toPromise(value);
        if (isPromise(promise)) {
            return promise;
        }

        return value;
    }));
}

// convert object to promise
function objectToPromise(obj) {
    var key, promise, ret,
    promises = [],
    result   = {},
    i        = -1,
    keys     = Object.keys(obj),
    len      = keys.length;

    ret = new CRL.Promise(function(resolve) {

        while (++i < len) {
            key     = keys[i];
            promise = toPromise(obj[key]);
            if (isPromise(promise)) {
                setupThen(promise, key);
            }
            else {
                result[key] = obj[key];
            }
        }

        CRL.Promise.all(promises).then(function() {
            resolve(result);
        })

        function setupThen(promise, key) {
            // default value
            result[key] = void 0;

            promise.then(function(value) {
                result[key] = value;
            })

            promises.push(promise);
        }

    })

    return ret;
}

// receiver
CRL.receive = function receive(obj) {
    var prom;

    if (obj && isFunction(obj.receive)) {
        return obj.receive();
    }

    prom = toPromise(obj);
    if (isPromise(prom)) {
        return prom;
    }

    return obj;
}

// sender
CRL.send = function send(obj, value) {
    if (obj && isFunction(obj.send)) {
        return obj.send(value);
    }
    throw 'unable to receive values';
}

function timeout(time) {
    if (!isNaN(time) && time !== null) {
        return new CRL.Promise(function(resolve) {
            schedule(resolve, time)
        })
    }

    throw 'Invalid time';
}

CRL.timeout = timeout;

// Buffer: simple array based buffer to use with channels
function Buffer(size) {
    this.size  = isNaN(size) ? 1 : size;
    this.array = [];
}

Buffer.prototype = {

    shift: function() {
        return this.array.shift();
    },

    push: function(value) {
        if (this.isFull()) { return false }
        this.array.push(value);
        return true;
    },

    isFull: function() {
        return !(this.array.length < this.size);
    },

    isEmpty: function() {
        return this.array.length === 0;
    }
}

// Channel: a structure to transport messages
function indentityFn(x) {return x}

function scheduledResolve(deferred, value) {
    schedule(function() { deferred.resolve(value) })
}

function Channel(buffer, transform) {
    this.buffer           = buffer;
    this.closed           = false;
    this.data             = void 0;
    this.senderPromises   = [];
    this.receiverPromises = [];
    this.transform        = transform || indentityFn;
}

Channel.prototype = {

    receive: function() {
        var data, deferred;

        // is unbuffered
        if (! this.buffer) {
            // there is data?
            if (this.data !== void 0) {
                // resume the first sender coroutine
                if (this.senderPromises[0]) {
                    scheduledResolve(this.senderPromises.shift());
                }
                // clean and return
                data      = this.data;
                this.data = void 0;
                return data;

            // if no data
            } else {
                // suspend the coroutine wanting to receive
                deferred = Promise.defer();
                this.receiverPromises.push(deferred);
                return deferred.promise;
            }
        }

        // if buffered
        // empty buffer?
        if (this.buffer.isEmpty()) {
            // suspend the coroutine wanting to receive
            deferred = Promise.defer();
            this.receiverPromises.push(deferred);
            return deferred.promise;

        // some value in the buffer?
        } else {
            // resume the first sender coroutine
            if (this.senderPromises[0]) {
                scheduledResolve(this.senderPromises.shift());
            }
            // clean and return
            return this.buffer.shift();
        }
    },

    send: function(data) {
        if (this.closed) { throw 'closed channel' }
        var deferred;

        // is unbuffered
        if (! this.buffer) {
            // some stored data?
            if (this.data !== void 0) {
                // deliver data to the first waiting coroutine
                if (this.receiverPromises[0]) {
                    scheduledResolve(this.receiverPromises.shift(), this.data);
                }

            // no stored data?
            } else {
                // pass sent data directly to the first waiting for it
                if (this.receiverPromises[0]) {
                    this.data = void 0;
                    scheduledResolve(this.receiverPromises.shift(), this.transform(data));
                    // schedule the the sender coroutine
                    return new timeout(0);
                }
            }

            // else, store the transformed data
            this.data = this.transform(data);
            deferred = Promise.defer();
            this.senderPromises.push(deferred);
            return deferred.promise;
        }

        // if buffered
        // emty buffer?
        if (! this.buffer.isFull()) {
            // TODO: optimize below code
            // store sent value in the buffer
            this.buffer.push(this.transform(data));
            // if any waiting for the data, give it
            if (this.receiverPromises[0]) {
                scheduledResolve(this.receiverPromises.shift(), this.buffer.shift());
            }
        }

        // full buffer?
        if (this.buffer.isFull()) {
            // stop until the buffer start to be drained
            deferred = Promise.defer();
            this.senderPromises.push(deferred);
            return deferred.promise;
        }
    },

    close: function() {
        this.closed         = true;
        this.senderPromises = [];
        while (this.receiverPromises.length) {
            scheduledResolve(this.receiverPromises.shift());
        }
    }
}

CRL.Channel = Channel;

CRL.chan = function chan(size, transform) {
    if (size instanceof Buffer) {
        return new Channel(size, transform);
    }

    // isNaN(null) == false  :O
    if (isNaN(size) || size === null) {
        return new Channel(null, transform);
    }

    return new Channel(new Buffer(size), transform);
}

})(this);
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

const program = require('commander');
const chalk = require('chalk');
const miteApi = require('mite-api');

const pkg = require('./../package.json');
const config = require('./config');
const formater = require('./lib/formater');
const DataOutput = require('./lib/data-output');
const listCommand = require('./lib/commands/list');
const columnOptions = require('./lib/options/columns');
const commandOptions = require('./lib/options');
const { handleError } = require('./lib/errors');

// no other options or comamnd line arguments used, default "period" to "today"
if (process.argv.length === 2) {
  process.argv.splice(2, 0, 'today');
}

program
  .version(pkg.version)
  .description('list time entries', {
    period:
      `name of the period for which the time entries should be shown \
or a single date. F.e. "today" or "last_week or "2019-03-17". \
Defaults to "today" when no other options are used and to "all" \
when other options are used.`
  })
  .arguments('<period>')
  .option.apply(program, commandOptions.toArgs(commandOptions.billable),
    'show entries which are billable or not billable'
  )
  .option(
    '--columns <columns>',
    columnOptions.description(listCommand.columns.options),
    columnOptions.parse
  )
  .option(
    '--customer-id <id>',
    'customer id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.format, null, config.get('outputFormat')))
  .option(
    '--from <period|YYYY-MM-DD>',
    'in combination with "to" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option(
    '--group-by <column>',
    'optional grouping parameter which should be used. Valid values are ' +
    listCommand.groupBy.options.join(', ')
  )
  .option(
    '-l, --limit <limit>',
    'optional number of items to show, default is infinite',
    undefined,
    ((val) => parseInt(val, 10))
  )
  .option(
    '--locked <true|false>',
    'filter entries by their locked status',
    (val => ['true', 'yes', 'ja', 'ok', '1'].indexOf(val.toLowerCase()) > -1),
    null
  )
  .option(
    '--min-duration <minDuration>',
    'filter out entries which have a duration below the given value (client side)',
  )
  .option(
    '--max-duration <maxDuration>',
    'filter out entries which have a duration above the given value (client side)',
  )
  .option(
    '--project-id <id>',
    'project id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option(
    '--to <period|YYYY-MM-DD>',
    'in combination with "from" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.tracking))
  .option(
    '--reversed',
    'reverse the sorting direction',
  )
  .option(
    '-s --search <query>',
    'search within the notes, to filter by multiple criteria connected with OR use comma-separated query values',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .option(
    '--service-id <id>',
    'service id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(
    commandOptions.sort,
    commandOptions.sort.description(listCommand.sort.options),
    listCommand.sort.default
  ))
  .option(
    '--user-id <id>',
    'optional single user id who’s time entries should be returned or ' +
    'multiple values comma-separated. Note that the current user may not ' +
    'have the permission ot read other user’s time entries which will result ' +
    'in an empty response',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .on('--help', function() {
    console.log(`
Examples:

  list all entries from the current month:
    mite list this_month

  list all entries which note contains the given search query:
    mite list this_year --search JIRA-123

  show all entries from two services 123 and 38171
    mite list last_month --service-id 123,38171

  show all time entries from a specific date
    mite list 2019-10-21

  show time entries from last thursday
    mite list thursday

  show all users who tracked billable entries ordered by the amount of time
  they have tracked:
    mite list this_year --billable true --columns user,duration --group-by user --sort duration

  export all time-entries from the current month as csv:
    mite list last_week --format csv --columns user,id

  create a markdown report of all customer and their generated profits:
    mite list this_year --format md --group-by customer --sort revenue

  The output of mite list can be forwarded to other commands using xargs. The
  following example will delete all matchin entries:
    mite list this_month --search="query" --columns id --format text | xargs -n1 mite delete

  Get the notes for one specific service, project for the last month to put
  them on a bill or similar
    mite list last_month --project-id 2681601 --service-id 325329 --columns note --format text | sort -u

  Show a seperate report for all users showing the revenues and times per
  service for all users matching a query:
    mite users --search marc --columns id --format text | xargs mite list last_month --group-by service --user-id

`);
  })
  .parse(process.argv);

/**
 * Returns the request options for requesting the time entries or grouped
 * time entries for the given time entries and filtering options.
 *
 * @param {string} period
 * @param {object} program
 * @return {Object<String, any>} time entries or grouped time entries
 */
function getRequestOptions(period, program) {

  // mite’s "periods" strings using underscore like in "this_month", "this_week"
  // but sometimes the user enters a minus instead of underscore, then replace
  // it
  if (typeof period === 'string' && !period.match(/[\d]+/)) {
    period = period.replace(/-/g, '_');
  }
  // check if the period is a week day name and calculate the date of this
  // weekday, f.e. "friday" from last week becomes the date a string
  const weekdays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
  const matchingWeekday = weekdays.find(weekday => {
    return (
      weekday === period ||
      period.substr(0, 2).toLowerCase() === weekday.substr(0, 2)
    );
  });
  if (matchingWeekday) {
    const weekdayIndex = weekdays.indexOf(matchingWeekday);
    const todayIndex = (new Date).getDay();
    const now = new Date();
    if (todayIndex <= weekdayIndex) {
      now.setDate(now.getDate() - (7 - weekdayIndex + todayIndex));
    } else {
      now.setDate(now.getDate() - weekdayIndex - 1);
    }
    period = now.toISOString().substr(0, 10);
  }

  const data = {
    ...(typeof program.billable === 'boolean' && { billable: program.billable }),
    ...(program.customerId && { customer_id: program.customerId }),
    ...(program.reversed && { direction: 'asc' }),
    ...(program.groupBy && { group_by: program.groupBy }),
    ...(program.limit && { limit: program.limit }),
    ...(typeof program.locked === 'boolean' && { locked: program.locked }),
    ...(program.search && { note: program.search }),
    ...(program.projectId && { project_id: program.projectId }),
    ...(program.serviceId && { service_id: program.serviceId }),
    ...(program.sort && { sort: program.sort }),
    ...(typeof program.tracking === 'boolean' && { tracking: program.tracking }),
    ...(program.userId && { user_id: program.userId}),
  };

  // add optional time period using from & to
  if (program.from && program.to) {
    data.from = program.from;
    data.to = program.to;
  } else if (period) {
    data.at = period;
  }

  return data;
}

/**
 * Callback function to filter time entries which are shown depending on the
 * command line options
 *
 * @param {object} program
 * @param {MiteTimeEntry} entry
 * @return {boolean}
 */
function filterData(program, row) {
  let valid = true;
  if (program.minDuration) {
    const minDuration = formater.durationToMinutes(program.minDuration, 10);
    valid &= row.minutes >= minDuration;
  }
  if (program.maxDuration) {
    const maxDuration = formater.durationToMinutes(program.maxDuration, 10);
    valid &= row.minutes <= maxDuration;
  }
  return valid;
}

function getReport(items, columns, format) {
  const tableData = DataOutput.compileTableData(items, columns, format);

  // Table footer
  // add table footer if any of the table columns has a reducer
  if (columnOptions.hasReducer(columns)) {
    let footerColumns = DataOutput.getTableFooterColumns(items, columns);
    footerColumns = footerColumns.map(v => v ? chalk.bold(v) : v); // make footer bold
    tableData.push(footerColumns);
  }

  return DataOutput.formatData(tableData, format, columns);
}

function main(period) {
  const mite = miteApi(config.get());

  const requestOpts = getRequestOptions(period, program);
  // "columns" default option is different
  if (!program.columns) {
    // when groupBy is used, make sure that revenue and duration are used
    if (program.groupBy) {
      program.columns = program.groupBy + ',revenue,duration';
    } else {
      program.columns = config.get().listColumns;
    }
  }
  const columns = columnOptions.resolve(program.columns, listCommand.columns.options);

  mite.getTimeEntries(requestOpts, (err, results) => {
    if (err) return handleError(err);

    // decide wheter to output grouped report or single entry report
    let items = results
      .map(data => data[program.groupBy ? 'time_entry_group' : 'time_entry'])
      .filter(v => v)
      .filter(filterData.bind(this, program))
      ;
    const report = getReport(items, columns, program.format);
    console.log(report);
  });
} // main

const period = program.args[0];
main(period);
<commit_msg>fix(mite-list): wrongly accepted weekday<commit_after>#!/usr/bin/env node
'use strict';

const program = require('commander');
const chalk = require('chalk');
const miteApi = require('mite-api');

const pkg = require('./../package.json');
const config = require('./config');
const formater = require('./lib/formater');
const DataOutput = require('./lib/data-output');
const listCommand = require('./lib/commands/list');
const columnOptions = require('./lib/options/columns');
const commandOptions = require('./lib/options');
const { handleError } = require('./lib/errors');

// no other options or comamnd line arguments used, default "period" to "today"
if (process.argv.length === 2) {
  process.argv.splice(2, 0, 'today');
}

program
  .version(pkg.version)
  .description('list time entries', {
    period:
      `name of the period for which the time entries should be shown \
or a single date. F.e. "today" or "last_week or "2019-03-17". \
Defaults to "today" when no other options are used and to "all" \
when other options are used.`
  })
  .arguments('<period>')
  .option.apply(program, commandOptions.toArgs(commandOptions.billable),
    'show entries which are billable or not billable'
  )
  .option(
    '--columns <columns>',
    columnOptions.description(listCommand.columns.options),
    columnOptions.parse
  )
  .option(
    '--customer-id <id>',
    'customer id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.format, null, config.get('outputFormat')))
  .option(
    '--from <period|YYYY-MM-DD>',
    'in combination with "to" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option(
    '--group-by <column>',
    'optional grouping parameter which should be used. Valid values are ' +
    listCommand.groupBy.options.join(', ')
  )
  .option(
    '-l, --limit <limit>',
    'optional number of items to show, default is infinite',
    undefined,
    ((val) => parseInt(val, 10))
  )
  .option(
    '--locked <true|false>',
    'filter entries by their locked status',
    (val => ['true', 'yes', 'ja', 'ok', '1'].indexOf(val.toLowerCase()) > -1),
    null
  )
  .option(
    '--min-duration <minDuration>',
    'filter out entries which have a duration below the given value (client side)',
  )
  .option(
    '--max-duration <maxDuration>',
    'filter out entries which have a duration above the given value (client side)',
  )
  .option(
    '--project-id <id>',
    'project id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option(
    '--to <period|YYYY-MM-DD>',
    'in combination with "from" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.tracking))
  .option(
    '--reversed',
    'reverse the sorting direction',
  )
  .option(
    '-s --search <query>',
    'search within the notes, to filter by multiple criteria connected with OR use comma-separated query values',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .option(
    '--service-id <id>',
    'service id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(
    commandOptions.sort,
    commandOptions.sort.description(listCommand.sort.options),
    listCommand.sort.default
  ))
  .option(
    '--user-id <id>',
    'optional single user id who’s time entries should be returned or ' +
    'multiple values comma-separated. Note that the current user may not ' +
    'have the permission ot read other user’s time entries which will result ' +
    'in an empty response',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .on('--help', function() {
    console.log(`
Examples:

  list all entries from the current month:
    mite list this_month

  list all entries which note contains the given search query:
    mite list this_year --search JIRA-123

  show all entries from two services 123 and 38171
    mite list last_month --service-id 123,38171

  show all time entries from a specific date
    mite list 2019-10-21

  show time entries from last thursday
    mite list thursday

  show all users who tracked billable entries ordered by the amount of time
  they have tracked:
    mite list this_year --billable true --columns user,duration --group-by user --sort duration

  export all time-entries from the current month as csv:
    mite list last_week --format csv --columns user,id

  create a markdown report of all customer and their generated profits:
    mite list this_year --format md --group-by customer --sort revenue

  The output of mite list can be forwarded to other commands using xargs. The
  following example will delete all matchin entries:
    mite list this_month --search="query" --columns id --format text | xargs -n1 mite delete

  Get the notes for one specific service, project for the last month to put
  them on a bill or similar
    mite list last_month --project-id 2681601 --service-id 325329 --columns note --format text | sort -u

  Show a seperate report for all users showing the revenues and times per
  service for all users matching a query:
    mite users --search marc --columns id --format text | xargs mite list last_month --group-by service --user-id

`);
  })
  .parse(process.argv);

/**
 * Returns the request options for requesting the time entries or grouped
 * time entries for the given time entries and filtering options.
 *
 * @param {string} period
 * @param {object} program
 * @return {Object<String, any>} time entries or grouped time entries
 */
function getRequestOptions(period, program) {

  // mite’s "periods" strings using underscore like in "this_month", "this_week"
  // but sometimes the user enters a minus instead of underscore, then replace
  // it
  if (typeof period === 'string' && !period.match(/[\d]+/)) {
    period = period.replace(/-/g, '_');
  }
  // check if the period is a week day name and calculate the date of this
  // weekday, f.e. "friday" from last week becomes the date a string
  const weekdays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
  const matchingWeekday = weekdays.find(weekday => {
    return (
      weekday === period ||
      period.toLowerCase() === weekday.toLowerCase() ||
      period.toLowerCase() === weekday.substr(0, 2)
    );
  });
  if (matchingWeekday) {
    const weekdayIndex = weekdays.indexOf(matchingWeekday);
    const todayIndex = (new Date).getDay();
    const now = new Date();
    if (todayIndex <= weekdayIndex) {
      now.setDate(now.getDate() - (7 - weekdayIndex + todayIndex));
    } else {
      now.setDate(now.getDate() - weekdayIndex - 1);
    }
    period = now.toISOString().substr(0, 10);
  }

  const data = {
    ...(typeof program.billable === 'boolean' && { billable: program.billable }),
    ...(program.customerId && { customer_id: program.customerId }),
    ...(program.reversed && { direction: 'asc' }),
    ...(program.groupBy && { group_by: program.groupBy }),
    ...(program.limit && { limit: program.limit }),
    ...(typeof program.locked === 'boolean' && { locked: program.locked }),
    ...(program.search && { note: program.search }),
    ...(program.projectId && { project_id: program.projectId }),
    ...(program.serviceId && { service_id: program.serviceId }),
    ...(program.sort && { sort: program.sort }),
    ...(typeof program.tracking === 'boolean' && { tracking: program.tracking }),
    ...(program.userId && { user_id: program.userId}),
  };

  // add optional time period using from & to
  if (program.from && program.to) {
    data.from = program.from;
    data.to = program.to;
  } else if (period) {
    data.at = period;
  }

  return data;
}

/**
 * Callback function to filter time entries which are shown depending on the
 * command line options
 *
 * @param {object} program
 * @param {MiteTimeEntry} entry
 * @return {boolean}
 */
function filterData(program, row) {
  let valid = true;
  if (program.minDuration) {
    const minDuration = formater.durationToMinutes(program.minDuration, 10);
    valid &= row.minutes >= minDuration;
  }
  if (program.maxDuration) {
    const maxDuration = formater.durationToMinutes(program.maxDuration, 10);
    valid &= row.minutes <= maxDuration;
  }
  return valid;
}

function getReport(items, columns, format) {
  const tableData = DataOutput.compileTableData(items, columns, format);

  // Table footer
  // add table footer if any of the table columns has a reducer
  if (columnOptions.hasReducer(columns)) {
    let footerColumns = DataOutput.getTableFooterColumns(items, columns);
    footerColumns = footerColumns.map(v => v ? chalk.bold(v) : v); // make footer bold
    tableData.push(footerColumns);
  }

  return DataOutput.formatData(tableData, format, columns);
}

function main(period) {
  const mite = miteApi(config.get());

  const requestOpts = getRequestOptions(period, program);
  // "columns" default option is different
  if (!program.columns) {
    // when groupBy is used, make sure that revenue and duration are used
    if (program.groupBy) {
      program.columns = program.groupBy + ',revenue,duration';
    } else {
      program.columns = config.get().listColumns;
    }
  }
  const columns = columnOptions.resolve(program.columns, listCommand.columns.options);

  mite.getTimeEntries(requestOpts, (err, results) => {
    if (err) return handleError(err);

    // decide wheter to output grouped report or single entry report
    let items = results
      .map(data => data[program.groupBy ? 'time_entry_group' : 'time_entry'])
      .filter(v => v)
      .filter(filterData.bind(this, program))
      ;
    const report = getReport(items, columns, program.format);
    console.log(report);
  });
} // main

const period = program.args[0];
main(period);
<|endoftext|>


<commit_before>/* global require, process, Buffer, module */
'use strict';

var fs = require("fs");
var path = require("path");
var join = path.join;
var crypto = require("crypto");
var RSA = require("node-rsa");
var archiver = require("archiver");
var Promise = require("es6-promise").Promise;
var resolve = require("./resolver.js");

function ChromeExtension(attrs) {
  if ((this instanceof ChromeExtension) !== true) {
    return new ChromeExtension(attrs);
  }

  /*
   Defaults
   */
  this.appId = null;

  this.rootDirectory = '';

  this.publicKey = null;

  this.privateKey = null;

  this.codebase = null;

  this.path = null;

  this.src = '**';

  /*
  Copying attributes
   */
  for (var name in attrs) {
    this[name] = attrs[name];
  }

  this.loaded = false;
}

ChromeExtension.prototype = {

  /**
   * Packs the content of the extension in a crx file.
   *
   * @param {Buffer=} contentsBuffer
   * @returns {Promise}
   * @example
   *
   * crx.pack().then(function(crxContent){
   *  // do something with the crxContent binary data
   * });
   *
   */
  pack: function (contentsBuffer) {
    if (!this.loaded) {
      return this.load().then(this.pack.bind(this, contentsBuffer));
    }

    var selfie = this;
    var packP = [
      this.generatePublicKey(),
      contentsBuffer || selfie.loadContents()
    ];

    return Promise.all(packP).then(function(outputs){
      var publicKey = outputs[0];
      var contents = outputs[1];

      selfie.publicKey = publicKey;

      var signature = selfie.generateSignature(contents);

      return selfie.generatePackage(signature, publicKey, contents);
    });
  },

  /**
   * Loads extension manifest and copies its content to a workable path.
   *
   * @param {string=} path
   * @returns {Promise}
   */
  load: function (path) {
    var selfie = this;

    return resolve(path || selfie.rootDirectory)
      .then(function(metadata){
        selfie.path = metadata.path;
        selfie.src = metadata.src;

        selfie.manifest = require(join(selfie.path, "manifest.json"));
        selfie.loaded = true;

        return selfie;
      });
  },

  /**
   * Writes data into the extension workable directory.
   *
   * @deprecated
   * @param {string} path
   * @param {*} data
   * @returns {Promise}
   */
  writeFile: function (path, data) {
    var absPath = join(this.path, path);

    /* istanbul ignore next */
    return new Promise(function(resolve, reject){
      fs.writeFile(absPath, data, function (err) {
        if (err) {
          return reject(err);
        }

        resolve();
      });
    });
  },

  /**
   * Generates a public key.
   *
   * BC BREAK `this.publicKey` is not stored anymore (since 1.0.0)
   * BC BREAK callback parameter has been removed in favor to the promise interface.
   *
   * @returns {Promise} Resolves to {Buffer} containing the public key
   * @example
   *
   * crx.generatePublicKey(function(publicKey){
   *   // do something with publicKey
   * });
   */
  generatePublicKey: function () {
    var privateKey = this.privateKey;

    return new Promise(function(resolve, reject){
      if (!privateKey) {
        return reject('Impossible to generate a public key: privateKey option has not been defined or is empty.');
      }

      var key = new RSA(privateKey);

      resolve(key.exportKey('pkcs8-public-der'));
    });
  },

  /**
   * Generates a SHA1 package signature.
   *
   * BC BREAK `this.signature` is not stored anymore (since 1.0.0)
   *
   * @param {Buffer} contents
   * @returns {Buffer}
   */
  generateSignature: function (contents) {
    return new Buffer(
      crypto
        .createSign("sha1")
        .update(contents)
        .sign(this.privateKey),
      "binary"
    );
  },

  /**
   *
   * BC BREAK `this.contents` is not stored anymore (since 1.0.0)
   *
   * @returns {Promise}
   */
  loadContents: function () {
    var selfie = this;

    return new Promise(function(resolve, reject){
      var archive = archiver('zip');
      var contents = new Buffer('');

      if (!selfie.loaded) {
	      throw new Error('crx.load needs to be called first in order to prepare the workspace.');
      }

      archive.on('error', reject);

      /*
        TODO: Remove in v4.
        It will be better to resolve an archive object
        rather than fitting everything in memory.

        @see https://github.com/oncletom/crx/issues/61
      */
      archive.on('data', function (buf) {
        contents = Buffer.concat([contents, buf]);
      });

      archive.on('finish', function () {
        resolve(contents);
      });

      archive
        .glob(selfie.src, {
          cwd: selfie.path,
          matchBase: true,
          ignore: ['*.pem', '.git', '*.crx']
        })
        .finalize();
    });
  },

  /**
   * Generates and returns a signed package from extension content.
   *
   * BC BREAK `this.package` is not stored anymore (since 1.0.0)
   *
   * @param {Buffer} signature
   * @param {Buffer} publicKey
   * @param {Buffer} contents
   * @returns {Buffer}
   */
  generatePackage: function (signature, publicKey, contents) {
    var keyLength = publicKey.length;
    var sigLength = signature.length;
    var zipLength = contents.length;
    var length = 16 + keyLength + sigLength + zipLength;

    var crx = new Buffer(length);

    crx.write("Cr24" + new Array(13).join("\x00"), "binary");

    crx[4] = 2;
    crx.writeUInt32LE(keyLength, 8);
    crx.writeUInt32LE(sigLength, 12);

    publicKey.copy(crx, 16);
    signature.copy(crx, 16 + keyLength);
    contents.copy(crx, 16 + keyLength + sigLength);

    return crx;
  },

  /**
   * Generates an appId from the publicKey.
   * Public key has to be set for this to work, otherwise an error is thrown.
   *
   * BC BREAK `this.appId` is not stored anymore (since 1.0.0)
   * BC BREAK introduced `publicKey` parameter as it is not stored any more since 2.0.0
   *
   * @param {Buffer|string} [publicKey] the public key to use to generate the app ID
   * @returns {string}
   */
  generateAppId: function (publicKey) {
    publicKey = publicKey || this.publicKey;
    if (typeof publicKey !== 'string' && !(publicKey instanceof Buffer)) {
      throw new Error('Public key is neither set, nor given');
    }
    return crypto
      .createHash("sha256")
      .update(publicKey)
      .digest("hex")
      .slice(0, 32)
      .replace(/./g, function (x) {
        return (parseInt(x, 16) + 10).toString(26);
      });
  },

  /**
   * Generates an updateXML file from the extension content.
   *
   * BC BREAK `this.updateXML` is not stored anymore (since 1.0.0)
   *
   * @returns {Buffer}
   */
  generateUpdateXML: function () {
    if (!this.codebase) {
      throw new Error("No URL provided for update.xml.");
    }

    return new Buffer(
      "<?xml version='1.0' encoding='UTF-8'?>\n" +
      "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n" +
      "  <app appid='" + (this.appId || this.generateAppId()) + "'>\n" +
      "    <updatecheck codebase='" + this.codebase + "' version='" + this.manifest.version + "' />\n" +
      "  </app>\n" +
      "</gupdate>"
    );
  }
};

module.exports = ChromeExtension;
<commit_msg>Remove the manifest data from cache on crx.load()<commit_after>/* global require, process, Buffer, module */
'use strict';

var fs = require("fs");
var path = require("path");
var join = path.join;
var crypto = require("crypto");
var RSA = require("node-rsa");
var archiver = require("archiver");
var Promise = require("es6-promise").Promise;
var resolve = require("./resolver.js");

function ChromeExtension(attrs) {
  if ((this instanceof ChromeExtension) !== true) {
    return new ChromeExtension(attrs);
  }

  /*
   Defaults
   */
  this.appId = null;

  this.rootDirectory = '';

  this.publicKey = null;

  this.privateKey = null;

  this.codebase = null;

  this.path = null;

  this.src = '**';

  /*
  Copying attributes
   */
  for (var name in attrs) {
    this[name] = attrs[name];
  }

  this.loaded = false;
}

ChromeExtension.prototype = {

  /**
   * Packs the content of the extension in a crx file.
   *
   * @param {Buffer=} contentsBuffer
   * @returns {Promise}
   * @example
   *
   * crx.pack().then(function(crxContent){
   *  // do something with the crxContent binary data
   * });
   *
   */
  pack: function (contentsBuffer) {
    if (!this.loaded) {
      return this.load().then(this.pack.bind(this, contentsBuffer));
    }

    var selfie = this;
    var packP = [
      this.generatePublicKey(),
      contentsBuffer || selfie.loadContents()
    ];

    return Promise.all(packP).then(function(outputs){
      var publicKey = outputs[0];
      var contents = outputs[1];

      selfie.publicKey = publicKey;

      var signature = selfie.generateSignature(contents);

      return selfie.generatePackage(signature, publicKey, contents);
    });
  },

  /**
   * Loads extension manifest and copies its content to a workable path.
   *
   * @param {string=} path
   * @returns {Promise}
   */
  load: function (path) {
    var selfie = this;

    return resolve(path || selfie.rootDirectory)
      .then(function(metadata){
        selfie.path = metadata.path;
        selfie.src = metadata.src;

        var manifestPath = join(selfie.path, 'manifest.json')
        delete require.cache[manifestPath];

        selfie.manifest = require(manifestPath);
        selfie.loaded = true;

        return selfie;
      });
  },

  /**
   * Writes data into the extension workable directory.
   *
   * @deprecated
   * @param {string} path
   * @param {*} data
   * @returns {Promise}
   */
  writeFile: function (path, data) {
    var absPath = join(this.path, path);

    /* istanbul ignore next */
    return new Promise(function(resolve, reject){
      fs.writeFile(absPath, data, function (err) {
        if (err) {
          return reject(err);
        }

        resolve();
      });
    });
  },

  /**
   * Generates a public key.
   *
   * BC BREAK `this.publicKey` is not stored anymore (since 1.0.0)
   * BC BREAK callback parameter has been removed in favor to the promise interface.
   *
   * @returns {Promise} Resolves to {Buffer} containing the public key
   * @example
   *
   * crx.generatePublicKey(function(publicKey){
   *   // do something with publicKey
   * });
   */
  generatePublicKey: function () {
    var privateKey = this.privateKey;

    return new Promise(function(resolve, reject){
      if (!privateKey) {
        return reject('Impossible to generate a public key: privateKey option has not been defined or is empty.');
      }

      var key = new RSA(privateKey);

      resolve(key.exportKey('pkcs8-public-der'));
    });
  },

  /**
   * Generates a SHA1 package signature.
   *
   * BC BREAK `this.signature` is not stored anymore (since 1.0.0)
   *
   * @param {Buffer} contents
   * @returns {Buffer}
   */
  generateSignature: function (contents) {
    return new Buffer(
      crypto
        .createSign("sha1")
        .update(contents)
        .sign(this.privateKey),
      "binary"
    );
  },

  /**
   *
   * BC BREAK `this.contents` is not stored anymore (since 1.0.0)
   *
   * @returns {Promise}
   */
  loadContents: function () {
    var selfie = this;

    return new Promise(function(resolve, reject){
      var archive = archiver('zip');
      var contents = new Buffer('');

      if (!selfie.loaded) {
	      throw new Error('crx.load needs to be called first in order to prepare the workspace.');
      }

      archive.on('error', reject);

      /*
        TODO: Remove in v4.
        It will be better to resolve an archive object
        rather than fitting everything in memory.

        @see https://github.com/oncletom/crx/issues/61
      */
      archive.on('data', function (buf) {
        contents = Buffer.concat([contents, buf]);
      });

      archive.on('finish', function () {
        resolve(contents);
      });

      archive
        .glob(selfie.src, {
          cwd: selfie.path,
          matchBase: true,
          ignore: ['*.pem', '.git', '*.crx']
        })
        .finalize();
    });
  },

  /**
   * Generates and returns a signed package from extension content.
   *
   * BC BREAK `this.package` is not stored anymore (since 1.0.0)
   *
   * @param {Buffer} signature
   * @param {Buffer} publicKey
   * @param {Buffer} contents
   * @returns {Buffer}
   */
  generatePackage: function (signature, publicKey, contents) {
    var keyLength = publicKey.length;
    var sigLength = signature.length;
    var zipLength = contents.length;
    var length = 16 + keyLength + sigLength + zipLength;

    var crx = new Buffer(length);

    crx.write("Cr24" + new Array(13).join("\x00"), "binary");

    crx[4] = 2;
    crx.writeUInt32LE(keyLength, 8);
    crx.writeUInt32LE(sigLength, 12);

    publicKey.copy(crx, 16);
    signature.copy(crx, 16 + keyLength);
    contents.copy(crx, 16 + keyLength + sigLength);

    return crx;
  },

  /**
   * Generates an appId from the publicKey.
   * Public key has to be set for this to work, otherwise an error is thrown.
   *
   * BC BREAK `this.appId` is not stored anymore (since 1.0.0)
   * BC BREAK introduced `publicKey` parameter as it is not stored any more since 2.0.0
   *
   * @param {Buffer|string} [publicKey] the public key to use to generate the app ID
   * @returns {string}
   */
  generateAppId: function (publicKey) {
    publicKey = publicKey || this.publicKey;
    if (typeof publicKey !== 'string' && !(publicKey instanceof Buffer)) {
      throw new Error('Public key is neither set, nor given');
    }
    return crypto
      .createHash("sha256")
      .update(publicKey)
      .digest("hex")
      .slice(0, 32)
      .replace(/./g, function (x) {
        return (parseInt(x, 16) + 10).toString(26);
      });
  },

  /**
   * Generates an updateXML file from the extension content.
   *
   * BC BREAK `this.updateXML` is not stored anymore (since 1.0.0)
   *
   * @returns {Buffer}
   */
  generateUpdateXML: function () {
    if (!this.codebase) {
      throw new Error("No URL provided for update.xml.");
    }

    return new Buffer(
      "<?xml version='1.0' encoding='UTF-8'?>\n" +
      "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n" +
      "  <app appid='" + (this.appId || this.generateAppId()) + "'>\n" +
      "    <updatecheck codebase='" + this.codebase + "' version='" + this.manifest.version + "' />\n" +
      "  </app>\n" +
      "</gupdate>"
    );
  }
};

module.exports = ChromeExtension;
<|endoftext|>


<commit_before>module.exports = {
    "env": {
        "browser": true,
        "amd": true
    },
    "extends": "eslint:recommended",
    "rules": {
        "accessor-pairs": "error",
        "array-bracket-spacing": [
            "error",
            "never"
        ],
        "array-callback-return": "error",
        "arrow-body-style": "error",
        "arrow-parens": "error",
        "arrow-spacing": "error",
        "block-scoped-var": "error",
        "block-spacing": "error",
        "brace-style": [
            "error",
            "stroustrup"
        ],
        "callback-return": "error",
        "camelcase": "error",
        "comma-spacing": [
            "error",
            {
                "after": true,
                "before": false
            }
        ],
        "comma-style": [
            "error",
            "last"
        ],
        "complexity": "error",
        "computed-property-spacing": [
            "error",
            "never"
        ],
        "consistent-return": "error",
        "consistent-this": "error",
        "curly": "error",
        "default-case": "error",
        "dot-location": "error",
        "dot-notation": "error",
        "eol-last": "error",
        "eqeqeq": "error",
        "func-names": "off",
        "func-style": [
            "error",
            "declaration"
        ],
        "generator-star-spacing": "error",
        "global-require": "error",
        "guard-for-in": "error",
        "handle-callback-err": "error",
        "id-blacklist": "error",
        "id-length": "off",
        "id-match": "error",
        "indent": "error",
        "init-declarations": "off",
        "jsx-quotes": "error",
        "key-spacing": "error",
        "keyword-spacing": "off",
        "linebreak-style": [
            "error",
            "unix"
        ],
        "lines-around-comment": "off",
        "max-depth": "error",
        "max-len": "off",
        "max-nested-callbacks": "error",
        "max-params": "error",
        "max-statements": "off",
        "max-statements-per-line": "error",
        "new-cap": "error",
        "new-parens": "error",
        "newline-after-var": "off",
        "newline-before-return": "off",
        "newline-per-chained-call": "error",
        "no-alert": "error",
        "no-array-constructor": "error",
        "no-bitwise": "error",
        "no-caller": "error",
        "no-catch-shadow": "error",
        "no-confusing-arrow": "error",
        "no-continue": "error",
        "no-div-regex": "error",
        "no-duplicate-imports": "error",
        "no-else-return": "error",
        "no-empty-function": "error",
        "no-eq-null": "error",
        "no-eval": "error",
        "no-extend-native": "error",
        "no-extra-bind": "error",
        "no-extra-label": "error",
        "no-extra-parens": "error",
        "no-floating-decimal": "error",
        "no-implicit-coercion": "error",
        "no-implicit-globals": "error",
        "no-implied-eval": "error",
        "no-inline-comments": "error",
        "no-inner-declarations": [
            "error",
            "functions"
        ],
        "no-invalid-this": "error",
        "no-iterator": "error",
        "no-label-var": "error",
        "no-labels": "error",
        "no-lone-blocks": "error",
        "no-lonely-if": "error",
        "no-loop-func": "off",
        "no-magic-numbers": "off",
        "no-mixed-requires": "error",
        "no-multi-spaces": "error",
        "no-multi-str": "error",
        "no-multiple-empty-lines": "error",
        "no-native-reassign": "error",
        "no-negated-condition": "off",
        "no-nested-ternary": "error",
        "no-new": "error",
        "no-new-func": "error",
        "no-new-object": "error",
        "no-new-require": "error",
        "no-new-wrappers": "error",
        "no-octal-escape": "error",
        "no-param-reassign": [
            "error",
            {
                "props": false
            }
        ],
        "no-path-concat": "error",
        "no-plusplus": [
            "error",
            {
                "allowForLoopAfterthoughts": true
            }
        ],
        "no-process-env": "error",
        "no-process-exit": "error",
        "no-proto": "error",
        "no-restricted-globals": "error",
        "no-restricted-imports": "error",
        "no-restricted-modules": "error",
        "no-restricted-syntax": "error",
        "no-return-assign": "error",
        "no-script-url": "error",
        "no-self-compare": "error",
        "no-sequences": "error",
        "no-shadow": "error",
        "no-shadow-restricted-names": "error",
        "no-spaced-func": "error",
        "no-sync": "error",
        "no-ternary": "error",
        "no-throw-literal": "error",
        "no-trailing-spaces": "error",
        "no-undef-init": "error",
        "no-undefined": "error",
        "no-underscore-dangle": "error",
        "no-unmodified-loop-condition": "error",
        "no-unneeded-ternary": "error",
        "no-unused-expressions": "error",
        "no-use-before-define": "error",
        "no-useless-call": "error",
        "no-useless-concat": "error",
        "no-useless-constructor": "error",
        "no-useless-escape": "error",
        "no-var": "off",
        "no-void": "error",
        "no-warning-comments": "error",
        "no-whitespace-before-property": "error",
        "no-with": "error",
        "object-curly-spacing": "error",
        "object-shorthand": "off",
        "one-var": "off",
        "one-var-declaration-per-line": "off",
        "operator-assignment": "error",
        "operator-linebreak": "error",
        "padded-blocks": "off",
        "prefer-arrow-callback": "off",
        "prefer-const": "error",
        "prefer-reflect": "error",
        "prefer-rest-params": "error",
        "prefer-spread": "error",
        "prefer-template": "off",
        "quote-props": "off",
        "quotes": [
            "error",
            "single"
        ],
        "radix": "error",
        "require-jsdoc": "off",
        "require-yield": "error",
        "semi": "error",
        "semi-spacing": [
            "error",
            {
                "after": true,
                "before": false
            }
        ],
        "sort-imports": "error",
        "sort-vars": "error",
        "space-before-blocks": "error",
        "space-before-function-paren": "off",
        "space-in-parens": "off",
        "space-infix-ops": "error",
        "space-unary-ops": "error",
        "spaced-comment": [
            "error",
            "always"
        ],
        "strict": [
            "error",
            "never"
        ],
        "template-curly-spacing": "error",
        "valid-jsdoc": "off",
        "vars-on-top": "off",
        "wrap-iife": "error",
        "wrap-regex": "error",
        "yield-star-spacing": "error",
        "yoda": [
            "error",
            "never"
        ]
    }
};
<commit_msg>expanding .eslintrc.js<commit_after>module.exports = {
    "env": {
        "browser": true,
        "amd": true
    },
    "extends": "eslint:recommended",
    "rules": {
        "accessor-pairs": "error",
        "array-bracket-spacing": [
            "error",
            "never"
        ],
        "array-callback-return": "error",
        "arrow-body-style": "error",
        "arrow-parens": "error",
        "arrow-spacing": "error",
        "block-scoped-var": "error",
        "block-spacing": "error",
        "brace-style": [
            "error",
            "stroustrup"
        ],
        "callback-return": "error",
        "camelcase": "error",
        "comma-spacing": [
            "error",
            {
                "after": true,
                "before": false
            }
        ],
        "comma-style": [
            "error",
            "last"
        ],
        "complexity": "error",
        "computed-property-spacing": [
            "error",
            "never"
        ],
        "consistent-return": "error",
        "consistent-this": "error",
        "curly": "error",
        "default-case": "error",
        "dot-location": "error",
        "dot-notation": "error",
        "eol-last": "error",
        "eqeqeq": "error",
        "func-names": "off",
        "func-style": [
            "warn",
            "declaration"
        ],
        "generator-star-spacing": "error",
        "global-require": "error",
        "guard-for-in": "error",
        "handle-callback-err": "error",
        "id-blacklist": "error",
        "id-length": "off",
        "id-match": "error",
        "indent": "error",
        "init-declarations": "off",
        "jsx-quotes": "error",
        "key-spacing": "error",
        "keyword-spacing": "off",
        "linebreak-style": [
            "error",
            "unix"
        ],
        "lines-around-comment": "off",
        "max-depth": "error",
        "max-len": "off",
        "max-nested-callbacks": "error",
        "max-params": "error",
        "max-statements": "off",
        "max-statements-per-line": "error",
        "new-cap": "error",
        "new-parens": "error",
        "newline-after-var": "off",
        "newline-before-return": "off",
        "newline-per-chained-call": "error",
        "no-alert": "error",
        "no-array-constructor": "error",
        "no-bitwise": "error",
        "no-caller": "error",
        "no-catch-shadow": "error",
        "no-confusing-arrow": "error",
        "no-continue": "error",
        "no-div-regex": "error",
        "no-duplicate-imports": "error",
        "no-else-return": "error",
        "no-empty-function": "error",
        "no-eq-null": "error",
        "no-eval": "error",
        "no-extend-native": "error",
        "no-extra-bind": "error",
        "no-extra-label": "error",
        "no-extra-parens": "error",
        "no-floating-decimal": "error",
        "no-implicit-coercion": "error",
        "no-implicit-globals": "error",
        "no-implied-eval": "error",
        "no-inline-comments": "error",
        "no-inner-declarations": [
            "error",
            "functions"
        ],
        "no-invalid-this": "error",
        "no-iterator": "error",
        "no-label-var": "error",
        "no-labels": "error",
        "no-lone-blocks": "error",
        "no-lonely-if": "error",
        "no-loop-func": "off",
        "no-magic-numbers": "off",
        "no-mixed-requires": "error",
        "no-multi-spaces": "error",
        "no-multi-str": "error",
        "no-multiple-empty-lines": "error",
        "no-native-reassign": "error",
        "no-negated-condition": "off",
        "no-nested-ternary": "error",
        "no-new": "error",
        "no-new-func": "error",
        "no-new-object": "error",
        "no-new-require": "error",
        "no-new-wrappers": "error",
        "no-octal-escape": "error",
        "no-param-reassign": [
            "error",
            {
                "props": false
            }
        ],
        "no-path-concat": "error",
        "no-plusplus": [
            "error",
            {
                "allowForLoopAfterthoughts": true
            }
        ],
        "no-process-env": "error",
        "no-process-exit": "error",
        "no-proto": "error",
        "no-restricted-globals": "error",
        "no-restricted-imports": "error",
        "no-restricted-modules": "error",
        "no-restricted-syntax": "error",
        "no-return-assign": "error",
        "no-script-url": "error",
        "no-self-compare": "error",
        "no-sequences": "error",
        "no-shadow": "error",
        "no-shadow-restricted-names": "error",
        "no-spaced-func": "error",
        "no-sync": "error",
        "no-ternary": "error",
        "no-throw-literal": "error",
        "no-trailing-spaces": "error",
        "no-undef-init": "error",
        "no-undefined": "error",
        "no-underscore-dangle": "error",
        "no-unmodified-loop-condition": "error",
        "no-unneeded-ternary": "error",
        "no-unused-expressions": "error",
        "no-use-before-define": "error",
        "no-useless-call": "error",
        "no-useless-concat": "error",
        "no-useless-constructor": "error",
        "no-useless-escape": "error",
        "no-var": "off",
        "no-void": "error",
        "no-warning-comments": "error",
        "no-whitespace-before-property": "error",
        "no-with": "error",
        "object-curly-spacing": "error",
        "object-shorthand": "off",
        "one-var": "off",
        "one-var-declaration-per-line": "off",
        "operator-assignment": "error",
        "operator-linebreak": "error",
        "padded-blocks": "off",
        "prefer-arrow-callback": "off",
        "prefer-const": "off",
        "prefer-reflect": "off",
        "prefer-rest-params": "error",
        "prefer-spread": "error",
        "prefer-template": "off",
        "quote-props": "off",
        "quotes": [
            "error",
            "single"
        ],
        "radix": "error",
        "require-jsdoc": "off",
        "require-yield": "error",
        "semi": "error",
        "semi-spacing": [
            "error",
            {
                "after": true,
                "before": false
            }
        ],
        "sort-imports": "off",
        "sort-vars": "off",
        "space-before-blocks": "error",
        "space-before-function-paren": "off",
        "space-in-parens": "off",
        "space-infix-ops": "error",
        "space-unary-ops": "error",
        "spaced-comment": [
            "error",
            "always"
        ],
        "strict": [
            "error",
            "never"
        ],
        "template-curly-spacing": "error",
        "valid-jsdoc": "off",
        "vars-on-top": "off",
        "wrap-iife": "error",
        "wrap-regex": "error",
        "yield-star-spacing": "error",
        "yoda": [
            "error",
            "never",
            {"exceptRange": true}
        ]
    }
};
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  env: { 'browser': true },
  parser: "vue-eslint-parser",
  parserOptions: {
    sourceType: "module",
  },
  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
  extends: [
    'plugin:vue/recommended', 'standard'
  ],
  plugins: [
    'vue',
    'vue-storefront'
  ],
  // add your custom rules here
  rules: {
    /* max attributes-per-line and order-in-components
    ** we should use this later, when eslint-plugin-vue will support auto fixing this
    */
    'vue/max-attributes-per-line': 0,
    'vue/order-in-components': 0,
    'vue/attributes-order': 0,
    // less restricted v-for -> v-if rules
    'vue/no-confusing-v-for-v-if': 0,
    // allow paren-less arrow functions
    'arrow-parens': 0,
    // allow async-await
    'generator-star-spacing': 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    "no-restricted-imports": [2, { "paths": ["lodash"] }]
    "vue-storefront/no-corecomponent-import": "error",
    "vue-storefront/no-corecomponent": "error",
    "vue-storefront/no-corepage-import": "error",
    "vue-storefront/no-corepage": "error"
  }
}
<commit_msg>Comma fix<commit_after>module.exports = {
  root: true,
  env: { 'browser': true },
  parser: "vue-eslint-parser",
  parserOptions: {
    sourceType: "module",
  },
  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
  extends: [
    'plugin:vue/recommended', 'standard'
  ],
  plugins: [
    'vue',
    'vue-storefront'
  ],
  // add your custom rules here
  rules: {
    /* max attributes-per-line and order-in-components
    ** we should use this later, when eslint-plugin-vue will support auto fixing this
    */
    'vue/max-attributes-per-line': 0,
    'vue/order-in-components': 0,
    'vue/attributes-order': 0,
    // less restricted v-for -> v-if rules
    'vue/no-confusing-v-for-v-if': 0,
    // allow paren-less arrow functions
    'arrow-parens': 0,
    // allow async-await
    'generator-star-spacing': 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    "no-restricted-imports": [2, { "paths": ["lodash"] }],
    "vue-storefront/no-corecomponent-import": "error",
    "vue-storefront/no-corecomponent": "error",
    "vue-storefront/no-corepage-import": "error",
    "vue-storefront/no-corepage": "error"
  }
}
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      legacyDecorators: true,
    },
  },
  plugins: ['ember', 'prettier', 'import-helpers'],
  extends: ['eslint:recommended', 'plugin:ember/recommended', 'plugin:prettier/recommended'],
  env: {
    browser: true,
  },
  rules: {
    'prettier/prettier': 'error',

    'ember/no-empty-attrs': 'off',
    'ember/no-get': 'off',
    'ember/require-computed-property-dependencies': 'off',

    'import-helpers/order-imports': [
      'error',
      {
        newlinesBetween: 'always',
        groups: [
          // Node.js built-in modules
          '/^(assert|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|http2|https|inspector|module|net|os|path|perf_hooks|process|punycode|querystring|readline|repl|stream|string_decoder|timers|tls|trace_events|tty|url|util|v8|vm|zli)/',
          // Testing modules
          ['/^(qunit|ember-qunit|@ember/test-helpers|ember-exam|htmlbars-inline-precompile)$/', '/^ember-exam\\//'],
          // Ember.js modules
          ['/^@(ember|ember-data|glimmer)\\//', '/^(ember|ember-data|rsvp)$/', '/^ember-data\\//'],
          ['module'],
          [`/^${require('./package.json').name}\\//`],
          ['parent', 'sibling', 'index'],
        ],
        alphabetize: { order: 'asc', ignoreCase: true },
      },
    ],
  },
  overrides: [
    // node files
    {
      files: [
        '.eslintrc.js',
        '.template-lintrc.js',
        'ember-cli-build.js',
        'fastboot.js',
        'testem.js',
        'blueprints/*/index.js',
        'config/**/*.js',
        'lib/*/index.js',
        'server/**/*.js',
      ],
      parserOptions: {
        sourceType: 'script',
        ecmaVersion: 2018,
      },
      env: {
        browser: false,
        node: true,
      },
    },
  ],
};
<commit_msg>ESLint: Disable `getter-return` rule<commit_after>module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      legacyDecorators: true,
    },
  },
  plugins: ['ember', 'prettier', 'import-helpers'],
  extends: ['eslint:recommended', 'plugin:ember/recommended', 'plugin:prettier/recommended'],
  env: {
    browser: true,
  },
  rules: {
    // it's fine to use `return` without a value and rely on the implicit `undefined` return value
    'getter-return': 'off',

    'prettier/prettier': 'error',

    'ember/no-empty-attrs': 'off',
    'ember/no-get': 'off',
    'ember/require-computed-property-dependencies': 'off',

    'import-helpers/order-imports': [
      'error',
      {
        newlinesBetween: 'always',
        groups: [
          // Node.js built-in modules
          '/^(assert|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|http2|https|inspector|module|net|os|path|perf_hooks|process|punycode|querystring|readline|repl|stream|string_decoder|timers|tls|trace_events|tty|url|util|v8|vm|zli)/',
          // Testing modules
          ['/^(qunit|ember-qunit|@ember/test-helpers|ember-exam|htmlbars-inline-precompile)$/', '/^ember-exam\\//'],
          // Ember.js modules
          ['/^@(ember|ember-data|glimmer)\\//', '/^(ember|ember-data|rsvp)$/', '/^ember-data\\//'],
          ['module'],
          [`/^${require('./package.json').name}\\//`],
          ['parent', 'sibling', 'index'],
        ],
        alphabetize: { order: 'asc', ignoreCase: true },
      },
    ],
  },
  overrides: [
    // node files
    {
      files: [
        '.eslintrc.js',
        '.template-lintrc.js',
        'ember-cli-build.js',
        'fastboot.js',
        'testem.js',
        'blueprints/*/index.js',
        'config/**/*.js',
        'lib/*/index.js',
        'server/**/*.js',
      ],
      parserOptions: {
        sourceType: 'script',
        ecmaVersion: 2018,
      },
      env: {
        browser: false,
        node: true,
      },
    },
  ],
};
<|endoftext|>


<commit_before>module.exports = {
    env: {
        es6: true,
        node: true,
    },
    plugins: ['standard', 'promise'],
    extends: 'eslint:recommended',
    globals: {
        module: false,
        describe: false,
        it: false,
        next: false,
        before: false,
        rrequire: true,
        mrequire: true,
        wrequire: true,
    },
    parser: 'babel-eslint',
    parserOptions: {
        ecmaVerions: 2017,
    },
    rules: {
        indent: [
            'error',
            4,
            {
                SwitchCase: 1,
            },
        ],
        'linebreak-style': ['error', 'unix'],
        quotes: ['error', 'single'],
        semi: ['error', 'never'],
        'max-len': [
            'error',
            110,
            {
                ignoreStrings: true,
                ignoreComments: true,
                ignoreTemplateLiterals: true,
                ignoreRegExpLiterals: true,
            },
        ],
        'space-before-function-paren': 0,
        'no-unused-vars': [
            'warn',
            {
                varsIgnorePattern: 'services',
            },
        ],
        'array-bracket-newline': [
            'error',
            {
                multiline: true,
                minItems: 1,
            },
        ],
        'array-element-newline': [
            'error',
            {
                minItems: 1,
            },
        ],
        'object-curly-spacing': ['error', 'always'],
        'no-console': 'warn',
        'no-var': 'error',
        'comma-dangle': ['error', 'always-multiline'],
        'object-property-newline': 2,
        'object-curly-newline': ['error', { multiline: true }],
        'arrow-parens': ['error', 'as-needed'],
    },
}
<commit_msg>Add src_path variable to linter<commit_after>module.exports = {
    env: {
        es6: true,
        node: true,
    },
    plugins: ['standard', 'promise'],
    extends: 'eslint:recommended',
    globals: {
        module: false,
        describe: false,
        it: false,
        next: false,
        before: false,
        rrequire: true,
        mrequire: true,
        wrequire: true,
        src_path: true,
    },
    parser: 'babel-eslint',
    parserOptions: {
        ecmaVerions: 2017,
    },
    rules: {
        indent: [
            'error',
            4,
            {
                SwitchCase: 1,
            },
        ],
        'linebreak-style': ['error', 'unix'],
        quotes: ['error', 'single'],
        semi: ['error', 'never'],
        'max-len': [
            'error',
            110,
            {
                ignoreStrings: true,
                ignoreComments: true,
                ignoreTemplateLiterals: true,
                ignoreRegExpLiterals: true,
            },
        ],
        'space-before-function-paren': 0,
        'no-unused-vars': [
            'warn',
            {
                varsIgnorePattern: 'services',
            },
        ],
        'array-bracket-newline': [
            'error',
            {
                multiline: true,
                minItems: 1,
            },
        ],
        'array-element-newline': [
            'error',
            {
                minItems: 1,
            },
        ],
        'object-curly-spacing': ['error', 'always'],
        'no-console': 'warn',
        'no-var': 'error',
        'comma-dangle': ['error', 'always-multiline'],
        'object-property-newline': 2,
        'object-curly-newline': ['error', { multiline: true }],
        'arrow-parens': ['error', 'as-needed'],
    },
}
<|endoftext|>


<commit_before>module.exports = {
    "env": {
        "browser": true,
        "es6": true
    },
    "parser": "babel-eslint",
    "plugins": [
      "flowtype",
      "react"
    ],
    "extends": [
      "eslint:recommended",
      "plugin:react/recommended"
    ],
    "parserOptions": {
        "sourceType": "module"
    },
    "rules": {
        "flowtype/define-flow-type": 1,
        "flowtype/use-flow-type": 1,
        "no-case-declarations": 0,
        "indent": [
            "error",
            2,
            { "SwitchCase": 1 }
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "never"
        ]
    }
};
<commit_msg>style(eslint): Modify eslint settings<commit_after>module.exports = {
  parser: "typescript-eslint-parser",
  plugins: ["prettier", "typescript"],
  extends: ["eslint:recommended"],
  rules: {
    "no-unused-vars": "off",
    "typescript/no-unused-vars": ["error"],
    "prefer-arrow-callback": ["error"],
  },
};
<|endoftext|>


<commit_before>const path = require('path');

// get the path of the js-sdk so we can extend the config
// eslint supports loading extended configs by module,
// but only if they come from a module that starts with eslint-config-
// So we load the filename directly (and it could be in node_modules/
// or or ../node_modules/ etc)
const matrixJsSdkPath = path.dirname(require.resolve('matrix-js-sdk'));

module.exports = {
    parser: "babel-eslint",
    extends: [matrixJsSdkPath + "/.eslintrc.js"],
    plugins: [
      "react",
      "flowtype",
    ],
    env: {
        es6: true,
    },
    parserOptions: {
        ecmaFeatures: {
            jsx: true,
        }
    },
    rules: {
        /** react **/
        // This just uses the react plugin to help eslint known when
        // variables have been used in JSX
        "react/jsx-uses-vars": "error",

        // bind or arrow function in props causes performance issues
        "react/jsx-no-bind": ["error", {
            "ignoreRefs": true,
        }],
        "react/jsx-key": ["error"],

        /** flowtype **/
        "flowtype/require-parameter-type": ["warn", {
            "excludeArrowFunctions": true,
        }],
        "flowtype/define-flow-type": "warn",
        "flowtype/require-return-type": ["warn",
            "always",
            {
              "annotateUndefined": "never",
              "excludeArrowFunctions": true,
            }
        ],
        "flowtype/space-after-type-colon": ["warn", "always"],
        "flowtype/space-before-type-colon": ["warn", "never"],

        /*
         * things that are errors in the js-sdk config that the current
         * code does not adhere to, turned down to warn
         */
        "max-len": ["warn", {
            // apparently people believe the length limit shouldn't apply
            // to JSX.
            ignorePattern: '^\\s*<',
        }],
        "valid-jsdoc": ["warn"],
        "new-cap": ["warn"],
        "key-spacing": ["warn"],
        "arrow-parens": ["warn"],
        "prefer-const": ["warn"],

        // crashes currently: https://github.com/eslint/eslint/issues/6274
        "generator-star-spacing": "off",
    },
    settings: {
        flowtype: {
            onlyFilesWithFlowAnnotation: true
        },
    },
};
<commit_msg>Reinstate max-len lint configs<commit_after>const path = require('path');

// get the path of the js-sdk so we can extend the config
// eslint supports loading extended configs by module,
// but only if they come from a module that starts with eslint-config-
// So we load the filename directly (and it could be in node_modules/
// or or ../node_modules/ etc)
const matrixJsSdkPath = path.dirname(require.resolve('matrix-js-sdk'));

module.exports = {
    parser: "babel-eslint",
    extends: [matrixJsSdkPath + "/.eslintrc.js"],
    plugins: [
      "react",
      "flowtype",
    ],
    env: {
        es6: true,
    },
    parserOptions: {
        ecmaFeatures: {
            jsx: true,
        }
    },
    rules: {
        /** react **/
        // This just uses the react plugin to help eslint known when
        // variables have been used in JSX
        "react/jsx-uses-vars": "error",

        // bind or arrow function in props causes performance issues
        "react/jsx-no-bind": ["error", {
            "ignoreRefs": true,
        }],
        "react/jsx-key": ["error"],

        /** flowtype **/
        "flowtype/require-parameter-type": ["warn", {
            "excludeArrowFunctions": true,
        }],
        "flowtype/define-flow-type": "warn",
        "flowtype/require-return-type": ["warn",
            "always",
            {
              "annotateUndefined": "never",
              "excludeArrowFunctions": true,
            }
        ],
        "flowtype/space-after-type-colon": ["warn", "always"],
        "flowtype/space-before-type-colon": ["warn", "never"],

        /*
         * things that are errors in the js-sdk config that the current
         * code does not adhere to, turned down to warn
         */
        "max-len": ["warn", {
            // apparently people believe the length limit shouldn't apply
            // to JSX.
            ignorePattern: '^\\s*<',
            ignoreComments: true,
            code: 90,
        }],
        "valid-jsdoc": ["warn"],
        "new-cap": ["warn"],
        "key-spacing": ["warn"],
        "arrow-parens": ["warn"],
        "prefer-const": ["warn"],

        // crashes currently: https://github.com/eslint/eslint/issues/6274
        "generator-star-spacing": "off",
    },
    settings: {
        flowtype: {
            onlyFilesWithFlowAnnotation: true
        },
    },
};
<|endoftext|>