<commit_before>'use strict';

class Async {
    static isPromise(obj) {
        return obj != null && Promise.prototype === obj.__proto__;
    }

    static call(callback, ...args) {
        if(typeof callback !== 'function') {
            throw new Error('Invalid parameter passed, expecting a function type');
        }

        let complete = false,
            id = setTimeout(() => {
                callback.apply(this, args);
                complete = true;
        }, 0);

        return () => {
            if(!complete) {
                clearTimeout(id);
                complete = true;
                return true;
            }
            return false;
        };
    }

    static defer(...callbacks) {
        return new Promise((resolve, reject) => {
            let count = 0,
                length = callbacks.length,
                data = new Array(callbacks.length);

            if(length) {
                function checkResolve() {
                    if(++count === length) {
                        resolve(data);
                    }
                }

                for(let i = 0; i < length; i++) {
                    let _i = i;

                    if(Async.isPromise(callbacks[i])) {
                        callbacks[i].then((results) => {
                            data[_i] = results;
                            checkResolve();
                        }).catch(reject);
                    }
                    else if(typeof callbacks[i] === 'function') {
                        new Promise((resolve, reject) => {
                            try {
                                callbacks[i]((results) => {
                                    data[_i] = results;
                                    checkResolve();
                                });
                            }
                            catch(ex) {
                                reject(ex);
                            }
                        }).catch(reject);
                    }
                    else {
                        reject(new Error(`Invalid object with the type ${typeof callbacks[i]} was passed`));
                    }
                }
            }
            else {
                resolve(data);
            }
        });
    }
}

module.exports = Async;<commit_msg>Added until and chain async functions<commit_after>'use strict';

const asyncFunctionConstructor = Object.getPrototypeOf(async function(){}).constructor;

class Async {
    static isPromise(obj) {
        return obj != null && Promise.prototype === obj.__proto__;
    }

    static isAsyncFunction(obj) {
        return obj != null && Object.getPrototypeOf(obj).constructor === asyncFunctionConstructor;
    }

    static call(callback, ...args) {
        if(typeof callback !== 'function') {
            throw new Error('Invalid parameter passed, expecting a function type');
        }

        let complete = false,
            id = setTimeout(() => {
                callback.apply(this, args);
                complete = true;
        }, 0);

        return () => {
            if(!complete) {
                clearTimeout(id);
                complete = true;
                return true;
            }
            return false;
        };
    }

    static async defer(...callbacks) {
        let length = callbacks.length,
            promises = new Array(length),
            i;
        
        for(i = 0; i < length; i++) {
            if(Async.isPromise(callbacks[i])) {
                promises[i] = callbacks[i];
            }
            else if(typeof callbacks[i] === 'function') {
                promises[i] = new Promise((resolve) => {
                    callbacks[i](resolve);
                });
            }
            else {
                throw new Error(`Invalid object with the type ${typeof callbacks[i]} was passed`);
            }
        }

        let data = new Array(length);

        for(i = 0; i < length; i++) {
            data[i] = await promises[i];
        }
        
        return data;
    }

    static async chain(...callbacks) {
        let length = callbacks.length,
            data = new Array(length);

        for(let i = 0; i < length; i++) {
            if(Async.isPromise(callbacks[i])) {
                data[i] = await callbacks[i];
            }
            else if (typeof callbacks[i] === 'function') {
                data[i] = await new Promise((resolve) => {
                    callbacks[i](resolve);
                });
            }
            else {
                throw new Error(`Invalid object with the type ${typeof callbacks[i]} was passed`);
            }
        }

        return data;
    }

    static until(callback) {
        let p = callback;

        if(!Async.isPromise(callback)) {
            if(typeof callback === 'function') {
                p = new Promise((resolve) => {
                    callback(resolve);
                });
            }
            else {
                throw new Error(`Invalid object with the type ${typeof callbacks[i]} was passed`);
            }
        }

        let resolvedMethod;

        return async (...args) => {
            if(!resolvedMethod) {
                resolvedMethod = await p;

                if(typeof resolvedMethod !== 'function') {
                    throw new Error(`Invalid object with the type ${typeof resolvedMethod} was resolved`);
                }
            }

            let ret = null;

            if(!Async.isPromise(resolvedMethod)) {
                if(!Async.isAsyncFunction(resolvedMethod)) {
                    ret = await resolvedMethod.apply(this, args);
                }
                else {
                    ret = await new Promise((resolve) => {
                        resolve(resolvedMethod.apply(this, args));
                    });
                }
            }

            return ret;
        };
    }
}

module.exports = Async;
{'fraction_non_alphanumeric': 0.11247684795420104, 'fraction_numerical': 0.00117864960431049, 'mean_word_length': 1.1011673151750974, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '711003', 'n_tokens_mistral': 1454, 'n_tokens_neox': 1368, 'n_words': 333}