<commit_before>/*
 * Copyright (c) 2015-2017 CoNWeT Lab., Universidad Politécnica de Madrid
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* global NGSI, StyledElements */

(function (se, mp) {

    "use strict";

    var NGSITypeBrowser = function NGSITypeBrowser() {

        /* Context */
        mp.widget.context.registerCallback(function (newValues) {
            if (this.layout && ("heightInPixels" in newValues || "widthInPixels" in newValues)) {
                this.layout.repaint();
            }
        }.bind(this));

        /* Preferences */
        mp.prefs.registerCallback(function (newValues) {
            if ('ngsi_server' in newValues || 'use_user_fiware_token' in newValues || 'use_owner_credentials' in newValues || 'ngsi_tenant' in newValues || 'ngsi_service_path' in newValues) {
                this.updateNGSIConnection();
            }

            this.ngsi_source.goToFirst();
        }.bind(this));

        this.layout = null;
        this.table = null;
    };

    NGSITypeBrowser.prototype.init = function init() {
        createNGSISource.call(this);
        this.updateNGSIConnection();

        this.layout = new se.VerticalLayout();
        createTable.call(this);

        this.layout.center.addClassName('loading');
        this.layout.insertInto(document.body);
    };

    NGSITypeBrowser.prototype.updateNGSIConnection = function updateNGSIConnection() {

        this.ngsi_server = mp.prefs.get('ngsi_server');
        var options = {
            request_headers: {},
            use_user_fiware_token: mp.prefs.get('use_user_fiware_token')
        };
        if (mp.prefs.get('use_owner_credentials')) {
            options.request_headers['X-FIWARE-OAuth-Token'] = 'true';
            options.request_headers['X-FIWARE-OAuth-Header-Name'] = 'X-Auth-Token';
            options.request_headers['x-FI-WARE-OAuth-Source'] = 'workspaceowner';
        }

        var tenant = mp.prefs.get('ngsi_tenant').trim().toLowerCase();
        if (tenant !== '') {
            options.request_headers['FIWARE-Service'] = tenant;
        }

        var path = mp.prefs.get('ngsi_service_path').trim().toLowerCase();
        if (path !== '' && path !== '/') {
            options.request_headers['FIWARE-ServicePath'] = path;
        }

        this.ngsi_connection = new NGSI.Connection(this.ngsi_server, options);
    };

    // =========================================================================
    // PRIVATE MEMBERS
    // =========================================================================

    var onNGSIQuerySuccess = function onNGSIQuerySuccess(next, page, data) {
        var search_info = {
            'resources': data.results,
            'current_page': page,
            'total_count': data.count
        };

        next(data.results, search_info);
    };

    var createNGSISource = function createNGSISource() {
        this.ngsi_source = new se.PaginatedSource({
            'pageSize': 30,
            'requestFunc': function (page, options, onSuccess, onError) {
                if (this.ngsi_connection !== null) {
                    this.ngsi_connection.getAvailableSubscriptions({
                        limit: options.pageSize,
                        offset: (page - 1) * options.pageSize
                    }).then(
                        onNGSIQuerySuccess.bind(null, onSuccess, page),
                        onError
                    );
                } else {
                    onSuccess([], {resources: [], total_count: 0, current_page: 0});
                }
            }.bind(this)
        });
        this.ngsi_source.addEventListener('requestStart', function () {
            this.layout.center.disable();
        }.bind(this));
        this.ngsi_source.addEventListener('requestEnd', function () {
            this.layout.center.enable();
        }.bind(this));
    };

    var createTable = function createTable() {
        var fields;

        // Configure the basic fields
        fields = [
            {field: 'id', label: 'Id', sortable: false, width: "20%"},
            {field: 'description', label: 'Description', sortable: false},
            {field: 'status', label: 'Status', width: '10ex', sortable: false},
            {field: 'expires', type: 'date', label: 'Expires', width: '24ex', sortable: false}
        ];

        if (mp.prefs.get('allow_delete')) {
            fields.push({
                label: 'Actions',
                width: '100px',
                contentBuilder: function (entry) {
                    var content, button;

                    content = new se.Container({class: 'btn-group'});

                    if (mp.prefs.get('allow_edit')) {
                        button = new se.Button({
                            iconClass: 'fa fa-pencil fa-fw',
                            title: 'Edit'
                        });
                        content.appendChild(button);
                    }

                    if (mp.prefs.get('allow_delete')) {
                        button = new se.Button({
                            class: 'btn-danger',
                            iconClass: 'fa fa-trash fa-fw',
                            title: 'Delete'
                        });
                        button.addEventListener("click", function () {
                            this.ngsi_connection.deleteSubscription(entry.id, {
                                onSuccess: this.ngsi_source.refresh.bind(this.ngsi_source)
                            });
                        }.bind(this));
                        content.appendChild(button);
                    }

                    return content;
                }.bind(this),
                sortable: false
            });
        }

        // Create the table
        this.table = new se.ModelTable(fields, {id: 'name', pageSize: 30, source: this.ngsi_source, 'class': 'table-striped'});
        this.table.reload();
        this.layout.center.clear();
        this.layout.center.appendChild(this.table);
    };

    var widget = new NGSITypeBrowser();
    window.addEventListener("DOMContentLoaded", widget.init.bind(widget), false);

})(StyledElements, MashupPlatform);
<commit_msg>Update NGSI v2 methods<commit_after>/*
 * Copyright (c) 2015-2017 CoNWeT Lab., Universidad Politécnica de Madrid
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* global NGSI, StyledElements */

(function (se, mp) {

    "use strict";

    var NGSITypeBrowser = function NGSITypeBrowser() {

        /* Context */
        mp.widget.context.registerCallback(function (newValues) {
            if (this.layout && ("heightInPixels" in newValues || "widthInPixels" in newValues)) {
                this.layout.repaint();
            }
        }.bind(this));

        /* Preferences */
        mp.prefs.registerCallback(function (newValues) {
            if ('ngsi_server' in newValues || 'use_user_fiware_token' in newValues || 'use_owner_credentials' in newValues || 'ngsi_tenant' in newValues || 'ngsi_service_path' in newValues) {
                this.updateNGSIConnection();
            }

            this.ngsi_source.goToFirst();
        }.bind(this));

        this.layout = null;
        this.table = null;
    };

    NGSITypeBrowser.prototype.init = function init() {
        createNGSISource.call(this);
        this.updateNGSIConnection();

        this.layout = new se.VerticalLayout();
        createTable.call(this);

        this.layout.center.addClassName('loading');
        this.layout.insertInto(document.body);
    };

    NGSITypeBrowser.prototype.updateNGSIConnection = function updateNGSIConnection() {

        this.ngsi_server = mp.prefs.get('ngsi_server');
        var options = {
            request_headers: {},
            use_user_fiware_token: mp.prefs.get('use_user_fiware_token')
        };
        if (mp.prefs.get('use_owner_credentials')) {
            options.request_headers['X-FIWARE-OAuth-Token'] = 'true';
            options.request_headers['X-FIWARE-OAuth-Header-Name'] = 'X-Auth-Token';
            options.request_headers['x-FI-WARE-OAuth-Source'] = 'workspaceowner';
        }

        var tenant = mp.prefs.get('ngsi_tenant').trim().toLowerCase();
        if (tenant !== '') {
            options.request_headers['FIWARE-Service'] = tenant;
        }

        var path = mp.prefs.get('ngsi_service_path').trim().toLowerCase();
        if (path !== '' && path !== '/') {
            options.request_headers['FIWARE-ServicePath'] = path;
        }

        this.ngsi_connection = new NGSI.Connection(this.ngsi_server, options);
    };

    // =========================================================================
    // PRIVATE MEMBERS
    // =========================================================================

    var onNGSIQuerySuccess = function onNGSIQuerySuccess(next, page, data) {
        var search_info = {
            'resources': data.results,
            'current_page': page,
            'total_count': data.count
        };

        next(data.results, search_info);
    };

    var createNGSISource = function createNGSISource() {
        this.ngsi_source = new se.PaginatedSource({
            'pageSize': 30,
            'requestFunc': function (page, options, onSuccess, onError) {
                if (this.ngsi_connection !== null) {
                    this.ngsi_connection.v2.listSubscriptions({
                        count: true,
                        limit: options.pageSize,
                        offset: (page - 1) * options.pageSize
                    }).then(
                        onNGSIQuerySuccess.bind(null, onSuccess, page),
                        onError
                    );
                } else {
                    onSuccess([], {resources: [], total_count: 0, current_page: 0});
                }
            }.bind(this)
        });
        this.ngsi_source.addEventListener('requestStart', function () {
            this.layout.center.disable();
        }.bind(this));
        this.ngsi_source.addEventListener('requestEnd', function () {
            this.layout.center.enable();
        }.bind(this));
    };

    var createTable = function createTable() {
        var fields;

        // Configure the basic fields
        fields = [
            {field: 'id', label: 'Id', sortable: false, width: "20%"},
            {field: 'description', label: 'Description', sortable: false},
            {field: 'status', label: 'Status', width: '10ex', sortable: false},
            {field: 'expires', type: 'date', label: 'Expires', width: '24ex', sortable: false}
        ];

        if (mp.prefs.get('allow_delete')) {
            fields.push({
                label: 'Actions',
                width: '100px',
                contentBuilder: function (entry) {
                    var content, button;

                    content = new se.Container({class: 'btn-group'});

                    if (mp.prefs.get('allow_edit')) {
                        button = new se.Button({
                            iconClass: 'fa fa-pencil fa-fw',
                            title: 'Edit'
                        });
                        content.appendChild(button);
                    }

                    if (mp.prefs.get('allow_delete')) {
                        button = new se.Button({
                            class: 'btn-danger',
                            iconClass: 'fa fa-trash fa-fw',
                            title: 'Delete'
                        });
                        button.addEventListener("click", function () {
                            this.ngsi_connection.v2.deleteSubscription(entry.id, {
                                onSuccess: this.ngsi_source.refresh.bind(this.ngsi_source)
                            });
                        }.bind(this));
                        content.appendChild(button);
                    }

                    return content;
                }.bind(this),
                sortable: false
            });
        }

        // Create the table
        this.table = new se.ModelTable(fields, {id: 'name', pageSize: 30, source: this.ngsi_source, 'class': 'table-striped'});
        this.table.reload();
        this.layout.center.clear();
        this.layout.center.appendChild(this.table);
    };

    var widget = new NGSITypeBrowser();
    window.addEventListener("DOMContentLoaded", widget.init.bind(widget), false);

})(StyledElements, MashupPlatform);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2016 CoNWeT Lab., Universidad Politécnica de Madrid
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* globals $, MashupPlatform, JSONEditor, StyledElements*/

(function () {

    "use strict";

    var MP = MashupPlatform;
    var layout;
    var stack_n;

    var playbtn, runbtn, stepbtn, dropbtn;

    var recording = false;
    var allowsend = false;

    var modes = ['code', 'form', 'text', 'tree', 'view'];

    var TEXT = 'textoutput'; // Output endpoint

    var editor;

    var stack = [];

    var select;

    var init = function init () {
        layout = new StyledElements.BorderLayout();
        layout.insertInto(document.body);
        layout.getNorthContainer().addClassName('header');
        layout.getNorthContainer().wrapperElement.innerHTML = '
Type: No data

';

        // Create the data-type selector
        var typed = $("#type-data")[0];
        var parent = typed.parentNode;
        parent.removeChild(typed);
        createTypeSelectors();
        select.insertInto(parent);

        // Create the remaining events count
        stack_n = document.createElement('div');
        document.getElementById('buttons').appendChild(stack_n);
        stack_n.className = 'badge badge-info';
        stack_n.textContent = '0';

        // Create and bind action buttons
        playbtn = new StyledElements.StyledButton({'class': 'btn-danger icon-circle', 'title': 'Start recording events'});
        playbtn.insertInto(document.getElementById('buttons'));
        playbtn.addEventListener("click", play_action);
        runbtn = new StyledElements.StyledButton({'class': 'btn-info icon-fast-forward', 'title': 'Launch all pending events'});
        runbtn.insertInto(document.getElementById('buttons'));
        runbtn.addEventListener('click', run_action);
        stepbtn = new StyledElements.StyledButton({'class': 'btn-info icon-step-forward', 'title': 'Launch current event'});
        stepbtn.insertInto(document.getElementById('buttons'));
        stepbtn.addEventListener('click', step_action);
        dropbtn = new StyledElements.StyledButton({'class': 'btn-info icon-trash', 'title': 'Drop current event'});
        dropbtn.insertInto(document.getElementById('buttons'));
        dropbtn.addEventListener('click', drop_action);
        // Disable the buttons
        setdisable_btns(true);

        // Set the editor options
        var options = {
            mode: 'tree',
            modes: modes,
            error: function (err) {
                window.alert(err.toString());
            }
        };

        //Create the editor
        layout.getCenterContainer().addClassName('jsoncontainer');
        editor = new JSONEditor(layout.getCenterContainer().wrapperElement, options);

        updateContent('No data');

        layout.repaint();

        MP.wiring.registerCallback('textinput', function (data) {
            updateContent(data);
            if (!recording) {
                sendData(TEXT, data);
            }
        });
        MP.widget.context.registerCallback(function (new_values) {
            layout.repaint();
        });

        // Bind and load preferences
        MP.prefs.registerCallback(loadprefs);
        loadprefs();
    };

    // Sets a value for the data-type selector
    var updateType = function updateType(type) {
        select.setValue(type);
    };

    //Create the selectors to choose the type of the output data
    var createTypeSelectors = function createTypeSelectors () {
        select = new StyledElements.Select();

        var entries = [
            {label: "JSON - (Text)", value: "JSON - (Text)"},
            {label: "JSON - (Object)", value: "JSON - (Object)"},
            {label: "Text", value: "Text"}
        ];

        select.addEntries(entries);
        select.setValue("JSON - (Text)");

        return select;

    };

    var parse_json = function parse_json(json, type) {
        editor.options.modes = modes;
        editor.set(json);

        if (editor.options.mode === "tree") {
            editor.setMode("text"); //Force the editor to refresh, since if its already on tree mode it gets bugged (lol)
            editor.setMode("tree");
        } else if (editor.options.mode === "text") {
            editor.setMode("tree");
        }

        if (editor.options.mode !== 'code') {
            editor.expandAll();
        }

        updateType(type);
    };

    var parse_data = function parse_data(d) {
        if (typeof d === 'string') {
            try {
                var tmp = JSON.parse(d);
                parse_json(tmp, "JSON - (Text)");
            } catch (err) {
                updateType("Text");
                editor.options.modes = ['text'];
                editor.setMode('text');
                editor.setText(d);
            }
        } else {
            parse_json(d, "JSON - (Object)");
        }
    };

    var clearEvents = function clearEvents() {
        updateType('No data');
        editor.options.modes = ['text'];
        editor.setMode('text');
        editor.setText('No data');
    };

    var updateContent = function updateContent(d) {
        if (recording) {
            stack.unshift(d);
            var n = parseInt(stack_n.textContent) + 1;
            stack_n.textContent = n;
            if (stack.length === 1) {
                // first event
                parse_data(d);
            }
            setdisable_btns(false);
        } else {
            parse_data(d);
        }
    };

    var updateStackInfo = function updateStackInfo() {
        stack_n.textContent = stack.length;
        setdisable_btns(stack.length === 0);
    };

    var sendData = function (type, data) {
        if (typeof data === "undefined") {
            var editordata = editor.getText();
            data = stack.pop();

            if (data !== editordata) {
                data = editordata;
            }

            var next = 'No data';
            if (stack.length > 0) {
                next = stack[stack.length - 1];
            } else if (allowsend) {
                next = data;
                stack.push(data);
            }
            updateStackInfo();
            parse_data(next);
        }

        if (data !== "No data") {
            MP.wiring.pushEvent(type, data);
        }
    };

    var change_class = function (elem, c1, c2) {
        elem.removeClassName(c1);
        elem.addClassName(c2);
    };

    var setdisable_btns = function (value) {
        runbtn.setDisabled(value);
        stepbtn.setDisabled(value);
        dropbtn.setDisabled(value);
        if (allowsend) {
            playbtn.setDisabled(true);
            runbtn.setDisabled(true);
            dropbtn.setDisabled(true);
            stepbtn.setDisabled(false);
        }
    };

    var play_proxy = function () {
        recording = false;
        change_class(playbtn, 'icon-stop', 'icon-circle');
        change_class(playbtn, 'btn-success', 'btn-danger');
        run_action();
        playbtn.setTitle('Start recording events');
        parse_data('No data');
        setdisable_btns(true);
    };

    var pause_proxy = function () {
        parse_data('No data');
        recording = true;
        change_class(playbtn, 'icon-circle', 'icon-stop');
        change_class(playbtn, 'btn-danger', 'btn-success');
        playbtn.setTitle('Stop recording events (Launch all pending events)');
    };

    var play_action = function () {
        if (recording) {
            // Stop recording, send all events
            play_proxy();
        } else {
            // Start recording events
            pause_proxy();
        }
    };

    var run_action = function () {
        while (stack.length > 0) {
            sendData(TEXT);
        }
    };

    var step_action = function () {
        sendData(TEXT);
    };

    var drop_action = function () {
        if (stack.length > 0) {
            stack.shift();
            var next = 'No data';
            if (stack.length > 0) {
                next = stack[stack.length - 1];
            }
            updateStackInfo();
            parse_data(next);
        }
    };

    var loadprefs = function loadprefs(data) {
        if (typeof data === "undefined") {
            data = {};
            data.allowsend = MP.prefs.get("allowsend");
        }

        if ('allowsend' in data) {
            allowsend = data.allowsend;
            if (data.allowsend) {
                pause_proxy();
                updateContent("{}");
                setdisable_btns(true);
            } else {
                drop_action();
                play_proxy();
                playbtn.setDisabled(false);
            }
        }
    };

    MP.prefs.registerCallback(loadprefs);
    $(document).ready(function () {init();});
})();
<commit_msg>output data has the selected type<commit_after>/*
 * Copyright (c) 2013-2016 CoNWeT Lab., Universidad Politécnica de Madrid
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* globals $, MashupPlatform, JSONEditor, StyledElements*/

(function () {

    "use strict";

    var MP = MashupPlatform;
    var layout;
    var stack_n;

    var playbtn, runbtn, stepbtn, dropbtn;

    var recording = false;
    var allowsend = false;

    var modes = ['code', 'form', 'text', 'tree', 'view'];

    var TEXT = 'textoutput'; // Output endpoint

    var editor;

    var stack = [];

    var typeSelector;

    var init = function init () {
        layout = new StyledElements.BorderLayout();
        layout.insertInto(document.body);
        layout.getNorthContainer().addClassName('header');
        layout.getNorthContainer().wrapperElement.innerHTML = '
Type: No data

';

        // Create the data-type selector
        var typed = $("#type-data")[0];
        var parent = typed.parentNode;
        parent.removeChild(typed);
        createTypeSelectors();
        typeSelector.insertInto(parent);

        // Create the remaining events count
        stack_n = document.createElement('div');
        document.getElementById('buttons').appendChild(stack_n);
        stack_n.className = 'badge badge-info';
        stack_n.textContent = '0';

        // Create and bind action buttons
        playbtn = new StyledElements.StyledButton({'class': 'btn-danger icon-circle', 'title': 'Start recording events'});
        playbtn.insertInto(document.getElementById('buttons'));
        playbtn.addEventListener("click", play_action);
        runbtn = new StyledElements.StyledButton({'class': 'btn-info icon-fast-forward', 'title': 'Launch all pending events'});
        runbtn.insertInto(document.getElementById('buttons'));
        runbtn.addEventListener('click', run_action);
        stepbtn = new StyledElements.StyledButton({'class': 'btn-info icon-step-forward', 'title': 'Launch current event'});
        stepbtn.insertInto(document.getElementById('buttons'));
        stepbtn.addEventListener('click', step_action);
        dropbtn = new StyledElements.StyledButton({'class': 'btn-info icon-trash', 'title': 'Drop current event'});
        dropbtn.insertInto(document.getElementById('buttons'));
        dropbtn.addEventListener('click', drop_action);
        // Disable the buttons
        setdisable_btns(true);

        // Set the editor options
        var options = {
            mode: 'tree',
            modes: modes,
            error: function (err) {
                window.alert(err.toString());
            }
        };

        //Create the editor
        layout.getCenterContainer().addClassName('jsoncontainer');
        editor = new JSONEditor(layout.getCenterContainer().wrapperElement, options);

        updateContent('No data');

        layout.repaint();

        MP.wiring.registerCallback('textinput', function (data) {
            updateContent(data);
            if (!recording) {
                sendData(TEXT, data);
            }
        });
        MP.widget.context.registerCallback(function (new_values) {
            layout.repaint();
        });

        // Bind and load preferences
        MP.prefs.registerCallback(loadprefs);
        loadprefs();
    };

    // Sets a value for the data-type selector
    var updateType = function updateType(type) {
        typeSelector.setValue(type);
    };

    //Create the selector to choose the type of the output data
    var createTypeSelectors = function createTypeSelectors () {
        typeSelector = new StyledElements.Select();

        var entries = [
            {label: "JSON - (Text)", value: "JSON - (Text)"},
            {label: "JSON - (Object)", value: "JSON - (Object)"},
            {label: "Text", value: "Text"}
        ];

        typeSelector.addEntries(entries);
        typeSelector.setValue("JSON - (Text)");
    };

    var parse_json = function parse_json(json, type) {
        editor.options.modes = modes;
        editor.set(json);

        if (editor.options.mode === "tree") {
            editor.setMode("text"); //Force the editor to refresh, since if its already on tree mode it gets bugged (lol)
            editor.setMode("tree");
        } else if (editor.options.mode === "text") {
            editor.setMode("tree");
        }

        if (editor.options.mode !== 'code') {
            editor.expandAll();
        }

        updateType(type);
    };

    var parse_data = function parse_data(d) {
        if (typeof d === 'string') {
            try {
                var tmp = JSON.parse(d);
                parse_json(tmp, "JSON - (Text)");
            } catch (err) {
                updateType("Text");
                editor.options.modes = ['text'];
                editor.setMode('text');
                editor.setText(d);
            }
        } else {
            parse_json(d, "JSON - (Object)");
        }
    };

    var clearEvents = function clearEvents() {
        updateType('No data');
        editor.options.modes = ['text'];
        editor.setMode('text');
        editor.setText('No data');
    };

    var updateContent = function updateContent(d) {
        if (recording) {
            stack.unshift(d);
            var n = parseInt(stack_n.textContent) + 1;
            stack_n.textContent = n;
            if (stack.length === 1) {
                // first event
                parse_data(d);
            }
            setdisable_btns(false);
        } else {
            parse_data(d);
        }
    };

    var updateStackInfo = function updateStackInfo() {
        stack_n.textContent = stack.length;
        setdisable_btns(stack.length === 0);
    };

    var sendData = function (output, data) {
        // Data is undefined if it was called by the step / play events
        if (typeof data === "undefined") {
            // Get the selected data type.
            var editordata;
            if (typeSelector.getValue() === "JSON - (Object)") {
                editordata = editor.get(); // Object
            } else {
                editordata = editor.getText(); //JSON string / string
            }

            data = stack.pop();

            if (data !== editordata) {
                data = editordata;
            }

            // Update the editor contents to view the next data
            var next = 'No data';
            if (stack.length > 0) {
                next = stack[stack.length - 1];
            } else if (allowsend) {
                next = data;
                stack.push(data);
            }
            updateStackInfo();
            parse_data(next);
        }

        if (data !== "No data") {
            MP.wiring.pushEvent(output, data);
        }
    };

    var change_class = function (elem, c1, c2) {
        elem.removeClassName(c1);
        elem.addClassName(c2);
    };

    var setdisable_btns = function (value) {
        runbtn.setDisabled(value);
        stepbtn.setDisabled(value);
        dropbtn.setDisabled(value);
        if (allowsend) {
            playbtn.setDisabled(true);
            runbtn.setDisabled(true);
            dropbtn.setDisabled(true);
            stepbtn.setDisabled(false);
        }
    };

    var play_proxy = function () {
        recording = false;
        change_class(playbtn, 'icon-stop', 'icon-circle');
        change_class(playbtn, 'btn-success', 'btn-danger');
        run_action();
        playbtn.setTitle('Start recording events');
        parse_data('No data');
        setdisable_btns(true);
    };

    var pause_proxy = function () {
        parse_data('No data');
        recording = true;
        change_class(playbtn, 'icon-circle', 'icon-stop');
        change_class(playbtn, 'btn-danger', 'btn-success');
        playbtn.setTitle('Stop recording events (Launch all pending events)');
    };

    var play_action = function () {
        if (recording) {
            // Stop recording, send all events
            play_proxy();
        } else {
            // Start recording events
            pause_proxy();
        }
    };

    var run_action = function () {
        while (stack.length > 0) {
            sendData(TEXT);
        }
    };

    var step_action = function () {
        sendData(TEXT);
    };

    var drop_action = function () {
        if (stack.length > 0) {
            stack.shift();
            var next = 'No data';
            if (stack.length > 0) {
                next = stack[stack.length - 1];
            }
            updateStackInfo();
            parse_data(next);
        }
    };

    var loadprefs = function loadprefs(data) {
        if (typeof data === "undefined") {
            data = {};
            data.allowsend = MP.prefs.get("allowsend");
        }

        if ('allowsend' in data) {
            allowsend = data.allowsend;
            if (data.allowsend) {
                pause_proxy();
                updateContent("{}");
                setdisable_btns(true);
            } else {
                drop_action();
                play_proxy();
                playbtn.setDisabled(false);
            }
        }
    };

    MP.prefs.registerCallback(loadprefs);
    $(document).ready(function () {init();});
})();
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:foldmethod=marker:foldmarker={{{,}}}:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

let {equiv:equiv} = require('./test/equiv');
let Util = require('util');

function merge(ctor, obj) {
  for (let [k,v] in Iterator(obj))
    ctor[k] = v;
}

const TAPProducer = function TAPProducer() {
  this.outputStream = require('system').stdout;

  var depth;
  Object.defineProperty(this, "paddDepth", {

    getter: function() { return depth },
    setter: function(d) {
      d = new Number(d).valueOf();
      if (isNaN(d))
        throw TypeError("paddDepth must be a number");
      depth = d;
      this.padding = this.getPadd();
    }
  });

  this.paddDepth = 0;
}

merge(TAPProducer.prototype, {
  paddStr: '  ',

  colourize: true,

  green: function green() {
    var a = Array.slice(arguments);
    if (a.length == 0 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[32m' + a + '\x1b[0m';
  },

  red: function red() {
    var a = Array.slice(arguments);
    if (a.length == 1 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[31m' + a + '\x1b[0m';
  },

  // Handle/print the assert
  do_assert: function do_assert(a) {

    a.num = ++this._state.currentCase.numAsserts;

    let data = [a.num];
    data.push(a.ok ? this.green('ok') : this.red('not ok'));

    if (a.message !== undefined)
      data.push('-', a.message)
    else if ('defaultMsg' in a)
      data.push('-', a.defaultMsg)

    if (!a.ok)
      this._state.currentCase.assertsFailed.push(a);

    this.print(data);

    if (a.diag)
      this.diag(a.diag);
    if (a.errorDiag)
      this.diag(a.errorDiag, this.red);
    return a.ok;
  },

  print: function print() {
    var msg;
    if (arguments[0] instanceof Array)
      msg = arguments[0].join(" ");
    else
      msg = Array.join(arguments, " ");

    this.outputStream.print(this.padding + msg)
  },

  diag: function diag(msg,filter) {
    var self = this,
        lines = msg.split(/\n/)

    lines = lines.map(function(l) {
      return self.padding + ("# " + l)
    });

    if (filter)
      lines = lines.map(function(x) { return filter.call(self,x) });
    lines = lines.join("\n");

    this.outputStream.print(lines);
  },

  getPadd: function getPadd() {
    var i = 0;
    return [this.paddStr for (i in Util.Range(0, this.paddDepth))].join('');
  }
});

const Suite = exports.Suite = function Suite(cases) {
  this.__proto__.__proto__.constructor.call(this);
  this._state = {
    cases: [],
    assertsFailed: [],
    numAsserts: 0,
    currentCase: undefined
  }
  this.nested = false;

  if (!cases) {
    return;
  }

  // TODO: setup and teardown methods
  for (let [k,t] in Iterator(cases)) {

    if (/^test_/.test(k) == false)
      continue;

    let testCase = {
      name: k.replace(/^test_(.*)/, "$1"),
      index: this._state.cases.length,
      numAsserts: 0,
      assertsFailed: []
    };

    // Not a function - must be a sub-test
    if (typeof t != "function") {
      let s = testCase.suite = new Suite(t);
      s.nested = true;
      s.name = k;
    }
    else testCase.func = t;

    this._state.cases.push(testCase);
  }

  this._state.plan = this._state.cases.length;
}

Suite.prototype.__proto__ = TAPProducer.prototype;

merge(Suite.prototype, {

  run: function run() {
    if (!this._state.cases.length) {
      throw new Error("Cannot run a Test.Suite without any test cases!");
    }

    var oldCurrent = exports.__currentSuite__;
    try {
      exports.__currentSuite__ = this;
      for (let [name,test] in Iterator(this._state.cases)) {
        this.runCase( test);
      }
    }
    finally {
      exports.__currentSuite__ = oldCurrent;
    }
    this.finalize();
  },

  runCase: function runCase(theCase) {
    var asserts = exports.asserts,
        depth = this.paddDepth,
        error;

    try {
      this.diag(theCase.name + "...");
      this.paddDepth = depth + 1;
      try {
        this._state.currentCase = theCase;
        if (theCase.suite) {
          var nested = theCase.suite;
          nested.paddDepth = this.paddDepth;

          nested.run();
          theCase = nested._state;
        }
        else {
          theCase.func.call(asserts, this);
        }
      }
      finally {
        this.printPlan(theCase);
        this.paddDepth = depth;
      }
    }
    catch (e) {
      error = e;
    }
    this.finishCase(theCase, error)
  },

  finishCase: function finishCase(theCase, error) {
    var failed = error || theCase.assertsFailed.length > 0;
    this._state.currentCase = this._state;
    if (error) {

      var diag = "case terminated with exception:\n"
               + error.toString();

      if (error.fileName) {
        diag += "\n  " +  error.stack.replace(/\n/g, "\n  ");
      }

      this.do_assert( {
        type: 'case',
        when: new Date(),
        errorDiag: diag,
        ok: !failed,
        message: theCase.name
      });
      return;
    }

    this.do_assert( {
      type: 'case',
      when: new Date(),
      ok: !failed,
      message: theCase.name
    });
    delete this._state.currentCase;

  },

  printPlan: function printPlan(theCase) {
    if (theCase.planned)
      return;

    if ("plan" in theCase == false)
      theCase.plan = theCase.numAsserts;

    this.print("1.." + theCase.plan);
    theCase.planned = true;
  },

  finalize: function finalize() {
    if (this.nested)
      return;
    if (this._state.assertsFailed.length)
      this.print(this.red("Failed", this._state.assertsFailed.length, "tests"));
    else
      this.print(this.green("All tests successful"));
  }
})

exports.runner = function runner() {
  var suite;
  var args = Array.slice(arguments);
  if (args.length == 1 && args[0] instanceof Suite) {
    builder = args[0];
  }
  else if (args.every(function(x) { return x instanceof Suite })) {
    suite = new Suite();
    args.forEach(suite.addSubSuite, builder);
  }
  else if (args[0] instanceof Object) {
    suite = new Suite(args[0]);
  }
  else {
    throw new TypeError("Invalid arguments to test.runner");
  }

  return suite.run();
};

// The general test runner for 'run this dir of tests'
exports.prove = function prove() {
  const fs = require('filesystem-base');

  var i = 0;
  var options = {};

  if (typeof arguments[0] == "object") {
    i++;
    options = arguments[0];
  }

  var test_files = [];

  for (; i < arguments.length; ++i) {
    var x = arguments[i].replace(/^file:\/\//, '');

    if (!fs.exists(x))
      throw new TypeError("Cannot determine test source for " + uneval(x));

    if (fs.isDirectory(x))
      findTests(fs.list(x));
    else
      findTests([x]);
  }

  var test = loadTests(test_files);
  var suite = new Suite(test);
  suite.run();

  var failed = suite._state.assertsFailed.length;
  quit( failed <= 255 ? failed : 255 );

  function findTests(files) {
    for ([,x] in Iterator(files) ) {
      // Ingore "." dot-files
      if (x.match(/(?:^|[\/\\])\.[^\/]*$/))
        continue;

      if (fs.isDirectory(x)) {
        if (options.recurse)
          findTests(fs.list(x));
        continue;
      }

      if (x.match(/\.t\.js$/))
        test_files.push(x);
    }
  }

  function loadTests(files) {
    var filename;
    var testObject = {};
    for ([,filename] in Iterator(files) ) {
      var id  = fs.canonical(filename);

      var test = require('file://' + id);
      testObject['test_' + id] = test;
    }

    return testObject;
  }
}

var currentSuite;
Object.defineProperty( exports, "__currentSuite__", {
  getter: function() { return currentSuite },
  setter: function(x) {
    if (x === undefined || x instanceof Suite)
      return currentSuite = x;
    throw new TypeError("__currentSuite__ must be an instanceof test.Suite");
  },
  configurable: false,
  enumerable: false
});

exports.asserts = {
  same: function(got, expected, message) {

    var ok = !!equiv(got, expected);

    var a = {
      type: 'same',
      when: new Date(),
      ok: ok,
      message: message,
      defaultMsg: "arguments are the same"
    };

    if (!ok) {
      a.diag = "   Got: " + (got === undefined
                             ? "undefined"
                             : uneval(got))
             + "\nWanted: " + (expected === undefined
                             ? "undefined"
                             : uneval(expected));
    }
    return exports.__currentSuite__.do_assert(a);
  },

  instanceOf: function(obj, type, msg) {
    var test = obj instanceof type;
    return exports.__currentSuite__.do_assert( {
      type: 'instanceof',
      ok: !!test,
      when: new Date(),
      message: msg,
      defaultMsg: "is instanceof "
                  + (type.name || "correct type")
    });
  },

  ok: function ok(test, msg) {
    if (arguments.length == 0) {
      test = true; // If nothing is passed in, then assume its successful
    }
    return exports.__currentSuite__.do_assert( {
      type: 'ok',
      ok: !!test,
      when: new Date(),
      message: msg
    } );
  },

  matches: function matches(value, re, msg) {
    if (re instanceof RegExp == false) {
      re = new RegExp(re);
    }
    var ok = !!re(value);

    var a = {
      type: 'matches',
      ok: ok,
      when: new Date(),
      message: msg,
      defaultMsg: "matches " + re,
    };

    if (!ok) {
      a.diag = (value === undefined
                ? "undefined"
                : uneval(value))
             + "\nDidn't Match: " + re
    }

    return exports.__currentSuite__.do_assert(a);
  },

  diag: function diag() {
    var suite = exports.__currentSuite__;
    suite.diag.apply(suite, arguments);
  }

};

/*
t = new TestHarness;
t.test_expect_prop = function() {
  with(this) {
    ok(true, "foo")
  }
}
t.test_expect_prop.expect = 6;

t.test_die = function() {
  throw new Error("foo\nbar");
}

t.test_noplan = function() {
  this.ok("no plan");
  this.same(1,new Number("1"), "numbers are the same");
}

t.test_gt_ten = function () {
  this.expect(12);
  [this.ok(1, i) for (i in Util.Range(0,12) )];
}

t.test_gt = function() {
  this.expect(1);
  this.ok();
  this.ok();
  this.ok();
}

t.go();
*/
<commit_msg>core/js: add an asserts.throwsOk<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:foldmethod=marker:foldmarker={{{,}}}:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

let {equiv:equiv} = require('./test/equiv');
let Util = require('util');

function merge(ctor, obj) {
  for (let [k,v] in Iterator(obj))
    ctor[k] = v;
}

const TAPProducer = function TAPProducer() {
  this.outputStream = require('system').stdout;

  var depth;
  Object.defineProperty(this, "paddDepth", {

    getter: function() { return depth },
    setter: function(d) {
      d = new Number(d).valueOf();
      if (isNaN(d))
        throw TypeError("paddDepth must be a number");
      depth = d;
      this.padding = this.getPadd();
    }
  });

  this.paddDepth = 0;
}

merge(TAPProducer.prototype, {
  paddStr: '  ',

  colourize: true,

  green: function green() {
    var a = Array.slice(arguments);
    if (a.length == 0 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[32m' + a + '\x1b[0m';
  },

  red: function red() {
    var a = Array.slice(arguments);
    if (a.length == 1 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[31m' + a + '\x1b[0m';
  },

  // Handle/print the assert
  do_assert: function do_assert(a) {

    a.num = ++this._state.currentCase.numAsserts;

    let data = [a.num];
    data.push(a.ok ? this.green('ok') : this.red('not ok'));

    if (a.message !== undefined)
      data.push('-', a.message)
    else if ('defaultMsg' in a)
      data.push('-', a.defaultMsg)

    if (!a.ok)
      this._state.currentCase.assertsFailed.push(a);

    this.print(data);

    if (a.diag)
      this.diag(a.diag);
    if (a.errorDiag)
      this.diag(a.errorDiag, this.red);
    return a.ok;
  },

  print: function print() {
    var msg;
    if (arguments[0] instanceof Array)
      msg = arguments[0].join(" ");
    else
      msg = Array.join(arguments, " ");

    this.outputStream.print(this.padding + msg)
  },

  diag: function diag(msg,filter) {
    var self = this,
        lines = msg.split(/\n/)

    lines = lines.map(function(l) {
      return self.padding + ("# " + l)
    });

    if (filter)
      lines = lines.map(function(x) { return filter.call(self,x) });
    lines = lines.join("\n");

    this.outputStream.print(lines);
  },

  getPadd: function getPadd() {
    var i = 0;
    return [this.paddStr for (i in Util.Range(0, this.paddDepth))].join('');
  }
});

const Suite = exports.Suite = function Suite(cases) {
  this.__proto__.__proto__.constructor.call(this);
  this._state = {
    cases: [],
    assertsFailed: [],
    numAsserts: 0,
    currentCase: undefined
  }
  this.nested = false;

  if (!cases) {
    return;
  }

  // TODO: setup and teardown methods
  for (let [k,t] in Iterator(cases)) {

    if (/^test_/.test(k) == false)
      continue;

    let testCase = {
      name: k.replace(/^test_(.*)/, "$1"),
      index: this._state.cases.length,
      numAsserts: 0,
      assertsFailed: []
    };

    // Not a function - must be a sub-test
    if (typeof t != "function") {
      let s = testCase.suite = new Suite(t);
      s.nested = true;
      s.name = k;
    }
    else testCase.func = t;

    this._state.cases.push(testCase);
  }

  this._state.plan = this._state.cases.length;
}

Suite.prototype.__proto__ = TAPProducer.prototype;

merge(Suite.prototype, {

  run: function run() {
    if (!this._state.cases.length) {
      throw new Error("Cannot run a Test.Suite without any test cases!");
    }

    var oldCurrent = exports.__currentSuite__;
    try {
      exports.__currentSuite__ = this;
      for (let [name,test] in Iterator(this._state.cases)) {
        this.runCase( test);
      }
    }
    finally {
      exports.__currentSuite__ = oldCurrent;
    }
    this.finalize();
  },

  runCase: function runCase(theCase) {
    var asserts = exports.asserts,
        depth = this.paddDepth,
        error;

    try {
      this.diag(theCase.name + "...");
      this.paddDepth = depth + 1;
      try {
        this._state.currentCase = theCase;
        if (theCase.suite) {
          var nested = theCase.suite;
          nested.paddDepth = this.paddDepth;

          nested.run();
          theCase = nested._state;
        }
        else {
          theCase.func.call(asserts, this);
        }
      }
      finally {
        this.printPlan(theCase);
        this.paddDepth = depth;
      }
    }
    catch (e) {
      error = e;
    }
    this.finishCase(theCase, error)
  },

  finishCase: function finishCase(theCase, error) {
    var failed = error || theCase.assertsFailed.length > 0;
    this._state.currentCase = this._state;
    if (error) {

      var diag = "case terminated with exception:\n"
               + error.toString();

      if (error.fileName) {
        diag += "\n  " +  error.stack.replace(/\n/g, "\n  ");
      }

      this.do_assert( {
        type: 'case',
        when: new Date(),
        errorDiag: diag,
        ok: !failed,
        message: theCase.name
      });
      return;
    }

    this.do_assert( {
      type: 'case',
      when: new Date(),
      ok: !failed,
      message: theCase.name
    });
    delete this._state.currentCase;

  },

  printPlan: function printPlan(theCase) {
    if (theCase.planned)
      return;

    if ("plan" in theCase == false)
      theCase.plan = theCase.numAsserts;

    this.print("1.." + theCase.plan);
    theCase.planned = true;
  },

  finalize: function finalize() {
    if (this.nested)
      return;
    if (this._state.assertsFailed.length)
      this.print(this.red("Failed", this._state.assertsFailed.length, "tests"));
    else
      this.print(this.green("All tests successful"));
  }
})

exports.runner = function runner() {
  var suite;
  var args = Array.slice(arguments);
  if (args.length == 1 && args[0] instanceof Suite) {
    builder = args[0];
  }
  else if (args.every(function(x) { return x instanceof Suite })) {
    suite = new Suite();
    args.forEach(suite.addSubSuite, builder);
  }
  else if (args[0] instanceof Object) {
    suite = new Suite(args[0]);
  }
  else {
    throw new TypeError("Invalid arguments to test.runner");
  }

  return suite.run();
};

// The general test runner for 'run this dir of tests'
exports.prove = function prove() {
  const fs = require('filesystem-base');

  var i = 0;
  var options = {};

  if (typeof arguments[0] == "object") {
    i++;
    options = arguments[0];
  }

  var test_files = [];

  for (; i < arguments.length; ++i) {
    var x = arguments[i].replace(/^file:\/\//, '');

    if (!fs.exists(x))
      throw new TypeError("Cannot determine test source for " + uneval(x));

    if (fs.isDirectory(x))
      findTests(fs.list(x));
    else
      findTests([x]);
  }

  var test = loadTests(test_files);
  var suite = new Suite(test);
  suite.run();

  var failed = suite._state.assertsFailed.length;
  quit( failed <= 255 ? failed : 255 );

  function findTests(files) {
    for ([,x] in Iterator(files) ) {
      // Ingore "." dot-files
      if (x.match(/(?:^|[\/\\])\.[^\/]*$/))
        continue;

      if (fs.isDirectory(x)) {
        if (options.recurse)
          findTests(fs.list(x));
        continue;
      }

      if (x.match(/\.t\.js$/))
        test_files.push(x);
    }
  }

  function loadTests(files) {
    var filename;
    var testObject = {};
    for ([,filename] in Iterator(files) ) {
      var id  = fs.canonical(filename);

      var test = require('file://' + id);
      testObject['test_' + id] = test;
    }

    return testObject;
  }
}

var currentSuite;
Object.defineProperty( exports, "__currentSuite__", {
  getter: function() { return currentSuite },
  setter: function(x) {
    if (x === undefined || x instanceof Suite)
      return currentSuite = x;
    throw new TypeError("__currentSuite__ must be an instanceof test.Suite");
  },
  configurable: false,
  enumerable: false
});

exports.asserts = {
  same: function(got, expected, message) {

    var ok = !!equiv(got, expected);

    var a = {
      type: 'same',
      when: new Date(),
      ok: ok,
      message: message,
      defaultMsg: "arguments are the same"
    };

    if (!ok) {
      a.diag = "   Got: " + (got === undefined
                             ? "undefined"
                             : uneval(got))
             + "\nWanted: " + (expected === undefined
                             ? "undefined"
                             : uneval(expected));
    }
    return exports.__currentSuite__.do_assert(a);
  },

  instanceOf: function(obj, type, msg) {
    var test = obj instanceof type;
    return exports.__currentSuite__.do_assert( {
      type: 'instanceof',
      ok: !!test,
      when: new Date(),
      message: msg,
      defaultMsg: "is instanceof "
                  + (type.name || "correct type")
    });
  },

  ok: function ok(test, msg) {
    if (arguments.length == 0) {
      test = true; // If nothing is passed in, then assume its successful
    }
    return exports.__currentSuite__.do_assert( {
      type: 'ok',
      ok: !!test,
      when: new Date(),
      message: msg
    } );
  },

  matches: function matches(value, re, msg) {
    if (re instanceof RegExp == false) {
      re = new RegExp(re);
    }
    var ok = !!re(value);

    var a = {
      type: 'matches',
      ok: ok,
      when: new Date(),
      message: msg,
      defaultMsg: "matches " + re,
    };

    if (!ok) {
      a.diag = (value === undefined
                ? "undefined"
                : uneval(value))
             + "\nDidn't Match: " + re
    }

    return exports.__currentSuite__.do_assert(a);
  },

  diag: function diag() {
    var suite = exports.__currentSuite__;
    suite.diag.apply(suite, arguments);
  },

  throwsOk: function( testcase, expected, message ) {
    if ( message == undefined ) {
      message = expected;
      expected = undefined;
    }
    var suite = exports.__currentSuite__;

    var a = {
      type: "throwsOk",
      ok: 0,
      message: message,
      defaultMsg: "throws error ok",
    };

    try {
      testcase();
      a.diag = "No error thrown";
      suite.do_assert( a );
    }
    catch ( e ) {
      if ( expected === undefined || expected == e.toString() ) {
        a.ok = true;
        suite.do_assert( a );
      }
      else {
        a.diag = "   Got: " + e.toString() + "\n"
                 "Wanted: " + expected;
        suite.do_assert( a );
      }
    }
  }

};

/*
t = new TestHarness;
t.test_expect_prop = function() {
  with(this) {
    ok(true, "foo")
  }
}
t.test_expect_prop.expect = 6;

t.test_die = function() {
  throw new Error("foo\nbar");
}

t.test_noplan = function() {
  this.ok("no plan");
  this.same(1,new Number("1"), "numbers are the same");
}

t.test_gt_ten = function () {
  this.expect(12);
  [this.ok(1, i) for (i in Util.Range(0,12) )];
}

t.test_gt = function() {
  this.expect(1);
  this.ok();
  this.ok();
  this.ok();
}

t.go();
*/
<|endoftext|>


<commit_before>import { watchFile, unwatchFile } from 'fs'
import Catchment from 'catchment'
import { EOL } from 'os'
import {
  createErrorTransformStream,
  createProgressTransformStream,
  createTestSuiteStackStream,
} from './stream'
import { buildRootTestSuite, clearRequireCache } from './bin'

function watchFiles(files, callback) {
  files.forEach((file) => {
    // console.log(`Watching ${file} for changes...`)
    watchFile(file, callback)
  })
}
function unwatchFiles(files) {
  files.forEach((file) => {
    // console.log(`Unwatching ${file}`)
    unwatchFile(file)
  })
}

/**
 *
 * @param {string[]} paths Paths to test suites.
 * @param {boolean} [watch] Whether to watch files for changes.
 * @param {string[]} [_currentlyWatching]
 */
export default async function run({
  paths,
  watch,
  timeout,
}, _currentlyWatching = []) {
  clearRequireCache()
  const rootTestSuite = await buildRootTestSuite(paths, timeout)

  if (watch) {
    unwatchFiles(_currentlyWatching)
    const newCurrentlyWatching = Object.keys(require.cache)
    watchFiles(newCurrentlyWatching, async () => {
      // we can also re-run only changed test suites
      await run({
        paths,
        watch,
        timeout,
      }, newCurrentlyWatching)
    })
  }

  const stack = createTestSuiteStackStream()

  const rs = createErrorTransformStream()
  const ts = createProgressTransformStream()
  stack.pipe(ts).pipe(process.stdout)
  stack.pipe(rs)

  const { promise: errorsPromise } = new Catchment({ rs })

  const count = {
    total: 0,
    error: 0,
  }

  const notify = (data) => {
    if (typeof data != 'object') return
    stack.write(data)
    if (data.type == 'test-end') {
      count.total++
      if (data.error) {
        count.error++
      }
    }
  }
  await rootTestSuite.runInSequence(notify, rootTestSuite.hasFocused)

  stack.end()
  const errorsCatchment = await errorsPromise
  process.stdout.write(EOL)
  process.stdout.write(errorsCatchment)

  process.stdout.write(`🦅  Executed ${count.total} tests`)
  if (count.error) {
    process.stdout.write(
      `: ${count.error} error${count.error > 1 ? 's' : ''}`
    )
  }
  process.stdout.write(`.${EOL}`)

  process.removeAllListeners('exit')

  process.once('exit', () => process.exit(count.error))
}
<commit_msg>beforeExit listener, closes #25<commit_after>import { watchFile, unwatchFile } from 'fs'
import Catchment from 'catchment'
import { EOL } from 'os'
import {
  createErrorTransformStream,
  createProgressTransformStream,
  createTestSuiteStackStream,
} from './stream'
import { buildRootTestSuite, clearRequireCache } from './bin'

function watchFiles(files, callback) {
  files.forEach((file) => {
    // console.log(`Watching ${file} for changes...`)
    watchFile(file, callback)
  })
}
function unwatchFiles(files) {
  files.forEach((file) => {
    // console.log(`Unwatching ${file}`)
    unwatchFile(file)
  })
}

/**
 *
 * @param {string[]} paths Paths to test suites.
 * @param {boolean} [watch] Whether to watch files for changes.
 * @param {string[]} [_currentlyWatching]
 */
export default async function run({
  paths,
  watch,
  timeout,
}, {
  _currentlyWatching = [],
  exitListener,
} = {}) {
  unwatchFiles(_currentlyWatching)
  if (exitListener) process.removeListener('beforeExit', exitListener)

  clearRequireCache()
  const rootTestSuite = await buildRootTestSuite(paths, timeout)

  const stack = createTestSuiteStackStream()

  const rs = createErrorTransformStream()
  const ts = createProgressTransformStream()
  stack.pipe(ts).pipe(process.stdout)
  stack.pipe(rs)

  const { promise: errorsPromise } = new Catchment({ rs })

  const count = {
    total: 0,
    error: 0,
  }

  const notify = (data) => {
    if (typeof data != 'object') return
    stack.write(data)
    if (data.type == 'test-end') {
      count.total++
      if (data.error) {
        count.error++
      }
    }
  }
  await rootTestSuite.runInSequence(notify, rootTestSuite.hasFocused)

  stack.end()
  const errorsCatchment = await errorsPromise
  process.stdout.write(EOL)
  process.stdout.write(errorsCatchment)

  process.stdout.write(`🦅  Executed ${count.total} tests`)
  if (count.error) {
    process.stdout.write(
      `: ${count.error} error${count.error > 1 ? 's' : ''}`
    )
  }
  process.stdout.write(`.${EOL}`)

  const newExitListener = () => {
    process.exit(count.error)
  }
  process.once('beforeExit', newExitListener)

  if (watch) {
    const newCurrentlyWatching = Object.keys(require.cache)
    watchFiles(newCurrentlyWatching, async () => {
      // we can also re-run only changed test suites
      await run({
        paths,
        watch,
        timeout,
      }, {
        _currentlyWatching: newCurrentlyWatching,
        exitListener: newExitListener,
      })
    })
  }
}
<|endoftext|>


<commit_before>macro foreach {
  // foreach(value of list), foreach(value of [1,...,n])
  rule {($x:ident of $list:expr) { $line ... }} => {
    var list = $list;
    for (var i = 0; i < list.length; i++) {
      var $x = list[i];
      $line ...
    }
  }
  // foreach(ix, value of list), foreach(ix, value of [1,...,n])
  rule {($ix:ident, $x:ident of $list:expr) { $line ... }} => {
    var list = $list;
    for (var $ix = 0; $ix < list.length; $ix++) {
      var $x = list[$ix];
      $line ...
    }
  }
}
export foreach

// Optimized for performance with large numbers of keys (N > 20).
// For smaller numbers of keys, just use for...in.
macro forattr {
  // forattr(ix of object)
  rule {($ix:ident of $obj:expr) { $line ... }} => {
    var obj = $obj;
    var keys = Object.keys(obj);
    for(var i = 0, len = keys.length; i < len; i++) {
      var $ix = keys[i];
      $line ...
    }
  }
  // forattr(ix, value of object)
  rule {($ix:ident, $x:ident of $obj:expr) { $line ... }} => {
    var obj = $obj;
    var keys = Object.keys(obj);
    for(var i = 0, len = keys.length; i < len; i++) {
      var $ix = keys[i];
      var $x = obj[$ix];
      $line ...
    }
  }
}
export forattr
<commit_msg>Adds placeholder factToId macro<commit_after>macro foreach {
  // foreach(value of list), foreach(value of [1,...,n])
  rule {($x:ident of $list:expr) { $line ... }} => {
    var list = $list;
    for (var i = 0; i < list.length; i++) {
      var $x = list[i];
      $line ...
    }
  }
  // foreach(ix, value of list), foreach(ix, value of [1,...,n])
  rule {($ix:ident, $x:ident of $list:expr) { $line ... }} => {
    var list = $list;
    for (var $ix = 0; $ix < list.length; $ix++) {
      var $x = list[$ix];
      $line ...
    }
  }
}
export foreach

// Optimized for performance with large numbers of keys (N > 20).
// For smaller numbers of keys, just use for...in.
macro forattr {
  // forattr(ix of object)
  rule {($ix:ident of $obj:expr) { $line ... }} => {
    var obj = $obj;
    var keys = Object.keys(obj);
    for(var i = 0, len = keys.length; i < len; i++) {
      var $ix = keys[i];
      $line ...
    }
  }
  // forattr(ix, value of object)
  rule {($ix:ident, $x:ident of $obj:expr) { $line ... }} => {
    var obj = $obj;
    var keys = Object.keys(obj);
    for(var i = 0, len = keys.length; i < len; i++) {
      var $ix = keys[i];
      var $x = obj[$ix];
      $line ...
    }
  }
}
export forattr

macro factToId {
  rule {($fact:expr)} => {
    JSON.stringify($fact);
  }
}
export factToId
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';

import DateUtilities from '../utility/DateUtilities';

class MonthHeader extends Component {

  static defaultProps = {}

  static propTypes = {
    displayDate: PropTypes.instanceOf(Date).isRequired,
    setDisplayDate: PropTypes.func.isRequired,
    minimumDate: PropTypes.instanceOf(Date),
    maximumDate: PropTypes.instanceOf(Date)
  }

  constructor(props) {
    super(props);
  }

  displayPreviousMonth = () => {
    const { setDisplayDate, displayDate } = this.props;
    setDisplayDate(DateUtilities.addMonthsToDate(displayDate, -1));
  }

  displayNextMonth = () => {
    const { setDisplayDate, displayDate } = this.props;
    setDisplayDate(DateUtilities.addMonthsToDate(displayDate, 1));
  }

  getMonthHeaderClassName = () => {
    const { displayDate, minimumDate, maximumDate} = this.props;

    var className = 'month-header';

    if (DateUtilities.areSameYearMonth(displayDate, minimumDate)) {
      className += ' minimum-date-month';
    }

    if (DateUtilities.areSameYearMonth(displayDate, maximumDate)) {
      className += ' maximum-date-month';
    }

    return className;
  }

  render () {
    const { displayDate } = this.props;
    return (

        <button type="button" onClick={() => this.displayPreviousMonth()} className={""} >{String.fromCharCode(9664)}</button>

{DateUtilities.toMonthYearString(displayDate)}

        <button type="button" onClick={() => this.displayNextMonth()} className={""} >{String.fromCharCode(9654)}</button>

    );
  }
}

export default MonthHeader;
<commit_msg>undefined/null check for min, max date<commit_after>import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';

import DateUtilities from '../utility/DateUtilities';

class MonthHeader extends Component {

  static defaultProps = {}

  static propTypes = {
    displayDate: PropTypes.instanceOf(Date).isRequired,
    setDisplayDate: PropTypes.func.isRequired,
    minimumDate: PropTypes.instanceOf(Date),
    maximumDate: PropTypes.instanceOf(Date)
  }

  constructor(props) {
    super(props);
  }

  displayPreviousMonth = () => {
    const { setDisplayDate, displayDate } = this.props;
    setDisplayDate(DateUtilities.addMonthsToDate(displayDate, -1));
  }

  displayNextMonth = () => {
    const { setDisplayDate, displayDate } = this.props;
    setDisplayDate(DateUtilities.addMonthsToDate(displayDate, 1));
  }

  getMonthHeaderClassName = () => {
    const { displayDate, minimumDate, maximumDate} = this.props;

    var className = 'month-header';

    if (minimumDate && DateUtilities.areSameYearMonth(displayDate, minimumDate)) {
      className += ' minimum-date-month';
    }

    if (maximumDate && DateUtilities.areSameYearMonth(displayDate, maximumDate)) {
      className += ' maximum-date-month';
    }

    return className;
  }

  render () {
    const { displayDate } = this.props;
    return (

        <button type="button" onClick={() => this.displayPreviousMonth()} className={""} >{String.fromCharCode(9664)}</button>

{DateUtilities.toMonthYearString(displayDate)}

        <button type="button" onClick={() => this.displayNextMonth()} className={""} >{String.fromCharCode(9654)}</button>

    );
  }
}

export default MonthHeader;
<|endoftext|>


<commit_before>/**
 * @module ol/geom
 */

export {default as Circle} from './geom/Circle.js';
export {default as Geometry} from './geom/Geometry.js';
export {default as GeometryCollection} from './geom/GeometryCollection.js';
export {default as LineString} from './geom/LineString.js';
export {default as MultiLineString} from './geom/MultiLineString.js';
export {default as MultiPoint} from './geom/MultiPoint.js';
export {default as MultiPolygon} from './geom/MultiPolygon.js';
export {default as Point} from './geom/Point.js';
export {default as Polygon} from './geom/Polygon.js';
<commit_msg>Add missing import for LinearRing<commit_after>/**
 * @module ol/geom
 */

export {default as Circle} from './geom/Circle.js';
export {default as Geometry} from './geom/Geometry.js';
export {default as GeometryCollection} from './geom/GeometryCollection.js';
export {default as LineString} from './geom/LineString.js';
export {default as MultiLineString} from './geom/MultiLineString.js';
export {default as MultiPoint} from './geom/MultiPoint.js';
export {default as MultiPolygon} from './geom/MultiPolygon.js';
export {default as Point} from './geom/Point.js';
export {default as Polygon} from './geom/Polygon.js';
export {default as LinearRing} from './geom/LinearRing.js';
<|endoftext|>


<commit_before>const valueFixers = require('value-fixers');
const parambulator = require('parambulator');

function fixFilterAndSearch(schema) {
  // currently only for int and float
  // schema can be
  // {
  //   fieldName1: 'int',
  //   fieldName2: 'float',
  // }

  const operators = ['=', '<>', '>', '>=', '<', '<='];

  function fixValue(type, value) {
    return {
      int: parseInt,
      float: parseFloat
    }[type](value);
  }

  function fixFilter(f) {
    if (!f || !Array.isArray(f)) return f;
    if (
      f.length === 3 &&
      typeof f[2] === 'string' &&
      schema[f[0]] &&
      operators.includes(f[1])
    )
      return [f[0], f[1], fixValue(schema[f[0]], f[2])];
    else return f.map(e => fixFilter(e));
  }

  function fixSearch(se, so, sv) {
    if (!se || !so || !sv || typeof sv !== 'string') return sv;
    const fieldName =
      typeof se === 'string'
        ? schema[se]
        : Array.isArray(se)
          ? se.find(e => (schema[e] ? e : null))
          : null;
    return fieldName ? fixValue(schema[fieldName], sv) : sv;
  }

  return qry => {
    if (!qry) return qry;
    const fixedFilter = fixFilter(qry.filter);
    const fixedSearchValue = fixSearch(
      qry.searchExpr,
      qry.searchOperation,
      qry.searchValue
    );

    return Object.assign(
      {},
      qry,
      fixedFilter
        ? {
            filter: fixedFilter
          }
        : {},
      fixedSearchValue
        ? {
            searchValue: fixedSearchValue
          }
        : {}
    );
  };
}

const sortOptionsChecker = parambulator({
  required$: ['desc', 'selector'],
  // isExpanded doesn't make any sense with sort, but the grid seems
  // to include it occasionally - probably a bug
  only$: ['desc', 'selector', 'isExpanded'],
  desc: {
    type$: 'boolean'
  },
  selector: {
    type$: 'string'
  }
});

const groupOptionsChecker = parambulator({
  required$: ['selector'],
  only$: ['desc', 'selector', 'isExpanded', 'groupInterval'],
  desc: {
    type$: 'boolean'
  },
  isExpanded: {
    type$: 'boolean'
  },
  selector: {
    type$: 'string'
  },
  groupInterval: {
    type$: ['string', 'integer']
    // unclear whether parambulator supports a spec that says "can be enum but also number"
    //enum$: [ "year", "quarter", "month", "day", "dayOfWeek", "hour", "minute", "second" ] // and numbers?
  }
});

const summaryOptionsChecker = parambulator({
  required$: ['summaryType'],
  only$: ['summaryType', 'selector'],
  summaryType: {
    enum$: ['sum', 'avg', 'min', 'max', 'count']
  },
  selector: {
    type$: 'string'
  }
});

function validateAll(list, checker, short = true) {
  return list.reduce(
    (r, v) => {
      if (short && !r.valid) return r; // short circuiting
      const newr = checker.validate(v);
      if (newr) {
        r.errors.push(newr);
        r.valid = false;
      }
      return r;
    },
    { valid: true, errors: [] }
  );
}

function parseAndFix(arg) {
  const ob = typeof arg === 'string' ? JSON.parse(arg) : arg;
  return valueFixers.fixObject(
    ob,
    valueFixers.defaultFixers.concat(valueFixers.fixBool)
  );
}

function representsTrue(val) {
  return val === true || val === 'true';
}

function wrapLoadOptions(lo) {
  return {
    loadOptions: lo
  };
}

function wrapProcessingOptions(po) {
  return {
    processingOptions: po
  };
}

function check(
  qry,
  onames,
  checker,
  converter = (v, vname) => v,
  defaultValue = {},
  wrapper = wrapLoadOptions
) {
  const options = typeof onames === 'string' ? [onames] : onames;
  const allFound = qry && options.reduce((r, v) => r && !!qry[v], true);

  // console.log(`Options: ${JSON.stringify(options)}, allFound: ${allFound}`);

  if (!allFound) return defaultValue;
  try {
    const vals = options.map(o => converter(qry[o], o));
    // console.log('Vals: ', JSON.stringify(vals));

    const checkResult = checker(...vals);
    // console.log('Check results: ', JSON.stringify(checkResult));
    return checkResult
      ? wrapper(checkResult)
      : {
          errors: options.map(o => `Invalid '${o}': ${qry[o]}`)
        };
  } catch (err) {
    return {
      errors: [err]
    };
  }
}

function takeOptions(qry) {
  return check(
    qry,
    'take',
    take =>
      take >= 0
        ? {
            take
          }
        : null,
    take => parseInt(take)
  );
}

function skipOptions(qry) {
  return check(
    qry,
    'skip',
    skip =>
      skip >= 0
        ? {
            skip
          }
        : null,
    skip => parseInt(skip)
  );
}

function totalCountOptions(qry) {
  return check(
    qry,
    'requireTotalCount',
    requireTotalCount =>
      requireTotalCount
        ? {
            requireTotalCount
          }
        : null,
    requireTotalCount => representsTrue(requireTotalCount)
  );
}

function sortOptions(qry) {
  return check(qry, 'sort', sort => {
    const sortOptions = parseAndFix(sort);
    if (Array.isArray(sortOptions) && sortOptions.length > 0) {
      const vr = validateAll(sortOptions, sortOptionsChecker);
      if (vr.valid)
        return {
          sort: sortOptions
        };
      else
        throw `Sort parameter validation errors: ${JSON.stringify(vr.errors)}`;
    } else return null;
  });
}

function groupOptions(qry) {
  return check(
    qry,
    'group',
    group => {
      const groupOptions = parseAndFix(group);
      if (Array.isArray(groupOptions)) {
        if (groupOptions.length > 0) {
          const vr = validateAll(groupOptions, groupOptionsChecker);
          if (vr.valid)
            return mergeResults([
              wrapLoadOptions({
                group: groupOptions
              }),
              check(
                qry,
                'requireGroupCount',
                requireGroupCount =>
                  requireGroupCount
                    ? {
                        requireGroupCount
                      }
                    : null,
                requireGroupCount => representsTrue(requireGroupCount)
              ),
              check(qry, 'groupSummary', groupSummary => {
                const gsOptions = parseAndFix(groupSummary);
                if (Array.isArray(gsOptions)) {
                  if (gsOptions.length > 0) {
                    const vr = validateAll(gsOptions, summaryOptionsChecker);
                    if (vr.valid)
                      return {
                        groupSummary: gsOptions
                      };
                    else
                      throw `Group summary parameter validation errors: ${JSON.stringify(
                        vr.errors
                      )}`;
                  } else return {}; // ignore empty array
                } else return null;
              })
            ]);
          else
            throw `Group parameter validation errors: ${JSON.stringify(
              vr.errors
            )}`;
        } else return {}; // ignore empty array
      } else return null;
    },
    undefined,
    undefined,
    o => o /* deactivate wrapper for the result */
  );
}

function totalSummaryOptions(qry) {
  return check(qry, 'totalSummary', totalSummary => {
    const tsOptions = parseAndFix(totalSummary);
    if (Array.isArray(tsOptions)) {
      if (tsOptions.length > 0) {
        const vr = validateAll(tsOptions, summaryOptionsChecker);
        if (vr.valid)
          return {
            totalSummary: tsOptions
          };
        else
          throw `Total summary parameter validation errors: ${JSON.stringify(
            vr.errors
          )}`;
      } else return {}; // ignore empty array
    } else return null;
  });
}

function filterOptions(qry) {
  return check(qry, 'filter', filter => {
    const filterOptions = parseAndFix(filter);
    if (typeof filterOptions === 'string' || Array.isArray(filterOptions))
      return {
        filter: filterOptions
      };
    else return null;
  });
}

function searchOptions(qry) {
  return check(
    qry,
    ['searchExpr', 'searchOperation', 'searchValue'],
    (se, so, sv) => {
      if (typeof se === 'string' || Array.isArray(se))
        return {
          searchExpr: se,
          searchOperation: so,
          searchValue: sv
        };
      else return null;
    }
  );
}

function selectOptions(qry) {
  return check(qry, 'select', select => {
    const selectOptions = parseAndFix(select);
    if (typeof selectOptions === 'string')
      return {
        select: [selectOptions]
      };
    else if (Array.isArray(selectOptions)) {
      if (selectOptions.length > 0) {
        if (selectOptions.reduce((r, v) => r && typeof v === 'string'))
          return {
            select: selectOptions
          };
        else
          throw `Select array parameter has invalid content: ${JSON.stringify(
            selectOptions
          )}`;
      } else return {}; // ignore empty array
    } else return null;
  });
}

function timezoneOptions(qry) {
  return check(
    qry,
    'tzOffset',
    tzOffset => ({
      timezoneOffset: parseInt(tzOffset) || 0
    }),
    v => v,
    {
      timezoneOffset: 0
    },
    wrapProcessingOptions
  );
}

function summaryQueryLimitOptions(qry) {
  return check(
    qry,
    'summaryQueryLimit',
    sql =>
      sql >= 0
        ? {
            summaryQueryLimit: sql
          }
        : {},
    sql => parseInt(sql),
    {},
    wrapProcessingOptions
  );
}

function mergeResults(results) {
  return results.reduce(
    (r, v) => ({
      loadOptions: {
        ...(r.loadOptions || {}),
        ...(v.loadOptions || {})
      },
      processingOptions: {
        ...(r.processingOptions || {}),
        ...(v.processingOptions || {})
      },
      errors: [...(r.errors || []), ...(v.errors || [])]
    }),
    {}
  );
}

function getOptions(qry, schema) {
  if (!qry) return undefined;

  const fixedQry = schema ? fixFilterAndSearch(schema)(qry) : qry;

  // console.log('Fixed query: ', JSON.stringify(fixedQry, null, 2));

  return mergeResults(
    [
      takeOptions,
      skipOptions,
      totalCountOptions,
      sortOptions,
      groupOptions,
      totalSummaryOptions,
      filterOptions,
      searchOptions,
      selectOptions,
      timezoneOptions,
      summaryQueryLimitOptions
    ].map(f => f(fixedQry))
  );
}

module.exports = {
  getOptions,
  private: {
    fixFilterAndSearch
  }
};
<commit_msg>fix throws (no-throw-literal)<commit_after>const valueFixers = require('value-fixers');
const parambulator = require('parambulator');

function fixFilterAndSearch(schema) {
  // currently only for int and float
  // schema can be
  // {
  //   fieldName1: 'int',
  //   fieldName2: 'float',
  // }

  const operators = ['=', '<>', '>', '>=', '<', '<='];

  function fixValue(type, value) {
    return {
      int: parseInt,
      float: parseFloat
    }[type](value);
  }

  function fixFilter(f) {
    if (!f || !Array.isArray(f)) return f;
    if (
      f.length === 3 &&
      typeof f[2] === 'string' &&
      schema[f[0]] &&
      operators.includes(f[1])
    )
      return [f[0], f[1], fixValue(schema[f[0]], f[2])];
    else return f.map(e => fixFilter(e));
  }

  function fixSearch(se, so, sv) {
    if (!se || !so || !sv || typeof sv !== 'string') return sv;
    const fieldName =
      typeof se === 'string'
        ? schema[se]
        : Array.isArray(se)
        ? se.find(e => (schema[e] ? e : null))
        : null;
    return fieldName ? fixValue(schema[fieldName], sv) : sv;
  }

  return qry => {
    if (!qry) return qry;
    const fixedFilter = fixFilter(qry.filter);
    const fixedSearchValue = fixSearch(
      qry.searchExpr,
      qry.searchOperation,
      qry.searchValue
    );

    return Object.assign(
      {},
      qry,
      fixedFilter
        ? {
            filter: fixedFilter
          }
        : {},
      fixedSearchValue
        ? {
            searchValue: fixedSearchValue
          }
        : {}
    );
  };
}

const sortOptionsChecker = parambulator({
  required$: ['desc', 'selector'],
  // isExpanded doesn't make any sense with sort, but the grid seems
  // to include it occasionally - probably a bug
  only$: ['desc', 'selector', 'isExpanded'],
  desc: {
    type$: 'boolean'
  },
  selector: {
    type$: 'string'
  }
});

const groupOptionsChecker = parambulator({
  required$: ['selector'],
  only$: ['desc', 'selector', 'isExpanded', 'groupInterval'],
  desc: {
    type$: 'boolean'
  },
  isExpanded: {
    type$: 'boolean'
  },
  selector: {
    type$: 'string'
  },
  groupInterval: {
    type$: ['string', 'integer']
    // unclear whether parambulator supports a spec that says "can be enum but also number"
    //enum$: [ "year", "quarter", "month", "day", "dayOfWeek", "hour", "minute", "second" ] // and numbers?
  }
});

const summaryOptionsChecker = parambulator({
  required$: ['summaryType'],
  only$: ['summaryType', 'selector'],
  summaryType: {
    enum$: ['sum', 'avg', 'min', 'max', 'count']
  },
  selector: {
    type$: 'string'
  }
});

function validateAll(list, checker, short = true) {
  return list.reduce(
    (r, v) => {
      if (short && !r.valid) return r; // short circuiting
      const newr = checker.validate(v);
      if (newr) {
        r.errors.push(newr);
        r.valid = false;
      }
      return r;
    },
    { valid: true, errors: [] }
  );
}

function parseAndFix(arg) {
  const ob = typeof arg === 'string' ? JSON.parse(arg) : arg;
  return valueFixers.fixObject(
    ob,
    valueFixers.defaultFixers.concat(valueFixers.fixBool)
  );
}

function representsTrue(val) {
  return val === true || val === 'true';
}

function wrapLoadOptions(lo) {
  return {
    loadOptions: lo
  };
}

function wrapProcessingOptions(po) {
  return {
    processingOptions: po
  };
}

function check(
  qry,
  onames,
  checker,
  converter = (v, vname) => v,
  defaultValue = {},
  wrapper = wrapLoadOptions
) {
  const options = typeof onames === 'string' ? [onames] : onames;
  const allFound = qry && options.reduce((r, v) => r && !!qry[v], true);

  // console.log(`Options: ${JSON.stringify(options)}, allFound: ${allFound}`);

  if (!allFound) return defaultValue;
  try {
    const vals = options.map(o => converter(qry[o], o));
    // console.log('Vals: ', JSON.stringify(vals));

    const checkResult = checker(...vals);
    // console.log('Check results: ', JSON.stringify(checkResult));
    return checkResult
      ? wrapper(checkResult)
      : {
          errors: options.map(o => `Invalid '${o}': ${qry[o]}`)
        };
  } catch (err) {
    return {
      errors: [err]
    };
  }
}

function takeOptions(qry) {
  return check(
    qry,
    'take',
    take =>
      take >= 0
        ? {
            take
          }
        : null,
    take => parseInt(take)
  );
}

function skipOptions(qry) {
  return check(
    qry,
    'skip',
    skip =>
      skip >= 0
        ? {
            skip
          }
        : null,
    skip => parseInt(skip)
  );
}

function totalCountOptions(qry) {
  return check(
    qry,
    'requireTotalCount',
    requireTotalCount =>
      requireTotalCount
        ? {
            requireTotalCount
          }
        : null,
    requireTotalCount => representsTrue(requireTotalCount)
  );
}

function sortOptions(qry) {
  return check(qry, 'sort', sort => {
    const sortOptions = parseAndFix(sort);
    if (Array.isArray(sortOptions) && sortOptions.length > 0) {
      const vr = validateAll(sortOptions, sortOptionsChecker);
      if (vr.valid)
        return {
          sort: sortOptions
        };
      else
        throw new Error(
          `Sort parameter validation errors: ${JSON.stringify(vr.errors)}`
        );
    } else return null;
  });
}

function groupOptions(qry) {
  return check(
    qry,
    'group',
    group => {
      const groupOptions = parseAndFix(group);
      if (Array.isArray(groupOptions)) {
        if (groupOptions.length > 0) {
          const vr = validateAll(groupOptions, groupOptionsChecker);
          if (vr.valid)
            return mergeResults([
              wrapLoadOptions({
                group: groupOptions
              }),
              check(
                qry,
                'requireGroupCount',
                requireGroupCount =>
                  requireGroupCount
                    ? {
                        requireGroupCount
                      }
                    : null,
                requireGroupCount => representsTrue(requireGroupCount)
              ),
              check(qry, 'groupSummary', groupSummary => {
                const gsOptions = parseAndFix(groupSummary);
                if (Array.isArray(gsOptions)) {
                  if (gsOptions.length > 0) {
                    const vr = validateAll(gsOptions, summaryOptionsChecker);
                    if (vr.valid)
                      return {
                        groupSummary: gsOptions
                      };
                    else
                      throw new Error(
                        `Group summary parameter validation errors: ${JSON.stringify(
                          vr.errors
                        )}`
                      );
                  } else return {}; // ignore empty array
                } else return null;
              })
            ]);
          else
            throw new Error(
              `Group parameter validation errors: ${JSON.stringify(vr.errors)}`
            );
        } else return {}; // ignore empty array
      } else return null;
    },
    undefined,
    undefined,
    o => o /* deactivate wrapper for the result */
  );
}

function totalSummaryOptions(qry) {
  return check(qry, 'totalSummary', totalSummary => {
    const tsOptions = parseAndFix(totalSummary);
    if (Array.isArray(tsOptions)) {
      if (tsOptions.length > 0) {
        const vr = validateAll(tsOptions, summaryOptionsChecker);
        if (vr.valid)
          return {
            totalSummary: tsOptions
          };
        else
          throw new Error(
            `Total summary parameter validation errors: ${JSON.stringify(
              vr.errors
            )}`
          );
      } else return {}; // ignore empty array
    } else return null;
  });
}

function filterOptions(qry) {
  return check(qry, 'filter', filter => {
    const filterOptions = parseAndFix(filter);
    if (typeof filterOptions === 'string' || Array.isArray(filterOptions))
      return {
        filter: filterOptions
      };
    else return null;
  });
}

function searchOptions(qry) {
  return check(
    qry,
    ['searchExpr', 'searchOperation', 'searchValue'],
    (se, so, sv) => {
      if (typeof se === 'string' || Array.isArray(se))
        return {
          searchExpr: se,
          searchOperation: so,
          searchValue: sv
        };
      else return null;
    }
  );
}

function selectOptions(qry) {
  return check(qry, 'select', select => {
    const selectOptions = parseAndFix(select);
    if (typeof selectOptions === 'string')
      return {
        select: [selectOptions]
      };
    else if (Array.isArray(selectOptions)) {
      if (selectOptions.length > 0) {
        if (selectOptions.reduce((r, v) => r && typeof v === 'string'))
          return {
            select: selectOptions
          };
        else
          throw new Error(
            `Select array parameter has invalid content: ${JSON.stringify(
              selectOptions
            )}`
          );
      } else return {}; // ignore empty array
    } else return null;
  });
}

function timezoneOptions(qry) {
  return check(
    qry,
    'tzOffset',
    tzOffset => ({
      timezoneOffset: parseInt(tzOffset) || 0
    }),
    v => v,
    {
      timezoneOffset: 0
    },
    wrapProcessingOptions
  );
}

function summaryQueryLimitOptions(qry) {
  return check(
    qry,
    'summaryQueryLimit',
    sql =>
      sql >= 0
        ? {
            summaryQueryLimit: sql
          }
        : {},
    sql => parseInt(sql),
    {},
    wrapProcessingOptions
  );
}

function mergeResults(results) {
  return results.reduce(
    (r, v) => ({
      loadOptions: {
        ...(r.loadOptions || {}),
        ...(v.loadOptions || {})
      },
      processingOptions: {
        ...(r.processingOptions || {}),
        ...(v.processingOptions || {})
      },
      errors: [...(r.errors || []), ...(v.errors || [])]
    }),
    {}
  );
}

function getOptions(qry, schema) {
  if (!qry) return undefined;

  const fixedQry = schema ? fixFilterAndSearch(schema)(qry) : qry;

  // console.log('Fixed query: ', JSON.stringify(fixedQry, null, 2));

  return mergeResults(
    [
      takeOptions,
      skipOptions,
      totalCountOptions,
      sortOptions,
      groupOptions,
      totalSummaryOptions,
      filterOptions,
      searchOptions,
      selectOptions,
      timezoneOptions,
      summaryQueryLimitOptions
    ].map(f => f(fixedQry))
  );
}

module.exports = {
  getOptions,
  private: {
    fixFilterAndSearch
  }
};
<|endoftext|>


<commit_before>(function($){
    // Restores select box state to saved value from localStorage.
    function restoreOptions() {
        $("#gitlabPath").val(config.getGitlabPath());
        $("#apiPath").val(config.getApiPath());
        $("#privateToken").val(config.getPrivateToken());
        $("#pollingSecond").val(config.getPollingSecond());
        $("#maxEventCount").val(config.getMaxEventCount());
        $("#maxNotificationCount").val(config.getMaxNotificationCount());
        $("#newMarkMinute").val(config.getNewMarkMinute());
    }

    // Saves options to localStorage.
    function saveOptions(){
        var projects = {};
        $("#projects tr.project").each(function(){
            var project_id = parseInt($(this).attr("id"));

            var project = {name: $("#" + project_id + " td.name").text(), events: {}}
            $.each(gitlab.events(), function(index, event){
                project.events[event] = util.isChecked("#" + project_id + " td." + event + " input:checkbox");
            });
            projects[project_id] = project;
        });

        config.save({
            gitlabPath:           $("#gitlabPath").val(),
            apiPath:              $("#apiPath").val(),
            privateToken:         $("#privateToken").val(),
            pollingSecond:        $("#pollingSecond").val(),
            maxEventCount:        $("#maxEventCount").val(),
            maxNotificationCount: $("#maxNotificationCount").val(),
            newMarkMinute:        $("#newMarkMinute").val(),
            projects:             projects
        });

        showStatus("Options Saved.");
    }

    function showStatus(status){
        $("span.status").text(status);
        setTimeout(function() {
            $("span.status").text("");
        }, 750);
    }

    function refreshProjects(){
        $("#projects").empty();

        if(config.getPrivateToken().length > 0){
            gitlab.getProjects(function(project){
                var tr = $("<tr/>").attr({id: project.id}).addClass("project");

                var project_url = config.getGitlabPath() + project.path_with_namespace;

                $("<td/>").addClass("name").append(
                    $("<a/>").attr({href: project_url}).text(project.path_with_namespace)
                ).appendTo(tr);

                var project = config.getProject(project.id);
                var events = gitlab.events();

                for(var i = 0; i < events.length; i++){
                    var event = events[i];
                    var checked = project.events[event] || false;

                    var label = $("<label/>").addClass("checkbox-inline");
                    $("<input/>").attr({type: "checkbox", checked: checked}).appendTo(label);
                    util.createEventIcon(event).appendTo(label);
                    $("<span/>").text(event).appendTo(label);
                    $("<td/>").addClass(event).append(label).appendTo(tr);
                }

                tr.appendTo( $("#projects") );
            });
        }
    }

    function clearCache(){
        config.clearCache();
        showStatus("Cache cleared");
    }

    $(document).ready(function(){
        if(!chrome){
            return;
        }

        restoreOptions();
        refreshProjects();

        $("button.save").click(function(){
            saveOptions();
        });

        $("button.clear").click(function(){
            clearCache();
            refreshProjects();
        });

        $("#load_repository").click(function(){
            saveOptions();
            refreshProjects();
        });
    });
})(jQuery);
<commit_msg>Modify: codeclimate<commit_after>(function($){
    // Restores select box state to saved value from localStorage.
    function restoreOptions() {
        $("#gitlabPath").val(config.getGitlabPath());
        $("#apiPath").val(config.getApiPath());
        $("#privateToken").val(config.getPrivateToken());
        $("#pollingSecond").val(config.getPollingSecond());
        $("#maxEventCount").val(config.getMaxEventCount());
        $("#maxNotificationCount").val(config.getMaxNotificationCount());
        $("#newMarkMinute").val(config.getNewMarkMinute());
    }

    // Saves options to localStorage.
    function saveOptions(){
        var projects = {};
        $("#projects tr.project").each(function(){
            var project_id = parseInt($(this).attr("id"));

            var project = {name: $("#" + project_id + " td.name").text(), events: {}};
            $.each(gitlab.events(), function(index, event){
                project.events[event] = util.isChecked("#" + project_id + " td." + event + " input:checkbox");
            });
            projects[project_id] = project;
        });

        config.save({
            gitlabPath:           $("#gitlabPath").val(),
            apiPath:              $("#apiPath").val(),
            privateToken:         $("#privateToken").val(),
            pollingSecond:        $("#pollingSecond").val(),
            maxEventCount:        $("#maxEventCount").val(),
            maxNotificationCount: $("#maxNotificationCount").val(),
            newMarkMinute:        $("#newMarkMinute").val(),
            projects:             projects
        });

        showStatus("Options Saved.");
    }

    function showStatus(status){
        $("span.status").text(status);
        setTimeout(function() {
            $("span.status").text("");
        }, 750);
    }

    function refreshProjects(){
        $("#projects").empty();

        if(config.getPrivateToken().length > 0){
            gitlab.getProjects(function(project){
                var tr = $("<tr/>").attr({id: project.id}).addClass("project");

                var project_url = config.getGitlabPath() + project.path_with_namespace;

                $("<td/>").addClass("name").append(
                    $("<a/>").attr({href: project_url}).text(project.path_with_namespace)
                ).appendTo(tr);

                var project_option = config.getProject(project.id);
                var events = gitlab.events();

                for(var i = 0; i < events.length; i++){
                    var event = events[i];
                    var checked = project_option.events[event] || false;

                    var label = $("<label/>").addClass("checkbox-inline");
                    $("<input/>").attr({type: "checkbox", checked: checked}).appendTo(label);
                    util.createEventIcon(event).appendTo(label);
                    $("<span/>").text(event).appendTo(label);
                    $("<td/>").addClass(event).append(label).appendTo(tr);
                }

                tr.appendTo( $("#projects") );
            });
        }
    }

    function clearCache(){
        config.clearCache();
        showStatus("Cache cleared");
    }

    $(document).ready(function(){
        if(!chrome){
            return;
        }

        restoreOptions();
        refreshProjects();

        $("button.save").click(function(){
            saveOptions();
        });

        $("button.clear").click(function(){
            clearCache();
            refreshProjects();
        });

        $("#load_repository").click(function(){
            saveOptions();
            refreshProjects();
        });
    });
})(jQuery);
<|endoftext|>