<commit_before>var Rho = Rho || (function ($) {
    'use strict';

    // === API configuration ========================================================

    var thisFileName = 'rhoapi.js';

    var RHO_ID_PARAM = '__rhoID';

    var API_CONTROLLER_URL = '/system/js_api_entrypoint';
    var API_CALLBACK_BASE_URL = '/system/js_api_entrypoint';

    // === Private parts ============================================================

    var idCount = 0;
    var pendingCallbacks = {};

    function defaultEmptyCallback() {}

    function nextId(tag) {
        if ('undefined' == typeof tag || !tag)
            tag = RHO_ID_PARAM;

        return (tag + idCount++);
    }

    function prepareCallback(callback, /*opt*/ isPersistent, /*opt*/ id) {
        if ('string' == typeof callback)
            return callback;

        if ('function' != typeof callback)
            callback = defaultEmptyCallback;

        if ('undefined' == typeof id || !id)
            id = nextId();

        pendingCallbacks[id] = {
            id: id,
            callback: callback,
            isPersistent: ('undefined' != typeof isPersistent) && isPersistent
        };
        // store options for pending callback
        return API_CALLBACK_BASE_URL+id;
    }

    function jsValue(result) {
        var value = null;

        switch(result['type']) {
            case 'instance':
                if (result['class']) {
                    var ids = result.value.split(' ');
                    if (1 == ids.length) {
                        value = objectForClass(result['class'], ids[0]);
                    } else {
                        value = [];
                        for (var i=0; i<ids.length; i++)
                            value.push(objectForClass(result['class'], ids[i]));
                    }
                }
                break;
            case 'default':
                if (result['class']) {
                    value = defaultObjectForClass(result['class'], result.value);
                }
                break;
            default:
                value = result.value;
        }
        return value;
    }

    function namesToProps(names) {
        var propHash = {};
        if ("string" == typeof names) {
            names = names.split(/[\s\,]/);
        }
        if (names instanceof Array) {
            for (var i=0; i<names.length; i++) {
                propHash[names[i]] = null;
            }
        } else if (names instanceof Object) {
            propHash = names;
        }
    }

    var reqIdCount = 0;
    function commonReq(params) {

        var valueCallback = null;
        if ("number" == typeof params.valueCallbackIndex) {
            if (params.valueCallbackIndex < params.args.length-1)
                throw 'Value callback should be a last passed argument!';

            valueCallback = params.args.pop();

            if (valueCallback && "function" != typeof valueCallback)
                throw 'Value callback should be a function!';
        }

        var cmd = { 'module': params.module, 'method': params.method, 'params': params.args };

        if ("number" == typeof params.callbackIndex) {
            cmd['callback_index'] = params.callbackIndex;
            cmd['args'][params.callbackIndex] = prepareCallback(params.args[params.callbackIndex]);
        }
        cmd['jsonrpc'] = '2.0';
        cmd['id'] = reqIdCount++;

        var cmdText = $.toJSON(cmd);
        console.log(cmdText);

        var result = null;
        var deferred =  new $.Deferred(function(dfr) {
            $.ajax({
                async: (null != valueCallback),
                type: 'post',
                url: API_CONTROLLER_URL,
                data: cmdText,
                dataType: 'json',
                headers:{'Accept':'text/plain'}
            }).done(function (data) {
                result = jsValue(data['result']);
                if (valueCallback) {
                    dfr.resolve(result);
                    valueCallback(result);
                }
            }).fail(function (xhr, status, message) {
                var errObj = null;
                try {
                    errObj = $.evalJSON(xhr.responseText);
                    message = errObj.error.message;
                } catch (ex) {};
                result = errObj.error;
                if (valueCallback) {
                    dfr.reject(message, result);
                    valueCallback(result);
                }
            });
        }).promise();

        return (null != valueCallback) ? deferred : result;
    }

    function apiReqFor(module) {
        return function(params) {
            params.args = Array.prototype.slice.call(params.args);
            if ('getProperties' == params.method && 0 < params.args.length) {
                params.args[0] = namesToProps(params.args[0]);
            }
            params.method = module +'.'+ params.method;
            return commonReq(params);
        };
    }<commit_msg>Common API JS error handling fix<commit_after>var Rho = Rho || (function ($) {
    'use strict';

    // === API configuration ========================================================

    var thisFileName = 'rhoapi.js';

    var RHO_ID_PARAM = '__rhoID';
    var RHO_CLASS_PARAM = '__rhoClass';

    var API_CONTROLLER_URL = '/system/js_api_entrypoint';
    var API_CALLBACK_BASE_URL = '/system/js_api_entrypoint';

    // === Private parts ============================================================

    var idCount = 0;
    var pendingCallbacks = {};

    function defaultEmptyCallback() {}

    function nextId(tag) {
        if ('undefined' == typeof tag || !tag)
            tag = RHO_ID_PARAM;

        return (tag + idCount++);
    }

    function prepareCallback(callback, /*opt*/ isPersistent, /*opt*/ id) {
        if ('string' == typeof callback)
            return callback;

        if ('function' != typeof callback)
            callback = defaultEmptyCallback;

        if ('undefined' == typeof id || !id)
            id = nextId();

        pendingCallbacks[id] = {
            id: id,
            callback: callback,
            isPersistent: ('undefined' != typeof isPersistent) && isPersistent
        };
        // store options for pending callback
        return API_CALLBACK_BASE_URL + id;
    }

    function scanForInstances(value) {
        for (var prop in value) {
            if (!value.hasOwnProperty(prop)) continue;
            if ('object' == typeof value[prop]) {
                value[prop] = createInstance(value[prop]);
            }
        }

        return value;
    }

    function createInstance(value) {
        if ('object' == typeof value) {
            if (value[RHO_ID_PARAM] && value[RHO_CLASS_PARAM]) {
                return objectForClass(value[RHO_CLASS_PARAM], value[RHO_ID_PARAM]);
            } else {
                return scanForInstances(value);
            }
        }
        return value;
    }

    function jsValue(result) {

        if ('undefined' == typeof result)
            throw 'Invalid API JSON response';

        if (null == result || 'object' != typeof result)
            return result;

        var value = $.extend({}, result);

        return scanForInstances(value);
    }

    function namesToProps(names) {
        var propHash = {};
        if ("string" == typeof names) {
            names = names.split(/[\s\,]/);
        }
        if (names instanceof Array) {
            for (var i=0; i<names.length; i++) {
                propHash[names[i]] = null;
            }
        } else if (names instanceof Object) {
            propHash = names;
        }
    }

    var reqIdCount = 0;
    function commonReq(params) {

        var valueCallback = null;
        if ("number" == typeof params.valueCallbackIndex) {
            if (params.valueCallbackIndex < params.args.length-1)
                throw 'Value callback should be a last passed argument!';

            if (params.valueCallbackIndex == params.args.length-1)
                valueCallback = params.args.pop();

            if (valueCallback && "function" != typeof valueCallback)
                throw 'Value callback should be a function!';
        }

        var cmd = { 'method': params.method, 'params': params.args };

        if ("number" == typeof params.callbackIndex) {
            cmd['callback_index'] = params.callbackIndex;
            cmd['args'][params.callbackIndex] = prepareCallback(params.args[params.callbackIndex]);
        }

        cmd[RHO_CLASS_PARAM] = params.module;
        cmd[RHO_ID_PARAM] = params.instanceId || null;
        cmd['jsonrpc'] = '2.0';
        cmd['id'] = reqIdCount++;

        var cmdText = $.toJSON(cmd);
        console.log(cmdText);

        var result = null;
        var deferred =  new $.Deferred(function(dfr) {
            function handleError(errObject) {
                dfr.reject(errObject.message, errObject.code);
                throw errObject.message;
            }

            $.ajax({
                async: (null != valueCallback),
                type: 'post',
                url: API_CONTROLLER_URL,
                data: cmdText,
                dataType: 'json',
                headers:{'Accept':'text/plain'}
            }).done(function (data) {
                if (data['error']) {
                    handleError(data['error']);
                } else {
                    result = jsValue(data['result']);
                    dfr.resolve(result);
                    if (valueCallback) {
                        valueCallback(result);
                    }
                }
            }).fail(function (xhr, status, message) {
                handleError({message: message, code: xhr.statusCode()});
            });
        }).promise();

        return (null != valueCallback) ? deferred : result;
    }

    function apiReqFor(module) {
        return function(params) {
            params.args = Array.prototype.slice.call(params.args);
            if ('getProperties' == params.method && 0 < params.args.length) {
                params.args[0] = namesToProps(params.args[0]);
            }
            params.module = module;
            params.method = params.method;
            return commonReq(params);
        };
    }
{'fraction_non_alphanumeric': 0.14287108421977163, 'fraction_numerical': 0.002146969844832634, 'mean_word_length': 1.656298600311042, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '2222321', 'n_tokens_mistral': 2751, 'n_tokens_neox': 2598, 'n_words': 607}