<commit_before>
const self = {};

const methods = [ 'get', 'put', 'post', 'head', 'patch', 'delete', 'options', 'connect' ];
methods.forEach(name => () self[name] = method.bind(self, name));

self.get = method.bind(self, name);
self.put = method.bind(self, name);
self.post = method.bind(self, name);
self.head = method.bind(self, name);
self.patch = method.bind(self, name);
self.delete = method.bind(self, name);
self.options = method.bind(self, name);
self.connect = method.bind(self, name);

self.mime = {
    xml: 'text/xml; charset=utf-8',
    html: 'text/html; charset=utf-8',
    text: 'text/plain; charset=utf-8',
    json: 'application/json; charset=utf-8',
    js: 'application/javascript; charset=utf-8'
};

self.types = [ 'json', 'text', 'blob', 'formData', 'arrayBuffer' ];

self.setup = async function (options = {}) {
    this.path = options.path;
    this.method = options.method;
    this.origin = options.origin;
    this.request = options.request;
    this.headers = options.headers;
    this.response = options.response;
    this.acceptType = options.acceptType;
    this.credentials = options.credentials;
    this.contentType = options.contentType;
    this.responseType = options.responseType;
};

self.method = async function (method, data) {
    data = typeof data === 'string' ? { url: data } : data;
    data.method = method;
    return this.fetch(data);
};

self.define = function (target, name, value) {
    const enumerable = true;
    Object.defineProperty(target, name, { enumerable, value });
};

self.serialize = async function (data) {
    let query = '';

    for (const name in data) {
        query = query.length > 0 ? query + '&' : query;
        query = query + encodeURIComponent(name) + '=' + encodeURIComponent(data[name]);
    }

    return query;
};

self.fetch = async function (options = {}) {
    const context = { ...options };

    context.path = context.path || this.path;
    context.origin = context.origin || this.origin;

    if (context.path && typeof context.path === 'string' && context.path.charAt(0) === '/') context.path = context.path.slice(1);
    if (context.origin && typeof context.origin === 'string' && context.origin.charAt(context.origin.length-1) === '/') context.origin = context.origin.slice(0, -1);
    if (context.path && context.origin && !context.url) context.url = context.origin + '/' + context.path;

    if (!context.method) throw new Error('Oxe.fetcher - requires method option');
    if (!context.url) throw new Error('Oxe.fetcher - requires url or origin and path option');

    context.aborted = false;
    context.signal = context.signal || this.signal;
    context.integrity = context.integrity || this.integrity;
    context.keepAlive = context.keepAlive || this.keepAlive;
    context.headers = context.headers || this.headers || {};
    context.acceptType = context.acceptType || this.acceptType;
    context.contentType = context.contentType || this.contentType;
    context.method = (context.method || this.method).toUpperCase();
    context.responseType = context.responseType || this.responseType;

    // omit, same-origin, or include
    context.credentials = context.credentials || this.credentials;

    // cors, no-cors, or same-origin
    context.mode = context.mode || this.mode;

    // default, no-store, reload, no-cache, force-cache, or only-if-cached
    context.cahce = context.cahce || this.cache;

    // follow, error, or manual
    context.redirect = context.redirect || this.redirect;

    // no-referrer, client, or a URL
    context.referrer = context.referrer || this.referrer;

    // no-referrer, no-referrer-when-downgrade, origin, origin-when-cross-origin, unsafe-url
    context.referrerPolicy = context.referrerPolicy || this.referrerPolicy;

    if (context.contentType) {
        switch (context.contentType) {
        case 'js': context.headers['Content-Type'] = this.mime.js; break;
        case 'xml': context.headers['Content-Type'] = this.mime.xml; break;
        case 'html': context.headers['Content-Type'] = this.mime.html; break;
        case 'json': context.headers['Content-Type'] = this.mime.json; break;
        default: context.headers['Content-Type'] = context.contentType;
        }
    }

    if (context.acceptType) {
        switch (context.acceptType) {
        case 'js': context.headers['Accept'] = this.mime.js; break;
        case 'xml': context.headers['Accept'] = this.mime.xml; break;
        case 'html': context.headers['Accept'] = this.mime.html; break;
        case 'json': context.headers['Accept'] = this.mime.json; break;
        default: context.headers['Accept'] = context.acceptType;
        }
    }

    define(context, 'abort', () => {
        context.aborted = true;
        return context;
    });

    if (typeof this.request === 'function') {
        await this.request(context);
    }

    if (context.aborted) {
        return;
    }

    if (context.body) {
        if (context.method === 'GET') {
            context.url = context.url + '?' + await self.serialize(context.body);
        } else if (context.contentType === 'json') {
            context.body = JSON.stringify(context.body);
        }
    }

    const result = await window.fetch(context.url, context);

    self.define(context, 'result', result);
    self.define(context, 'code', result.status);
    // self.define(context, 'headers', result.headers);
    // self.define(context, 'message', result.statusText);

    if (!context.responseType) {
        context.body = result.body;
    } else {
        const responseType = context.responseType === 'buffer' ? 'arrayBuffer' : context.responseType || '';
        const contentType = result.headers.get('content-type') || result.headers.get('Content-Type') || '';

        let type;
        if (responseType === 'json' && contentType.indexOf('json') !== -1) {
            type = 'json';
        } else {
            type = responseType || 'text';
        }

        if (this.types.indexOf(type) === -1) {
            throw new Error('Oxe.fetch - invalid responseType value');
        }

        context.body = await result[type]();
    }

    if (typeof this.response === 'function') {
        await this.response(context);
    }

    if (context.aborted) {
        return;
    }

    return context;
};

// const methods = [ 'get', 'put', 'post', 'head', 'patch', 'delete', 'options', 'connect' ];
// methods.forEach(name => () self[name] = method.bind(self, name));

export default Object.freeze(self);
<commit_msg>optimizations<commit_after>export default Object.freeze({

    option: {},
    
    types: Object.freeze([
        'json',
        'text',
        'blob',
        'formData',
        'arrayBuffer'
    ]),

    mime: Object.freeze({
        xml: 'text/xml; charset=utf-8',
        html: 'text/html; charset=utf-8',
        text: 'text/plain; charset=utf-8',
        json: 'application/json; charset=utf-8',
        js: 'application/javascript; charset=utf-8'
    }),

    async setup (option = {}) {
        this.option.path = option.path;
        this.option.method = option.method;
        this.option.origin = option.origin;
        this.option.request = option.request;
        this.option.headers = option.headers;
        this.option.response = option.response;
        this.option.acceptType = option.acceptType;
        this.option.credentials = option.credentials;
        this.option.contentType = option.contentType;
        this.option.responseType = option.responseType;
    },

    async method (method, data) {
        data = typeof data === 'string' ? { url: data } : data;
        data.method = method;
        return this.fetch(data);
    },

    async get () {
        return this.method('get', ...arguments);
    },
    
    async put () {
        return this.method('put', ...arguments);
    },
    
    async post () {
        return this.method('post', ...arguments);
    },
    
    async head () {
        return this.method('head', ...arguments);
    },
    
    async patch () {
        return this.method('patch', ...arguments);
    },
    
    async delete () {
        return this.method('delete', ...arguments);
    },
    
    async options () {
        return this.method('options', ...arguments);
    },
    
    async connect () {
        return this.method('connect', ...arguments);
    },

    async serialize (data) {
        let query = '';

        for (const name in data) {
            query = query.length > 0 ? query + '&' : query;
            query = query + encodeURIComponent(name) + '=' + encodeURIComponent(data[name]);
        }

        return query;
    },

    async fetch (data = {}) {
        const { option } = this;
        const context = { ...option, ...data };

        if (context.path && typeof context.path === 'string' && context.path.charAt(0) === '/') context.path = context.path.slice(1);
        if (context.origin && typeof context.origin === 'string' && context.origin.charAt(context.origin.length-1) === '/') context.origin = context.origin.slice(0, -1);
        if (context.path && context.origin && !context.url) context.url = context.origin + '/' + context.path;

        if (!context.method) throw new Error('Oxe.fetcher - requires method option');
        if (!context.url) throw new Error('Oxe.fetcher - requires url or origin and path option');

        context.aborted = false;
        context.headers = context.headers || {};
        context.method = context.method.toUpperCase();

        Object.defineProperty(context, 'abort', {
            enumerable: true,
            value () { context.aborted = true; return context; }
        });

        if (context.contentType) {
            switch (context.contentType) {
            case 'js': context.headers['Content-Type'] = this.mime.js; break;
            case 'xml': context.headers['Content-Type'] = this.mime.xml; break;
            case 'html': context.headers['Content-Type'] = this.mime.html; break;
            case 'json': context.headers['Content-Type'] = this.mime.json; break;
            default: context.headers['Content-Type'] = context.contentType;
            }
        }

        if (context.acceptType) {
            switch (context.acceptType) {
            case 'js': context.headers['Accept'] = this.mime.js; break;
            case 'xml': context.headers['Accept'] = this.mime.xml; break;
            case 'html': context.headers['Accept'] = this.mime.html; break;
            case 'json': context.headers['Accept'] = this.mime.json; break;
            default: context.headers['Accept'] = context.acceptType;
            }
        }

        if (typeof option.request === 'function') await option.request(context);
        if (context.aborted) return;

        if (context.body) {
            if (context.method === 'GET') {
                context.url = context.url + '?' + await this.serialize(context.body);
            } else if (context.contentType === 'json') {
                context.body = JSON.stringify(context.body);
            }
        }

        const result = await window.fetch(context.url, context);

        Object.defineProperties(context, {
            result: { enumerable: true, value: result },
            code: { enumerable: true, value: result.status }
            // headers: { enumerable: true, value: result.headers }
            // message: { enumerable: true, value: result.statusText }
        });

        if (!context.responseType) {
            context.body = result.body;
        } else {
            const responseType = context.responseType === 'buffer' ? 'arrayBuffer' : context.responseType || '';
            const contentType = result.headers.get('content-type') || result.headers.get('Content-Type') || '';

            let type;
            if (responseType === 'json' && contentType.indexOf('json') !== -1) {
                type = 'json';
            } else {
                type = responseType || 'text';
            }

            if (this.types.indexOf(type) === -1) {
                throw new Error('Oxe.fetch - invalid responseType value');
            }

            context.body = await result[type]();
        }

        if (typeof option.response === 'function') await option.response(context);
        if (context.aborted) return;

        return context;
    }

});
{'fraction_non_alphanumeric': 0.1566647667128084, 'fraction_numerical': 0.0021170914420649786, 'mean_word_length': 2.4529097554118637, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 12}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1403410', 'n_tokens_mistral': 3585, 'n_tokens_neox': 3519, 'n_words': 787}