<commit_before>/******************************************************************************

Copyright (c) 2016, Highsoft

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.

******************************************************************************/

/** An editable field
 *
 *  Creates a table row with thre columns:
 *    - label
 *    - widget
 *    - help icon
 *
 *  @example
 *  //Create a table, append to body, add a color picker to it.
 *  highed.dom.ap(document.body,
 *      highed.dom.ap(highed.dom.cr('table'),
 *          highed.InspectorField('color', '#FFF', {
 *              title: 'Set the color!'
 *          }, function (newValue) {
 *              highed.dom.style(document.body, {
 *                  backgroundColor: newValue
 *              });
 *          })
 *      )
 *  );
 *
 *  @param type {enum} - the type of widget to use
 *    > string
 *    > number
 *    > range
 *    > boolean
 *    > color
 *    > font
 *    > options
 *    > object
 *  @param value {anything} - the current value of the field
 *  @param properties {object} - the properties for the widget
 *  @param fn {function} - the function to call when the field is changed
 *     > {anything} - the changed value
 *  @param nohint {boolean} - if true, the help icon will be skipped
 *  @param fieldID {anything} - the id of the field
 *  @returns {domnode} - a DOM node containing the field + label wrapped in a tr
 */
highed.InspectorField = function (type, value, properties, fn, nohint, fieldID) {
    var
        fields = {
            string: function (val, callback) {
                var input = highed.dom.cr('input', 'highed-field-input', '', fieldID);

                highed.dom.on(input, 'change', function (e) {
                    tryCallback(callback, input.value);
                    e.cancelBubble = true;
                });

                input.value = val || value;

                return input;
            },
            number: function (val, callback) {
                var input = highed.dom.cr('input', 'highed-field-input', '', fieldID);

                input.type = 'number';

                if (!highed.isNull(properties.custom)) {
                    input.step = properties.custom.step;
                    input.min = properties.custom.minValue;
                    input.max = properties.custom.maxValue;
                }

                highed.dom.on(input, 'change', function () {
                    tryCallback(callback, parseFloat(input.value));
                });

                input.value = val || value;

                return input;
            },
            range: function (val, callback) {
                var slider = highed.Slider(false, {
                    min: properties.custom.minValue,
                    max: properties.custom.maxValue,
                    step: properties.custom.step,
                    resetTo: val || value
                });

                slider.on('Change', function (v) {
                    tryCallback(callback, v);
                });

                return slider.container;
                // var f = highed.dom.cr('input', 'highed-field-input', '', fieldID),
                //     indicator = highed.dom.cr('div', 'highed-field-range-indicator', ' '),
                //     nullIt = highed.dom.cr('span', 'highed-icon highed-field-range-null fa fa-undo', '')
                // ;

                // f.className = 'highed-field-range';
                // f.type = 'range';
                // f.step = properties.custom.step;
                // f.min = properties.custom.minValue;
                // f.max = properties.custom.maxValue;

                // highed.dom.on(f, 'input', function () {
                //     indicator.innerHTML = f.value;
                // });

                // highed.dom.on(f, 'change', function () {
                //     tryCallback(callback, f.value);
                // });

                // if ((val || value) === null || ((val || value)) === 'null') {
                //     indicator.innerHTML = 'auto';
                // } else if (!highed.isNull(val || value)) {
                //     indicator.innerHTML = val || value;
                // } else {
                //     indicator.innerHTML = ' ';
                // }

                // f.value = val || value;

                // highed.dom.on(nullIt, 'click', function () {
                //     f.value = 0;
                //     indicator.innerHTML = 'auto';
                //     tryCallback(callback, null);
                // });

                // return [f, indicator, nullIt];
            },
            boolean: function (val, callback) {
                var input = highed.dom.cr('input', '', '', fieldID);
                input.type = 'checkbox';

                input.checked = highed.toBool(val || value);

                highed.dom.on(input, 'change', function () {
                    tryCallback(callback, input.checked);
                });

                return input;
            },
            color: function (val, callback) {
                var box = highed.dom.cr('div', 'highed-field-colorpicker', '', fieldID);

                function update(col, callback) {
                    box.innerHTML = col;
                    highed.dom.style(box, {
                        background: col,
                        color: highed.getContrastedColor(col)
                    });
                }

                highed.dom.on(box, 'click', function (e) {
                    highed.pickColor(e.clientX, e.clientY, val || value, function (col) {
                        update(col);
                        tryCallback(callback, col);
                    });
                });

                update(val || value);

                return box;
            },
            font: function (val, callback) {
                return fields.string(val, callback);

            },
            configset: function (val, callback) {
                return fields.string(val, callback);
            },
            cssobject: function (val, callback) {
                var picker = highed.FontPicker(callback || fn, val || value);
                return picker.container;
            },
            options: function (val, callback) {
                // var options = highed.dom.cr('select', 'highed-field-select', '', fieldID);

                // highed.dom.options(options, properties.values);

                // highed.dom.val(options, val || value);

                // highed.dom.on(options, 'change', function () {
                //     tryCallback(callback, highed.dom.val(options));
                // });

                var ddown = highed.DropDown();

                if (highed.isStr(properties.values)) {
                    try {
                        properties.values = JSON.parse(properties.values);
                    } catch (e) {
                        properties.values = properties.values.split(' ');
                    }
                }

                ddown.addItems(properties.values);

                 ddown.selectById(val || value);

                ddown.on('Change', function (selected) {
                    tryCallback(callback, selected.id());
                    console.log('options changed');
                });

                return ddown.container;
            },
            object: function (val, callback) {
                //Create a sub-table of options
                var stable = highed.dom.cr('table', 'highed-customizer-table', '', fieldID),
                    wasUndefined = highed.isNull(val || value)
                ;

                val = val || {};

                if (properties && highed.isArr(properties.attributes)) {
                    properties.attributes.forEach(function (attr) {

                        val[attr.name] = val[attr.name] || attr.defaults || (attr.dataType.indexOf('object') >= 0 ? {} : '');

                        attr.title = highed.uncamelize(attr.title);

                        highed.dom.ap(stable,
                            highed.InspectorField(
                                attr.dataType,
                                val[attr.name],
                                attr,
                                function (nval) {
                                    val[attr.name] = nval;
                                    tryCallback(callback, val);
                                }
                            )
                        );
                    });
                }

                if (wasUndefined) {
                    tryCallback(callback, val);
                }

                return stable;
            },
            array: function () {
                var container = highed.dom.cr('div', '', '', fieldID),
                    add = highed.dom.cr('span', 'highed-field-array-add fa fa-plus', ''),
                    itemsNode = highed.dom.cr('div', 'highed-inline-blocks'),
                    items = {},
                    itemCounter = 0,
                    itemTable = highed.dom.cr('table', 'highed-field-table')
                ;

                if (highed.isStr(value)) {
                    try {
                        value = JSON.parse(value);
                    } catch (e) {

                    }
                }

                function addCompositeItem(val, supressCallback) {
                    var item,
                        rem = highed.dom.cr('span', 'highed-icon fa fa-trash'),
                        row = highed.dom.cr('tr'),
                        id = ++itemCounter
                    ;

                    function processChange(newVal) {
                        if (newVal) {
                            items[id].value = newVal;
                            doEmitCallback();
                        }
                    }

                    function doEmitCallback() {
                        if (highed.isFn(fn)) {
                            fn(Object.keys(items).map(function (key) {
                                return items[key].value;
                            }));
                        }
                    }

                    items[id] = {
                        id: id,
                        row: row,
                        value: val
                    };

                    item = fields[properties.subType] ?
                           fields[properties.subType](val, processChange) :
                           fields.string(val, processChange);

                    highed.dom.ap(itemTable,
                        highed.dom.ap(row,
                            highed.dom.ap(highed.dom.cr('td'),
                                item
                            ),
                            highed.dom.ap(highed.dom.cr('td'),
                                rem
                            )
                        )
                    );

                    highed.dom.on(rem, 'click', function (e) {
                        delete items[id];
                        itemTable.removeChild(row);

                        doEmitCallback();

                        e.cancelBubble = true;
                        e.preventDefault();
                        e.stopPropagation();
                        e.stopImmediatePropagation();
                        return false;
                    });

                    if (!supressCallback) {
                        processChange();
                    }
                }

                highed.dom.ap(container, itemTable);

                highed.dom.on(add, 'click', function () {
                    addCompositeItem();
                });

                if (highed.isStr(value)) {
                    value = value.split(',');
                }

                if (highed.isArr(value)) {
                    value.forEach(function (item) {
                        addCompositeItem(item, true);
                    });
                }

                highed.dom.ap(container, itemsNode, add);

                return container;
            }
        },
        help = highed.dom.cr('span', 'highed-icon fa fa-question-circle'),
        helpTD = highed.dom.cr('td'),
        widgetTD = highed.dom.cr('td', 'highed-field-table-widget-column'),
        titleCol = highed.dom.cr('td'),
        typeIndicator = highed.dom.cr('span', 'highed-customize-type')
    ;

    function tryCallback(cb, val) {
        cb = cb || fn;
        if (highed.isFn(cb)) {
            cb(val);
        }
    }

    if (highed.isNull(value)) {
        value = '';
    }

    //Choose a type
    if (type && type.indexOf('|') >= 0) {
        type = type.indexOf('object') >= 0 ? 'object' : type.split('|')[0];
    }

    if (!highed.isNull(properties.custom) &&
        !highed.isNull(properties.custom.minValue) &&
        !highed.isNull(properties.custom.maxValue) &&
        !highed.isNull(properties.custom.step)) {
        type = 'range';
    }

    if (type && type.indexOf('array') === 0) {
        properties.subType = type.substr(6, type.length - 7);
        type = 'array';
    }

    if (type === 'object') {
        nohint = true;
    }

    highed.dom.on([help], 'mouseover', function (e) {
        highed.Tooltip(e.clientX, e.clientY, properties.tooltip || properties.tooltipText);
    });

    highed.dom.on(help, 'touchstart', function () {
        highed.Tooltip(0, 0, properties.tooltip || properties.tooltipText, true);
    });

    if (nohint) {
        highed.dom.style(help, {display: 'none'});
        widgetTD.colSpan = 2;
    }

    typeIndicator.className += ' highed-customize-type-' + type;

    return highed.dom.ap(
        highed.dom.ap(highed.dom.cr('tr'),
            highed.dom.ap(titleCol,
                highed.dom.cr('span', 'highed-customize-field-label', properties.title),
                typeIndicator
            ),
            highed.dom.ap(widgetTD,
                fields[type] ? fields[type]() : fields.string()
            ),
            (!nohint ?
             highed.dom.ap(helpTD,
                 //highed.dom.cr('span', 'highed-field-tooltip', properties.tooltip)
                 help
            ) : false)
        )
    );
};
<commit_msg>Fixed recursion madness<commit_after>/******************************************************************************

Copyright (c) 2016, Highsoft

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.

******************************************************************************/

/** An editable field
 *
 *  Creates a table row with thre columns:
 *    - label
 *    - widget
 *    - help icon
 *
 *  @example
 *  //Create a table, append to body, add a color picker to it.
 *  highed.dom.ap(document.body,
 *      highed.dom.ap(highed.dom.cr('table'),
 *          highed.InspectorField('color', '#FFF', {
 *              title: 'Set the color!'
 *          }, function (newValue) {
 *              highed.dom.style(document.body, {
 *                  backgroundColor: newValue
 *              });
 *          })
 *      )
 *  );
 *
 *  @param type {enum} - the type of widget to use
 *    > string
 *    > number
 *    > range
 *    > boolean
 *    > color
 *    > font
 *    > options
 *    > object
 *  @param value {anything} - the current value of the field
 *  @param properties {object} - the properties for the widget
 *  @param fn {function} - the function to call when the field is changed
 *     > {anything} - the changed value
 *  @param nohint {boolean} - if true, the help icon will be skipped
 *  @param fieldID {anything} - the id of the field
 *  @returns {domnode} - a DOM node containing the field + label wrapped in a tr
 */
highed.InspectorField = function (type, value, properties, fn, nohint, fieldID) {
    var
        fields = {
            string: function (val, callback) {
                var input = highed.dom.cr('input', 'highed-field-input', '', fieldID);

                highed.dom.on(input, 'change', function (e) {
                    tryCallback(callback, input.value);
                    e.cancelBubble = true;
                });

                input.value = val || value;

                return input;
            },
            number: function (val, callback) {
                var input = highed.dom.cr('input', 'highed-field-input', '', fieldID);

                input.type = 'number';

                if (!highed.isNull(properties.custom)) {
                    input.step = properties.custom.step;
                    input.min = properties.custom.minValue;
                    input.max = properties.custom.maxValue;
                }

                highed.dom.on(input, 'change', function () {
                    tryCallback(callback, parseFloat(input.value));
                });

                input.value = val || value;

                return input;
            },
            range: function (val, callback) {
                var slider = highed.Slider(false, {
                    min: properties.custom.minValue,
                    max: properties.custom.maxValue,
                    step: properties.custom.step,
                    resetTo: val || value
                });

                slider.on('Change', function (v) {
                    tryCallback(callback, v);
                });

                return slider.container;
                // var f = highed.dom.cr('input', 'highed-field-input', '', fieldID),
                //     indicator = highed.dom.cr('div', 'highed-field-range-indicator', ' '),
                //     nullIt = highed.dom.cr('span', 'highed-icon highed-field-range-null fa fa-undo', '')
                // ;

                // f.className = 'highed-field-range';
                // f.type = 'range';
                // f.step = properties.custom.step;
                // f.min = properties.custom.minValue;
                // f.max = properties.custom.maxValue;

                // highed.dom.on(f, 'input', function () {
                //     indicator.innerHTML = f.value;
                // });

                // highed.dom.on(f, 'change', function () {
                //     tryCallback(callback, f.value);
                // });

                // if ((val || value) === null || ((val || value)) === 'null') {
                //     indicator.innerHTML = 'auto';
                // } else if (!highed.isNull(val || value)) {
                //     indicator.innerHTML = val || value;
                // } else {
                //     indicator.innerHTML = ' ';
                // }

                // f.value = val || value;

                // highed.dom.on(nullIt, 'click', function () {
                //     f.value = 0;
                //     indicator.innerHTML = 'auto';
                //     tryCallback(callback, null);
                // });

                // return [f, indicator, nullIt];
            },
            boolean: function (val, callback) {
                var input = highed.dom.cr('input', '', '', fieldID);
                input.type = 'checkbox';

                input.checked = highed.toBool(val || value);

                highed.dom.on(input, 'change', function () {
                    tryCallback(callback, input.checked);
                });

                return input;
            },
            color: function (val, callback) {
                var box = highed.dom.cr('div', 'highed-field-colorpicker', '', fieldID);

                function update(col, callback) {
                    box.innerHTML = col;
                    highed.dom.style(box, {
                        background: col,
                        color: highed.getContrastedColor(col)
                    });
                }

                highed.dom.on(box, 'click', function (e) {
                    highed.pickColor(e.clientX, e.clientY, val || value, function (col) {
                        update(col);
                        tryCallback(callback, col);
                    });
                });

                update(val || value);

                return box;
            },
            font: function (val, callback) {
                return fields.string(val, callback);

            },
            configset: function (val, callback) {
                return fields.string(val, callback);
            },
            cssobject: function (val, callback) {
                var picker = highed.FontPicker(callback || fn, val || value);
                return picker.container;
            },
            options: function (val, callback) {
                // var options = highed.dom.cr('select', 'highed-field-select', '', fieldID);

                // highed.dom.options(options, properties.values);

                // highed.dom.val(options, val || value);

                // highed.dom.on(options, 'change', function () {
                //     tryCallback(callback, highed.dom.val(options));
                // });

                var ddown = highed.DropDown();

                if (highed.isStr(properties.values)) {
                    try {
                        properties.values = JSON.parse(properties.values);
                    } catch (e) {
                        properties.values = properties.values.split(' ');
                    }
                }

                ddown.addItems(properties.values);

                 ddown.selectById(val || value);

                ddown.on('Change', function (selected) {
                    tryCallback(callback, selected.id());
                    console.log('options changed');
                });

                return ddown.container;
            },
            object: function (val, callback) {
                //Create a sub-table of options
                var stable = highed.dom.cr('table', 'highed-customizer-table', '', fieldID),
                    wasUndefined = highed.isNull(val || value)
                ;

                val = val || {};

                if (properties && highed.isArr(properties.attributes)) {
                    properties.attributes.forEach(function (attr) {

                        val[attr.name] = val[attr.name] || attr.defaults || (attr.dataType.indexOf('object') >= 0 ? {} : '');

                        attr.title = highed.uncamelize(attr.title);

                        highed.dom.ap(stable,
                            highed.InspectorField(
                                attr.dataType,
                                val[attr.name],
                                attr,
                                function (nval) {
                                    val[attr.name] = nval;
                                    tryCallback(callback, val);
                                }
                            )
                        );
                    });
                }

                if (wasUndefined) {
                    tryCallback(callback, val);
                }

                return stable;
            },
            array: function () {
                var container = highed.dom.cr('div', '', '', fieldID),
                    add = highed.dom.cr('span', 'highed-field-array-add fa fa-plus', ''),
                    itemsNode = highed.dom.cr('div', 'highed-inline-blocks'),
                    items = {},
                    itemCounter = 0,
                    itemTable = highed.dom.cr('table', 'highed-field-table')
                ;

                if (highed.isStr(value)) {
                    try {
                        value = JSON.parse(value);
                    } catch (e) {

                    }
                }

                function addCompositeItem(val, supressCallback) {
                    var item,
                        rem = highed.dom.cr('span', 'highed-icon fa fa-trash'),
                        row = highed.dom.cr('tr'),
                        id = ++itemCounter
                    ;

                    function processChange(newVal) {
                        if (newVal) {
                            items[id].value = newVal;
                            doEmitCallback();
                        }
                    }

                    function doEmitCallback() {
                        if (highed.isFn(fn)) {
                            fn(Object.keys(items).map(function (key) {
                                return items[key].value;
                            }));
                        }
                    }

                    items[id] = {
                        id: id,
                        row: row,
                        value: val
                    };

                    item = fields[properties.subType] ?
                           fields[properties.subType](val, processChange) :
                           fields.string(val, processChange);

                    highed.dom.ap(itemTable,
                        highed.dom.ap(row,
                            highed.dom.ap(highed.dom.cr('td'),
                                item
                            ),
                            highed.dom.ap(highed.dom.cr('td'),
                                rem
                            )
                        )
                    );

                    highed.dom.on(rem, 'click', function (e) {
                        delete items[id];
                        itemTable.removeChild(row);

                        doEmitCallback();

                        e.cancelBubble = true;
                        e.preventDefault();
                        e.stopPropagation();
                        e.stopImmediatePropagation();
                        return false;
                    });

                    if (!supressCallback) {
                        processChange();
                    }
                }

                highed.dom.ap(container, itemTable);

                highed.dom.on(add, 'click', function () {
                    addCompositeItem();
                });

                if (highed.isArr(value)) {
                    value.forEach(function (item) {
                        addCompositeItem(item, true);
                    });
                }

                highed.dom.ap(container, itemsNode, add);

                return container;
            }
        },
        help = highed.dom.cr('span', 'highed-icon fa fa-question-circle'),
        helpTD = highed.dom.cr('td'),
        widgetTD = highed.dom.cr('td', 'highed-field-table-widget-column'),
        titleCol = highed.dom.cr('td'),
        typeIndicator = highed.dom.cr('span', 'highed-customize-type')
    ;

    function tryCallback(cb, val) {
        cb = cb || fn;
        if (highed.isFn(cb)) {
            cb(val);
        }
    }

    if (highed.isNull(value)) {
        value = '';
    }

    //Choose a type
    if (type && type.indexOf('|') >= 0) {
        type = type.indexOf('object') >= 0 ? 'object' : type.split('|')[0];
    }

    if (!highed.isNull(properties.custom) &&
        !highed.isNull(properties.custom.minValue) &&
        !highed.isNull(properties.custom.maxValue) &&
        !highed.isNull(properties.custom.step)) {
        type = 'range';
    }

    if (type && type.indexOf('array') === 0) {
        properties.subType = type.substr(6, type.length - 7);
        type = 'array';
    }

    if (type === 'object') {
        nohint = true;
    }

    highed.dom.on([help], 'mouseover', function (e) {
        highed.Tooltip(e.clientX, e.clientY, properties.tooltip || properties.tooltipText);
    });

    highed.dom.on(help, 'touchstart', function () {
        highed.Tooltip(0, 0, properties.tooltip || properties.tooltipText, true);
    });

    if (nohint) {
        highed.dom.style(help, {display: 'none'});
        widgetTD.colSpan = 2;
    }

    typeIndicator.className += ' highed-customize-type-' + type;

    return highed.dom.ap(
        highed.dom.ap(highed.dom.cr('tr'),
            highed.dom.ap(titleCol,
                highed.dom.cr('span', 'highed-customize-field-label', properties.title),
                typeIndicator
            ),
            highed.dom.ap(widgetTD,
                fields[type] ? fields[type]() : fields.string()
            ),
            (!nohint ?
             highed.dom.ap(helpTD,
                 //highed.dom.cr('span', 'highed-field-tooltip', properties.tooltip)
                 help
            ) : false)
        )
    );
};
<|endoftext|>


<commit_before>'use strict';
var forEachEntry = require('raptor-util/forEachEntry');
var ok = require('assert').ok;
var CustomTag;

function inheritProps(sub, sup) {
    forEachEntry(sup, function (k, v) {
        if (!sub[k]) {
            sub[k] = v;
        }
    });
}

function createCustomTagNodeFactory(tagDef) {
    return function nodeFactory(el) {
        return new CustomTag(el, tagDef);
    };
}

class Tag{
    constructor() {
        ok(arguments.length === 0);
        this.taglibId = null;
        this.taglibPath = null;
        this.name = undefined;
        this.renderer = null;
        this.codeGeneratorModulePath = null;
        this.nodeFactoryPath = null;
        this.template = null;
        this.attributes = {};
        this.transformers = {};
        this.nestedVariables = null;
        this.importedVariables = null;
        this.patternAttributes = [];
        this.bodyFunction = null;
        this.nestedTags = null;
        this.isRepeated = null;
        this.isNestedTag = false;
        this.parentTagName = null;
        this.openTagOnly = null;
        this.body = null;
        this.type = null; // Only applicable for nested tags
        this._nodeFactory = undefined;
    }

    inheritFrom(superTag) {
        var subTag = this;
        /*
         * Have the sub tag inherit any properties from the super tag that are not in the sub tag
         */
        forEachEntry(superTag, function (k, v) {
            if (subTag[k] === undefined) {
                subTag[k] = v;
            }
        });
        [
            'attributes',
            'transformers',
            'nestedVariables',
            'importedVariables',
            'bodyFunction'
        ].forEach(function (propName) {
            inheritProps(subTag[propName], superTag[propName]);
        });
        subTag.patternAttributes = superTag.patternAttributes.concat(subTag.patternAttributes);
    }

    forEachVariable(callback, thisObj) {
        if (!this.nestedVariables) {
            return;
        }

        this.nestedVariables.vars.forEach(callback, thisObj);
    }

    forEachImportedVariable(callback, thisObj) {
        if (!this.importedVariables) {
            return;
        }

        forEachEntry(this.importedVariables, function (key, importedVariable) {
            callback.call(thisObj, importedVariable);
        });
    }

    forEachTransformer(callback, thisObj) {
        forEachEntry(this.transformers, function (key, transformer) {
            callback.call(thisObj, transformer);
        });
    }
    hasTransformers() {
        /*jshint unused:false */
        for (var k in this.transformers) {
            if (this.transformers.hasOwnProperty(k)) {
                return true;
            }

        }
        return false;
    }
    addAttribute(attr) {
        attr.filePath = this.filePath;

        if (attr.pattern) {
            this.patternAttributes.push(attr);
        } else {
            if (attr.name === '*') {
                attr.dynamicAttribute = true;

                if (attr.targetProperty === null || attr.targetProperty === '') {
                    attr.targetProperty = null;

                }
                else if (!attr.targetProperty) {
                    attr.targetProperty = '*';
                }
            }

            this.attributes[attr.name] = attr;
        }
    }
    toString() {
        return '[Tag: <' + this.name + '@' + this.taglibId + '>]';
    }
    forEachAttribute(callback, thisObj) {
        for (var attrName in this.attributes) {
            if (this.attributes.hasOwnProperty(attrName)) {
                callback.call(thisObj, this.attributes[attrName]);
            }
        }
    }
    getAttribute(attrName) {
        var attributes = this.attributes;

        // try by exact match first
        var attribute = attributes[attrName] || attributes['*'];

        if (attribute === undefined && this.patternAttributes) {
            // try searching by pattern
            for (var i = 0, len = this.patternAttributes.length; i < len; i++) {
                var patternAttribute = this.patternAttributes[i];
                if (patternAttribute.pattern.test(attrName)) {
                    attribute = patternAttribute;
                    break;
                }
            }
        }

        return attribute;
    }
    addNestedVariable(nestedVariable) {
        if (!this.nestedVariables) {
            this.nestedVariables = {
                __noMerge: true,
                vars: []
            };
        }

        this.nestedVariables.vars.push(nestedVariable);
    }
    addImportedVariable(importedVariable) {
        if (!this.importedVariables) {
            this.importedVariables = {};
        }
        var key = importedVariable.targetProperty;
        this.importedVariables[key] = importedVariable;
    }
    addTransformer(transformer) {
        var key = transformer.path;
        transformer.taglibId = this.taglibId;
        this.transformers[key] = transformer;
    }
    setBodyFunction(name, params) {
        this.bodyFunction = {
            __noMerge: true,
            name: name,
            params: params
        };
    }
    setBodyProperty(propertyName) {
        this.bodyProperty = propertyName;
    }
    addNestedTag(nestedTag) {
        ok(nestedTag.name, '"nestedTag.name" is required');

        if (!this.nestedTags) {
            this.nestedTags = {};
        }

        nestedTag.isNestedTag = true;

        if (!nestedTag.targetProperty) {
            nestedTag.targetProperty = nestedTag.name;
        }

        this.nestedTags[nestedTag.name] = nestedTag;
    }
    forEachNestedTag(callback, thisObj) {
        if (!this.nestedTags) {
            return;
        }

        forEachEntry(this.nestedTags, function (key, nestedTag) {
            callback.call(thisObj, nestedTag);
        });
    }
    hasNestedTags() {
        return this.nestedTags != null;
    }
    getNodeFactory() {
        var nodeFactory = this._nodeFactory;
        if (nodeFactory !== undefined) {
            return nodeFactory;
        }

        let codeGeneratorModulePath = this.codeGeneratorModulePath;

        if (this.codeGeneratorModulePath) {
            var loadedCodeGenerator = require(this.codeGeneratorModulePath);
            nodeFactory = function(elNode) {
                elNode.setType(codeGeneratorModulePath);
                elNode.setCodeGenerator(loadedCodeGenerator);
                return elNode;
            };
        } else if (this.nodeFactoryPath) {
            nodeFactory = require(this.nodeFactoryPath);
            if (typeof nodeFactory !== 'function') {
                throw new Error('Invalid node factory exported by module at path "' + this.nodeFactoryPath + '"');
            }
        } else if (this.renderer || this.template || this.isNestedTag) {
            nodeFactory = createCustomTagNodeFactory(this);
        } else {
            return null;
        }

        return (this._nodeFactory = nodeFactory);
    }

    toJSON() {
        return this;
    }

    setTaglib(taglib) {
        this.taglibId = taglib ? taglib.id : null;
        this.taglibPath = taglib ? taglib.path : null;
    }
}

module.exports = Tag;

CustomTag = require('../ast/CustomTag');<commit_msg>remove Tag#inheritFrom. fixes #469<commit_after>'use strict';
var forEachEntry = require('raptor-util/forEachEntry');
var ok = require('assert').ok;
var CustomTag;

function createCustomTagNodeFactory(tagDef) {
    return function nodeFactory(el) {
        return new CustomTag(el, tagDef);
    };
}

class Tag{
    constructor() {
        ok(arguments.length === 0);
        this.taglibId = null;
        this.taglibPath = null;
        this.name = undefined;
        this.renderer = null;
        this.codeGeneratorModulePath = null;
        this.nodeFactoryPath = null;
        this.template = null;
        this.attributes = {};
        this.transformers = {};
        this.nestedVariables = null;
        this.importedVariables = null;
        this.patternAttributes = [];
        this.bodyFunction = null;
        this.nestedTags = null;
        this.isRepeated = null;
        this.isNestedTag = false;
        this.parentTagName = null;
        this.openTagOnly = null;
        this.body = null;
        this.type = null; // Only applicable for nested tags
        this._nodeFactory = undefined;
    }

    forEachVariable(callback, thisObj) {
        if (!this.nestedVariables) {
            return;
        }

        this.nestedVariables.vars.forEach(callback, thisObj);
    }

    forEachImportedVariable(callback, thisObj) {
        if (!this.importedVariables) {
            return;
        }

        forEachEntry(this.importedVariables, function (key, importedVariable) {
            callback.call(thisObj, importedVariable);
        });
    }

    forEachTransformer(callback, thisObj) {
        forEachEntry(this.transformers, function (key, transformer) {
            callback.call(thisObj, transformer);
        });
    }
    hasTransformers() {
        /*jshint unused:false */
        for (var k in this.transformers) {
            if (this.transformers.hasOwnProperty(k)) {
                return true;
            }

        }
        return false;
    }
    addAttribute(attr) {
        attr.filePath = this.filePath;

        if (attr.pattern) {
            this.patternAttributes.push(attr);
        } else {
            if (attr.name === '*') {
                attr.dynamicAttribute = true;

                if (attr.targetProperty === null || attr.targetProperty === '') {
                    attr.targetProperty = null;

                }
                else if (!attr.targetProperty) {
                    attr.targetProperty = '*';
                }
            }

            this.attributes[attr.name] = attr;
        }
    }
    toString() {
        return '[Tag: <' + this.name + '@' + this.taglibId + '>]';
    }
    forEachAttribute(callback, thisObj) {
        for (var attrName in this.attributes) {
            if (this.attributes.hasOwnProperty(attrName)) {
                callback.call(thisObj, this.attributes[attrName]);
            }
        }
    }
    getAttribute(attrName) {
        var attributes = this.attributes;

        // try by exact match first
        var attribute = attributes[attrName] || attributes['*'];

        if (attribute === undefined && this.patternAttributes) {
            // try searching by pattern
            for (var i = 0, len = this.patternAttributes.length; i < len; i++) {
                var patternAttribute = this.patternAttributes[i];
                if (patternAttribute.pattern.test(attrName)) {
                    attribute = patternAttribute;
                    break;
                }
            }
        }

        return attribute;
    }
    addNestedVariable(nestedVariable) {
        if (!this.nestedVariables) {
            this.nestedVariables = {
                __noMerge: true,
                vars: []
            };
        }

        this.nestedVariables.vars.push(nestedVariable);
    }
    addImportedVariable(importedVariable) {
        if (!this.importedVariables) {
            this.importedVariables = {};
        }
        var key = importedVariable.targetProperty;
        this.importedVariables[key] = importedVariable;
    }
    addTransformer(transformer) {
        var key = transformer.path;
        transformer.taglibId = this.taglibId;
        this.transformers[key] = transformer;
    }
    setBodyFunction(name, params) {
        this.bodyFunction = {
            __noMerge: true,
            name: name,
            params: params
        };
    }
    setBodyProperty(propertyName) {
        this.bodyProperty = propertyName;
    }
    addNestedTag(nestedTag) {
        ok(nestedTag.name, '"nestedTag.name" is required');

        if (!this.nestedTags) {
            this.nestedTags = {};
        }

        nestedTag.isNestedTag = true;

        if (!nestedTag.targetProperty) {
            nestedTag.targetProperty = nestedTag.name;
        }

        this.nestedTags[nestedTag.name] = nestedTag;
    }
    forEachNestedTag(callback, thisObj) {
        if (!this.nestedTags) {
            return;
        }

        forEachEntry(this.nestedTags, function (key, nestedTag) {
            callback.call(thisObj, nestedTag);
        });
    }
    hasNestedTags() {
        return this.nestedTags != null;
    }
    getNodeFactory() {
        var nodeFactory = this._nodeFactory;
        if (nodeFactory !== undefined) {
            return nodeFactory;
        }

        let codeGeneratorModulePath = this.codeGeneratorModulePath;

        if (this.codeGeneratorModulePath) {
            var loadedCodeGenerator = require(this.codeGeneratorModulePath);
            nodeFactory = function(elNode) {
                elNode.setType(codeGeneratorModulePath);
                elNode.setCodeGenerator(loadedCodeGenerator);
                return elNode;
            };
        } else if (this.nodeFactoryPath) {
            nodeFactory = require(this.nodeFactoryPath);
            if (typeof nodeFactory !== 'function') {
                throw new Error('Invalid node factory exported by module at path "' + this.nodeFactoryPath + '"');
            }
        } else if (this.renderer || this.template || this.isNestedTag) {
            nodeFactory = createCustomTagNodeFactory(this);
        } else {
            return null;
        }

        return (this._nodeFactory = nodeFactory);
    }

    toJSON() {
        return this;
    }

    setTaglib(taglib) {
        this.taglibId = taglib ? taglib.id : null;
        this.taglibPath = taglib ? taglib.path : null;
    }
}

module.exports = Tag;

CustomTag = require('../ast/CustomTag');<|endoftext|>


<commit_before>// ==UserScript==
// @name        ChatJax++
// @namespace   https://github.com/vyznev/
// @description Enable MathJax in Stack Exchange chat
// @author      Ilmari Karonen
// @version     0.1.4
// @copyright   2014, Ilmari Karonen (http://stackapps.com/users/10283/ilmari-karonen)
// @license     ISC; http://opensource.org/licenses/ISC
// @match       *://chat.stackexchange.com/*
// @grant       none
// ==/UserScript==

// Copyright (C) 2014 Ilmari Karonen.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// In addition to the license granted above, I, Ilmari Karonen, to the extent I
// am authorized to do so, and subject to the disclaimer stated above, hereby
// grant Stack Exchange, Inc. permission to make use of this software in any
// way they see fit, including but not limited to incorporating all or parts of
// it within the Stack Exchange codebase, with or without credit to myself.
// This permission grant does not extend to any code written by third parties,
// unless said parties also agree to it.

( function () {  // start of anonymous wrapper function (needed to restrict variable scope on Opera)

// Opera does not support @match, so re-check that we're on SE chat before doing anything
if ( location.hostname != 'chat.stackexchange.com' ) return;

// TODO: dynamically load config and MathJax URL from main site
var mathJaxURL = "//beta.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML-full";
var config = {
	"HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"], linebreaks: { automatic:true }, EqnChunk: 50 },
	tex2jax: { inlineMath: [ ["$", "$"], ["\\\\(","\\\\)"] ], displayMath: [ ["$$","$$"], ["\\[", "\\]"] ], processEscapes: true, ignoreClass: "tex2jax_ignore|dno" },
	TeX: {  noUndefined: { attributes: { mathcolor: "red", mathbackground: "#FFEEEE", mathsize: "90%" } }, Macros: { href: "{}" } },
	messageStyle: "none"
};
config.elements = ['main', 'content', 'starred-posts'];  // don't parse mathjax in sidebar, except for starred posts

// Chat polling code:
var chatJaxSetup = function () {
	if ( window.SOUP ) {
		// Great, we have SOUP!  Just use its chat monitoring feature:
		SOUP.hookChat( function ( json ) {
			try {
				if ( !window.MathJax || !window.CHAT ) return;
				var data = JSON.parse( json );
				var room = data['r' + CHAT.CURRENT_ROOM_ID];
				if ( !room || !room.e || !room.e.forEach ) return;

				var seen = {};
				room.e.forEach( function ( e ) {
					console.log( 'MathJax++ got event', e );
					var type = e.event_type;
					if ( !type || seen[type] ) return;
					seen[type] = true;

					if ( type == 1 || type == 2 || type == 20 ) {
						MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'message-' + e.message_id ] );
					}
					else if ( type == 6 ) setInterval( function () {
						// XXX: for some reason, starred posts need an extra delay :(
						MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'starred-posts'] );
					}, 10 );
				} );
			} catch (err) {
				console.log( "ChatJax++ event hook failed", err );
			}
		} );

		// re-typeset content loaded via AJAX to avoid race conditions
		SOUP.hookAjax( /^\/chats\/\d+\/events\b/, function () {
			window.MathJax && MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'main' ] );
		} );
		SOUP.hookAjax( /^\/chats\/stars\/\d+\b/, function () {
			window.MathJax && MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'starred-posts' ] );
		}, 10 );

		// also catch expansion of collapsed posts
		var urlRegexp = /^\/messages\/(\d+)\/(\d+)\b/;
		SOUP.hookAjax( urlRegexp, function ( event, xhr, settings ) {
			if ( !window.MathJax || !window.CHAT ) return;
			var match = urlRegexp.exec( settings.url );
			if ( !match || match[1] != CHAT.CURRENT_ROOM_ID ) return;
			MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'message-' + match[2] ] );
		} );
	}
	else console.log("ChatJax++: TODO: Implement non-SOUP functionality!");
};

// Inject MathJax config and chat polling code to page:
var configScript = document.createElement( 'script' );
configScript.type = 'text/x-mathjax-config';
configScript.textContent = "MathJax.Hub.Config(" + JSON.stringify(config) + ");\n(" + chatJaxSetup + ")();";
document.head.appendChild( configScript );

// Load MathJax itself:
var mathJaxScript = document.createElement( 'script' );
mathJaxScript.src = mathJaxURL;
document.head.appendChild( mathJaxScript );

} )();  // end of anonymous wrapper function
<commit_msg>fix crash due to use of config.elements; misc. tweaks<commit_after>// ==UserScript==
// @name        ChatJax++
// @namespace   https://github.com/vyznev/
// @description Enable MathJax in Stack Exchange chat
// @author      Ilmari Karonen
// @version     0.1.5
// @copyright   2014-2105, Ilmari Karonen (http://stackapps.com/users/10283/ilmari-karonen)
// @license     ISC; http://opensource.org/licenses/ISC
// @match       *://chat.stackexchange.com/*
// @grant       none
// ==/UserScript==

// Copyright (C) 2014 Ilmari Karonen.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// In addition to the license granted above, I, Ilmari Karonen, to the extent I
// am authorized to do so, and subject to the disclaimer stated above, hereby
// grant Stack Exchange, Inc. permission to make use of this software in any
// way they see fit, including but not limited to incorporating all or parts of
// it within the Stack Exchange codebase, with or without credit to myself.
// This permission grant does not extend to any code written by third parties,
// unless said parties also agree to it.

( function () {  // start of anonymous wrapper function (needed to restrict variable scope on Opera)

// Opera does not support @match, so re-check that we're on SE chat before doing anything
if ( location.hostname != 'chat.stackexchange.com' ) return;

// TODO: dynamically load config and MathJax URL from main site
var mathJaxURL = "//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML-full";
var config = {
	"HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"], linebreaks: { automatic:true }, EqnChunk: 50 },
	tex2jax: { inlineMath: [ ["$", "$"], ["\\\\(","\\\\)"] ], displayMath: [ ["$$","$$"], ["\\[", "\\]"] ], processEscapes: true, ignoreClass: "tex2jax_ignore|dno" },
	TeX: {  noUndefined: { attributes: { mathcolor: "red", mathbackground: "#FFEEEE", mathsize: "90%" } }, Macros: { href: "{}" } },
	messageStyle: "none"
};

// Chat polling code:
var chatJaxSetup = function () {
	if ( !window.MathJax || !window.CHAT ) return;
	if ( !window.SOUP ) {
		console.log("ChatJax++: TODO: Implement non-SOUP functionality!");
		return;
	}
	// Great, we have SOUP!  Just use its chat monitoring feature:
	SOUP.hookChat( function ( json ) {
		try {
			var data = JSON.parse( json );
			var room = data['r' + CHAT.CURRENT_ROOM_ID];
			if ( !room || !room.e || !room.e.forEach ) return;
			var seen = {};
			room.e.forEach( function ( e ) {
				console.log( 'MathJax++ got event', e );
				var id = null;
				switch ( e.event_type ) {
					case 1: case 2: case 20: id = 'message-' + e.message_id; break;
					case 6: id = 'starred-posts'; break;
				}
				if ( !id || seen[id] ) return;
				seen[id] = true;

				if ( id != 'starred-posts' ) {
					MathJax.Hub.Queue( ['Typeset', MathJax.Hub, id] );
				} else setInterval( function () {
					// XXX: for some reason, starred posts need an extra delay :(
					MathJax.Hub.Queue( ['Typeset', MathJax.Hub, id] );
				}, 10 );
			} );
		} catch (err) {
			console.log( "ChatJax++ event hook failed", err );
		}
	} );

	// re-typeset content loaded via AJAX to avoid race conditions
	SOUP.hookAjax( /^\/chats\/\d+\/events\b/, function () {
		MathJax.Hub.Queue( ['Typeset', MathJax.Hub ] );
	} );
	SOUP.hookAjax( /^\/chats\/stars\/\d+\b/, function () {
		MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'starred-posts' ] );
	}, 10 );

	// also catch expansion of collapsed posts
	var urlRegexp = /^\/messages\/(\d+)\/(\d+)\b/;
	SOUP.hookAjax( urlRegexp, function ( event, xhr, settings ) {
		var match = urlRegexp.exec( settings.url );
		if ( !match || match[1] != CHAT.CURRENT_ROOM_ID ) return;
		MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'message-' + match[2] ] );
	} );

	// don't parse MathJax in sidebar (except for starred posts)
	var sidebar = document.getElementById('sidebar');
	if (sidebar) sidebar.className += ' tex2jax_ignore';

	MathJax.Hub.Queue( ['Typeset', MathJax.Hub, 'starred-posts' ] );
};

// Inject MathJax config and chat polling code to page:
var configScript = document.createElement( 'script' );
configScript.type = 'text/x-mathjax-config';
configScript.textContent = "MathJax.Hub.Config(" + JSON.stringify(config) + ");\n(" + chatJaxSetup + ")();";
document.head.appendChild( configScript );

// Load MathJax itself:
var mathJaxScript = document.createElement( 'script' );
mathJaxScript.src = mathJaxURL;
document.head.appendChild( mathJaxScript );

} )();  // end of anonymous wrapper function
<|endoftext|>


<commit_before>const themeOptions = require('gatsby-theme-apollo-docs/theme-options');

module.exports = {
  pathPrefix: '/docs/react',
  plugins: [
    {
      resolve: 'gatsby-theme-apollo-docs',
      options: {
        ...themeOptions,
        root: __dirname,
        subtitle: 'Client (React)',
        description: 'A guide to using the Apollo GraphQL Client with React',
        githubRepo: 'apollographql/apollo-client',
        defaultVersion: 2.6,
        versions: {
          '3.0 beta': 'release-3.0',
          '2.6': 'version-2.6',
          '2.5': 'version-2.5',
          '2.4': 'version-2.4',
        },
        checkLinksOptions: {
          exceptions: [
            '/api/core/',
            '/v2.4/api/core/',
            '/v2.5/api/core/',
            '/v2.6/api/core/',
            '/v3.0/api/core/'
          ],
        },
        typescriptApiBox: {
          data: require('./docs.json'),
          filepathPrefix: 'src/',
        },
        sidebarCategories: {
          null: ['index', 'why-apollo', 'get-started'],
          'Fetching data': [
            'data/queries',
            'data/mutations',
            'data/local-state',
            'data/subscriptions',
            'data/pagination',
            'data/fragments',
            'data/error-handling',
          ],
          Caching: ['caching/cache-configuration', 'caching/cache-interaction'],
          'Development & Testing': [
            'development-testing/static-typing',
            'development-testing/testing',
            'development-testing/client-schema-mocking',
            'development-testing/developer-tooling',
          ],
          Performance: [
            'performance/performance',
            'performance/optimistic-ui',
            'performance/server-side-rendering',
            'performance/babel',
          ],
          Integrations: [
            'integrations/integrations',
            'integrations/react-native',
            'integrations/meteor',
            'integrations/webpack',
          ],
          Networking: [
            'networking/network-layer',
            'networking/authentication',
          ],
          'Apollo Client API': [
            'api/core',
            'api/react-hooks',
            'api/react-testing',
            'api/react-ssr',
            'api/react-components',
            'api/react-hoc'
          ],
          Migrating: ['migrating/hooks-migration', 'migrating/boost-migration'],
        },
      },
    },
  ],
};
<commit_msg>Disable all doc sets except for 2.6<commit_after>const themeOptions = require('gatsby-theme-apollo-docs/theme-options');

module.exports = {
  pathPrefix: '/docs/react',
  plugins: [
    {
      resolve: 'gatsby-theme-apollo-docs',
      options: {
        ...themeOptions,
        root: __dirname,
        subtitle: 'Client (React)',
        description: 'A guide to using the Apollo GraphQL Client with React',
        githubRepo: 'apollographql/apollo-client',
        defaultVersion: 2.6,
        versions: {
          '2.6': 'version-2.6',
        },
        /*
        versions: {
          '3.0 beta': 'release-3.0',
          '2.6': 'version-2.6',
          '2.5': 'version-2.5',
          '2.4': 'version-2.4',
        },
        */
        checkLinksOptions: {
          exceptions: [
            '/api/core/',
            '/v2.4/api/core/',
            '/v2.5/api/core/',
            '/v2.6/api/core/',
            '/v3.0/api/core/'
          ],
        },
        typescriptApiBox: {
          data: require('./docs.json'),
          filepathPrefix: 'src/',
        },
        sidebarCategories: {
          null: ['index', 'why-apollo', 'get-started'],
          'Fetching data': [
            'data/queries',
            'data/mutations',
            'data/local-state',
            'data/subscriptions',
            'data/pagination',
            'data/fragments',
            'data/error-handling',
          ],
          Caching: ['caching/cache-configuration', 'caching/cache-interaction'],
          'Development & Testing': [
            'development-testing/static-typing',
            'development-testing/testing',
            'development-testing/client-schema-mocking',
            'development-testing/developer-tooling',
          ],
          Performance: [
            'performance/performance',
            'performance/optimistic-ui',
            'performance/server-side-rendering',
            'performance/babel',
          ],
          Integrations: [
            'integrations/integrations',
            'integrations/react-native',
            'integrations/meteor',
            'integrations/webpack',
          ],
          Networking: [
            'networking/network-layer',
            'networking/authentication',
          ],
          'Apollo Client API': [
            'api/core',
            'api/react-hooks',
            'api/react-testing',
            'api/react-ssr',
            'api/react-components',
            'api/react-hoc'
          ],
          Migrating: ['migrating/hooks-migration', 'migrating/boost-migration'],
        },
      },
    },
  ],
};
<|endoftext|>


<commit_before>var expect = require('chai').expect;
//var setup  = require(__dirname + '/lib/setup');
var simpleControl = require(__dirname + '/../lib/simpleControl');
var debug = true;
var writtenValue;

var adapter = {
    log: {
        warn: function (txt) {
            console.warn(txt);
        },
        debug: function (txt) {
            console.log(txt);
        },
        info: function (txt) {
            console.log(txt);
        },
        error: function (txt) {
            console.error(txt);
        }
    },
    getForeignObject: function (id, cb) {
        if (id == 'temperatureC') {
            cb(null, {
                _id: 'temperatureC',
                common: {
                    role: 'value.temperature',
                    unit: '°C'
                }
            });
        } else if (id == 'temperatureF') {
            cb(null, {
                _id: 'temperatureF',
                common: {
                    role: 'value.temperature',
                    unit: '°F'
                }
            });
        } else if (id == 'temperatureNone') {
            cb(null, {
                _id: 'temperatureNone',
                common: {
                }
            });
        } else if (id == 'someSwitch') {
            cb(null, {
                _id: 'someSwitch',
                common: {
                    name: 'some switch',
                    unit: '%',
                    type: 'boolean'
                },
                type: 'state'
            });
        } else if (id == 'someLevel') {
            cb(null, {
                _id: 'someLevel',
                common: {
                    name: 'some Level',
                    unit: '%',
                    type: 'number'
                },
                type: 'state'
            });
        } else {
            cb('not found');
        }
    },
    setForeignState: function (id, value, cb) {
        writtenValue = value;
        cb(null);
    },
    getForeignState: function (id, cb) {
        cb(null, {val: 15});
    }
};
var systemConfig = {
    tempUnit: '°F'
};

simpleControl.init(systemConfig, adapter);

describe('Commands: Test time', function () {
    it('must return current time', function (done) {
        simpleControl.sayTime(null, null, null, null, function (text) {
            if (debug) console.log('sayTime returned: ' + text);
            expect(text).to.be.ok;
            expect(text).has.length(5);
            expect(text[2]).is.equal(':');
            expect(parseInt(text.substring(0, 2), 10).toString()).to.be.equal(text.substring(0, 2).replace(/^0/, ''));
            expect(parseInt(text.substring(3, 5), 10).toString()).to.be.equal(text.substring(3, 5).replace(/^0/, ''));
            done();
        });
    });
});

describe('Commands: Test name', function () {
    it('must return no name in english', function (done) {
        simpleControl.sayName('en', null, null, null, function (text) {
            if (debug) console.log('sayName(en) returned: ' + text);
            expect(text).to.be.ok;
            done();
        });
    });

    it('must return no name in german', function (done) {
        simpleControl.sayName('de', null, null, null, function (text) {
            if (debug) console.log('sayName(de) returned: ' + text);
            expect(text).to.be.ok;
            done();
        });
    });

    it('must return no name in russian', function (done) {
        simpleControl.sayName('ru', null, null, null, function (text) {
            if (debug) console.log('sayName(ru) returned: ' + text);
            expect(text).to.be.ok;
            done();
        });
    });

    it('must return name', function (done) {
        simpleControl.sayName('en', null, null, '1/2/3', function (text) {
            if (debug) console.log('sayName(1/2/3) returned: ' + text);
            expect(text).to.be.ok;
            expect(parseInt(text, 10)).to.be.above(0);
            expect(parseInt(text, 10)).to.be.below(4);
            done();
        });
    });

});

describe('Commands: Test temperature', function () {
    it('must say temperature in english and celsius', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureC'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, C) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in german and celsius', function (done) {
        simpleControl.sayTemperature('de', null, ['temperatureC'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(de, C) returned: ' + text);
            expect(text.indexOf('15 Grad')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in russian and celsius', function (done) {
        simpleControl.sayTemperature('ru', null, ['temperatureC'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(ru, C) returned: ' + text);
            expect(text.indexOf('15 градусов')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in english and fahrenheit', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureF'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, F) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in german and fahrenheit', function (done) {
        simpleControl.sayTemperature('de', null, ['temperatureF'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(de, F) returned: ' + text);
            expect(text.indexOf('15 Grad')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in russian and fahrenheit', function (done) {
        simpleControl.sayTemperature('ru', null, ['temperatureF'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(ru, F) returned: ' + text);
            expect(text.indexOf('15 градусов')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in english with default units', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureNone'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, Default) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.least(0);
            done();
        });
    });
    it('must say temperature dont know', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureNone1'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, unknownId) returned: ' + text);
            expect(text.indexOf('degrees')).to.be.below(0);
            expect(text).to.be.ok;
            done();
        });
    });
});

describe('Commands: Test userQuery', function () {
    it('must return temperature on query', function (done) {
        simpleControl.userQuery('en', null, ['temperatureC'], '%s grad/a %s grad/b %s grad', function (text) {
            if (debug) console.log('userQuery(temperatureC) returned: ' + text);
            expect(text.indexOf('15 grad')).to.be.at.least(0);
            done();
        });
    });

    it('must return temperature on query', function (done) {
        simpleControl.userQuery('en', null, ['temperatureC'], '%s %u/a %s %u /b %s %u', function (text) {
            if (debug) console.log('userQuery(temperatureC, %u) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.at.least(0);
            done();
        });
    });

    it('must return temperature on query', function (done) {
        simpleControl.userQuery('en', null, ['unknown'], '%s %u/a %s %u /b %s %u', function (text) {
            if (debug) console.log('userQuery(unknown) returned: ' + text);
            expect(text).to.be.not.ok;
            done();
        });
    });
});

describe('Commands: Test device control', function () {
    it('must control device with predefined value', function (done) {
        simpleControl.userDeviceControl('en', null, ['someSwitch', 'true'], 'Value %s written', function (text) {
            if (debug) console.log('userDeviceControl(someSwitch) returned: ' + text);
            expect(writtenValue).to.be.equal(true);
            expect(text).to.be.ok;
            expect(text.indexOf('Value true written')).to.be.at.least(0);
            done();
        });
    });

    it('must control device with variable value', function (done) {
        simpleControl.userDeviceControl('en', 'control 60.5% value', ['someLevel'], '%n %s%u written', function (text) {
            if (debug) console.log('userDeviceControl(someSwitch, 60.5%) returned: ' + text);
            expect(writtenValue).to.be.equal(60.5);
            expect(text).to.be.ok;
            expect(text.indexOf('some Level 60.5% written')).to.be.at.least(0);
            done();
        });
    });

    it('must not return any ack text', function (done) {
        simpleControl.userDeviceControl('en', 'control 60.5% value', ['someSwitch'], '', function (text) {
            if (debug) console.log('userDeviceControl(someSwitch, no ack) returned: ' + text);
            expect(text).to.be.not.ok;
            done();
        });
    });
});

describe('Commands: Test extract text', function () {
    it('Must return text except key words', function (done) {
        simpleControl.userText('en', simpleControl.extractText('say to computer I will be back', 'say [to] computer'), ['someSwitch'], 'Text: %s/Text: %s', function (text) {
            if (debug) console.log('userText(say to computer I will be late, someSwitch) returned: ' + text);
            expect(text).to.be.equal('Text: I will be back');
            done();
        });
    });
    it('Must return value except key words', function (done) {
        simpleControl.userText('en', simpleControl.extractText('say to computer active', 'say [to] computer'), ['someSwitch'], 'Text: %s/Text: %s', function (text) {
            if (debug) console.log('userText(say to computer I will be late, someSwitch) returned: ' + text);
            expect(text).to.be.equal('Text: active');
            done();
        });
    });
});
<commit_msg>(bluefox) update test<commit_after>var expect = require('chai').expect;
//var setup  = require(__dirname + '/lib/setup');
var simpleControl = require(__dirname + '/../lib/simpleControl');
var debug = true;
var writtenValue;

var adapter = {
    log: {
        warn: function (txt) {
            console.warn(txt);
        },
        debug: function (txt) {
            console.log(txt);
        },
        info: function (txt) {
            console.log(txt);
        },
        error: function (txt) {
            console.error(txt);
        }
    },
    getForeignObject: function (id, cb) {
        if (id == 'temperatureC') {
            cb(null, {
                _id: 'temperatureC',
                common: {
                    role: 'value.temperature',
                    unit: '°C'
                }
            });
        } else if (id == 'temperatureF') {
            cb(null, {
                _id: 'temperatureF',
                common: {
                    role: 'value.temperature',
                    unit: '°F'
                }
            });
        } else if (id == 'temperatureNone') {
            cb(null, {
                _id: 'temperatureNone',
                common: {
                }
            });
        } else if (id == 'someSwitch') {
            cb(null, {
                _id: 'someSwitch',
                common: {
                    name: 'some switch',
                    unit: '%',
                    type: 'boolean'
                },
                type: 'state'
            });
        } else if (id == 'someLevel') {
            cb(null, {
                _id: 'someLevel',
                common: {
                    name: 'some Level',
                    unit: '%',
                    type: 'number'
                },
                type: 'state'
            });
        } else {
            cb('not found');
        }
    },
    setForeignState: function (id, value, cb) {
        writtenValue = value;
        cb(null);
    },
    getForeignState: function (id, cb) {
        cb(null, {val: 15});
    }
};
var systemConfig = {
    tempUnit: '°F'
};

simpleControl.init(systemConfig, adapter);

describe('Commands: Test time', function () {
    it('must return current time', function (done) {
        simpleControl.sayTime(null, null, null, null, function (text) {
            if (debug) console.log('sayTime returned: ' + text);
            expect(text).to.be.ok;
            expect(text).has.length(5);
            expect(text[2]).is.equal(':');
            expect(parseInt(text.substring(0, 2), 10).toString()).to.be.equal(text.substring(0, 2).replace(/^0/, ''));
            expect(parseInt(text.substring(3, 5), 10).toString()).to.be.equal(text.substring(3, 5).replace(/^0/, ''));
            done();
        });
    });
});

describe('Commands: Test name', function () {
    it('must return no name in english', function (done) {
        simpleControl.sayName('en', null, null, null, function (text) {
            if (debug) console.log('sayName(en) returned: ' + text);
            expect(text).to.be.ok;
            done();
        });
    });

    it('must return no name in german', function (done) {
        simpleControl.sayName('de', null, null, null, function (text) {
            if (debug) console.log('sayName(de) returned: ' + text);
            expect(text).to.be.ok;
            done();
        });
    });

    it('must return no name in russian', function (done) {
        simpleControl.sayName('ru', null, null, null, function (text) {
            if (debug) console.log('sayName(ru) returned: ' + text);
            expect(text).to.be.ok;
            done();
        });
    });

    it('must return name', function (done) {
        simpleControl.sayName('en', null, null, '1/2/3', function (text) {
            if (debug) console.log('sayName(1/2/3) returned: ' + text);
            expect(text).to.be.ok;
            expect(parseInt(text, 10)).to.be.above(0);
            expect(parseInt(text, 10)).to.be.below(4);
            done();
        });
    });

});

describe('Commands: Test temperature', function () {
    it('must say temperature in english and celsius', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureC'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, C) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in german and celsius', function (done) {
        simpleControl.sayTemperature('de', null, ['temperatureC'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(de, C) returned: ' + text);
            expect(text.indexOf('15 Grad')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in russian and celsius', function (done) {
        simpleControl.sayTemperature('ru', null, ['temperatureC'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(ru, C) returned: ' + text);
            expect(text.indexOf('15 градусов')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in english and fahrenheit', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureF'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, F) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in german and fahrenheit', function (done) {
        simpleControl.sayTemperature('de', null, ['temperatureF'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(de, F) returned: ' + text);
            expect(text.indexOf('15 Grad')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in russian and fahrenheit', function (done) {
        simpleControl.sayTemperature('ru', null, ['temperatureF'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(ru, F) returned: ' + text);
            expect(text.indexOf('15 градусов')).to.be.least(0);
            done();
        });
    });
    it('must say temperature in english with default units', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureNone'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, Default) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.least(0);
            done();
        });
    });
    it('must say temperature dont know', function (done) {
        simpleControl.sayTemperature('en', null, ['temperatureNone1'], '%s %u/a %s %u/b %s %u', function (text) {
            if (debug) console.log('sayTemperature(en, unknownId) returned: ' + text);
            expect(text.indexOf('degrees')).to.be.below(0);
            expect(text).to.be.ok;
            done();
        });
    });
});

describe('Commands: Test userQuery', function () {
    it('must return temperature on query', function (done) {
        simpleControl.userQuery('en', null, ['temperatureC'], '%s grad/a %s grad/b %s grad', function (text) {
            if (debug) console.log('userQuery(temperatureC) returned: ' + text);
            expect(text.indexOf('15 grad')).to.be.at.least(0);
            done();
        });
    });

    it('must return temperature on query', function (done) {
        simpleControl.userQuery('en', null, ['temperatureC'], '%s %u/a %s %u /b %s %u', function (text) {
            if (debug) console.log('userQuery(temperatureC, %u) returned: ' + text);
            expect(text.indexOf('15 degrees')).to.be.at.least(0);
            done();
        });
    });

    it('must return temperature on query', function (done) {
        simpleControl.userQuery('en', null, ['unknown'], '%s %u/a %s %u /b %s %u', function (text) {
            if (debug) console.log('userQuery(unknown) returned: ' + text);
            expect(text).to.be.not.ok;
            done();
        });
    });
});

describe('Commands: Test device control', function () {
    it('must control device with predefined value', function (done) {
        simpleControl.userDeviceControl('en', null, ['someSwitch', 'true'], 'Value %s written', function (text) {
            if (debug) console.log('userDeviceControl(someSwitch) returned: ' + text);
            expect(writtenValue).to.be.equal(true);
            expect(text).to.be.ok;
            expect(text.indexOf('Value true written')).to.be.at.least(0);
            done();
        });
    });

    it('must control device with variable value', function (done) {
        simpleControl.userDeviceControl('en', 'control 60.5% value', ['someLevel'], '%n %s%u written', function (text) {
            if (debug) console.log('userDeviceControl(someSwitch, 60.5%) returned: ' + text);
            expect(writtenValue).to.be.equal(60.5);
            expect(text).to.be.ok;
            expect(text.indexOf('some Level 60.5% written')).to.be.at.least(0);
            done();
        });
    });

    it('must not return any ack text', function (done) {
        simpleControl.userDeviceControl('en', 'control 60.5% value', ['someSwitch'], '', function (text) {
            if (debug) console.log('userDeviceControl(someSwitch, no ack) returned: ' + text);
            expect(text).to.be.not.ok;
            done();
        });
    });
});

describe('Commands: Test extract text', function () {
    it('Must return text except key words', function (done) {
        simpleControl.sendText('en', simpleControl.extractText('say to computer I will be back', 'say [to] computer'), ['someSwitch'], 'Text: %s/Text: %s', function (text) {
            if (debug) console.log('userText(say to computer I will be late, someSwitch) returned: ' + text);
            expect(text).to.be.equal('Text: I will be back');
            done();
        });
    });
    it('Must return value except key words', function (done) {
        simpleControl.sendText('en', simpleControl.extractText('say to computer active', 'say [to] computer'), ['someSwitch'], 'Text: %s/Text: %s', function (text) {
            if (debug) console.log('userText(say to computer I will be late, someSwitch) returned: ' + text);
            expect(text).to.be.equal('Text: active');
            done();
        });
    });
});
<|endoftext|>


<commit_before>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule instantiateReactComponent
 * @typechecks static-only
 */

'use strict';

var ReactCompositeComponent = require('ReactCompositeComponent');
var ReactEmptyComponent = require('ReactEmptyComponent');
var ReactNativeComponent = require('ReactNativeComponent');

var assign = require('Object.assign');
var invariant = require('invariant');
var warning = require('warning');

// To avoid a cyclic dependency, we create the final class in this module
var ReactCompositeComponentWrapper = function() { };
assign(
  ReactCompositeComponentWrapper.prototype,
  ReactCompositeComponent.Mixin,
  {
    _instantiateReactComponent: instantiateReactComponent
  }
);

/**
 * Check if the type reference is a known internal type. I.e. not a user
 * provided composite type.
 *
 * @param {function} type
 * @return {boolean} Returns true if this is a valid internal type.
 */
function isInternalComponentType(type) {
  return (
    typeof type === 'function' &&
    typeof type.prototype.mountComponent === 'function' &&
    typeof type.prototype.receiveComponent === 'function'
  );
}

/**
 * Given a ReactNode, create an instance that will actually be mounted.
 *
 * @param {ReactNode} node
 * @param {*} parentCompositeType The composite type that resolved this.
 * @return {object} A new instance of the element's constructor.
 * @protected
 */
function instantiateReactComponent(node, parentCompositeType) {
  var instance;

  if (node === null || node === false) {
    node = ReactEmptyComponent.emptyElement;
  }

  if (typeof node === 'object') {
    var element = node;
    if (__DEV__) {
      warning(
        element && (typeof element.type === 'function' ||
                    typeof element.type === 'string'),
        'Only functions or strings can be mounted as React components.'
      );
    }

    // Special case string values
    if (parentCompositeType === element.type &&
        typeof element.type === 'string') {
      // Avoid recursion if the wrapper renders itself.
      instance = ReactNativeComponent.createInternalComponent(element);
      // All native components are currently wrapped in a composite so we're
      // safe to assume that this is what we should instantiate.
    } else if (isInternalComponentType(element.type)) {
      // This is temporarily available for custom components that are not string
      // represenations. I.e. ART. Once those are updated to use the string
      // representation, we can drop this code path.
      instance = new element.type(element);
    } else {
      instance = new ReactCompositeComponentWrapper();
    }
  } else if (typeof node === 'string' || typeof node === 'number') {
    instance = ReactNativeComponent.createInstanceForText(node);
  } else {
    invariant(
      false,
      'Encountered invalid React node of type %s',
      typeof node
    );
  }

  if (__DEV__) {
    warning(
      typeof instance.construct === 'function' &&
      typeof instance.mountComponent === 'function' &&
      typeof instance.receiveComponent === 'function' &&
      typeof instance.unmountComponent === 'function',
      'Only React Components can be mounted.'
    );
  }

  // Sets up the instance. This can probably just move into the constructor now.
  instance.construct(node);

  // These two fields are used by the DOM and ART diffing algorithms
  // respectively. Instead of using expandos on components, we should be
  // storing the state needed by the diffing algorithms elsewhere.
  instance._mountIndex = 0;
  instance._mountImage = null;

  if (__DEV__) {
    instance._isOwnerNecessary = false;
    instance._warnedAboutRefsInRender = false;
  }

  // Internal instances should fully constructed at this point, so they should
  // not get any new fields added to them at this point.
  if (__DEV__) {
    if (Object.preventExtensions) {
      Object.preventExtensions(instance);
    }
  }

  return instance;
}

module.exports = instantiateReactComponent;
<commit_msg>check if type.prototype is object<commit_after>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule instantiateReactComponent
 * @typechecks static-only
 */

'use strict';

var ReactCompositeComponent = require('ReactCompositeComponent');
var ReactEmptyComponent = require('ReactEmptyComponent');
var ReactNativeComponent = require('ReactNativeComponent');

var assign = require('Object.assign');
var invariant = require('invariant');
var warning = require('warning');

// To avoid a cyclic dependency, we create the final class in this module
var ReactCompositeComponentWrapper = function() { };
assign(
  ReactCompositeComponentWrapper.prototype,
  ReactCompositeComponent.Mixin,
  {
    _instantiateReactComponent: instantiateReactComponent
  }
);

/**
 * Check if the type reference is a known internal type. I.e. not a user
 * provided composite type.
 *
 * @param {function} type
 * @return {boolean} Returns true if this is a valid internal type.
 */
function isInternalComponentType(type) {
  return (
    typeof type === 'function' &&
    typeof type.prototype === 'object' &&
    typeof type.prototype.mountComponent === 'function' &&
    typeof type.prototype.receiveComponent === 'function'
  );
}

/**
 * Given a ReactNode, create an instance that will actually be mounted.
 *
 * @param {ReactNode} node
 * @param {*} parentCompositeType The composite type that resolved this.
 * @return {object} A new instance of the element's constructor.
 * @protected
 */
function instantiateReactComponent(node, parentCompositeType) {
  var instance;

  if (node === null || node === false) {
    node = ReactEmptyComponent.emptyElement;
  }

  if (typeof node === 'object') {
    var element = node;
    if (__DEV__) {
      warning(
        element && (typeof element.type === 'function' ||
                    typeof element.type === 'string'),
        'Only functions or strings can be mounted as React components.'
      );
    }

    // Special case string values
    if (parentCompositeType === element.type &&
        typeof element.type === 'string') {
      // Avoid recursion if the wrapper renders itself.
      instance = ReactNativeComponent.createInternalComponent(element);
      // All native components are currently wrapped in a composite so we're
      // safe to assume that this is what we should instantiate.
    } else if (isInternalComponentType(element.type)) {
      // This is temporarily available for custom components that are not string
      // represenations. I.e. ART. Once those are updated to use the string
      // representation, we can drop this code path.
      instance = new element.type(element);
    } else {
      instance = new ReactCompositeComponentWrapper();
    }
  } else if (typeof node === 'string' || typeof node === 'number') {
    instance = ReactNativeComponent.createInstanceForText(node);
  } else {
    invariant(
      false,
      'Encountered invalid React node of type %s',
      typeof node
    );
  }

  if (__DEV__) {
    warning(
      typeof instance.construct === 'function' &&
      typeof instance.mountComponent === 'function' &&
      typeof instance.receiveComponent === 'function' &&
      typeof instance.unmountComponent === 'function',
      'Only React Components can be mounted.'
    );
  }

  // Sets up the instance. This can probably just move into the constructor now.
  instance.construct(node);

  // These two fields are used by the DOM and ART diffing algorithms
  // respectively. Instead of using expandos on components, we should be
  // storing the state needed by the diffing algorithms elsewhere.
  instance._mountIndex = 0;
  instance._mountImage = null;

  if (__DEV__) {
    instance._isOwnerNecessary = false;
    instance._warnedAboutRefsInRender = false;
  }

  // Internal instances should fully constructed at this point, so they should
  // not get any new fields added to them at this point.
  if (__DEV__) {
    if (Object.preventExtensions) {
      Object.preventExtensions(instance);
    }
  }

  return instance;
}

module.exports = instantiateReactComponent;
<|endoftext|>


<commit_before>var nodeunit = require('nodeunit');

var bertrpc = require('../src/bertrpc');
var bert = require('../src/bert');

var TestModule = {
    foo: function (a, b) {
        return ['foo', 'bar', a, b];
    },

    other: 'hello'
};

exports.testExpose = function(test) {
    bertrpc.expose('test', TestModule);
    test.equals(bertrpc.modules.test, TestModule);
    test.done();
};

exports.testDispatch = function(test) {
    var res = bertrpc.dispatch('call', 'test', 'foo', [1, 2]);
    test.strictEqual(res[0], 'foo');
    test.strictEqual(res[1], 'bar');
    test.strictEqual(res[2], 1);
    test.strictEqual(res[3], 2);
    test.done();
};

//exports.testDispatchMissingArgs = function(test) {
//    test.throws(function() {
//        bertrpc.dispatch('call', 'test', 'foo', []);
//    });
//    test.done();
//};

exports.testDispatchBadModule = function(test) {
    test.throws(function() {
        bertrpc.dispatch('call', 'foo', 'bar', []);
    });
    test.done();
};

exports.testDispatchBadAttribute = function(test) {
    test.throws(function() {
        bertrpc.dispatch('call', 'test', 'bar', []);
    });
    test.done();
};

exports.testDispatchNonFunction = function(test) {
    test.throws(function() {
        bertrpc.dispatch('call', 'test', 'other', []);
    });
    test.done();
};

exports.testReadBerpFromFD = function(test) {
    var packet = bert.encode('hi');
    var did = 0;
    var berp = bert.int_to_bytes(packet.length, 4) + packet;

    var fd = {
        addListener: function (event, callback) {
            test.equals(event, 'receive');
            callback(berp + berp + berp);
        }
    };

    bertrpc.read(fd, function (size, term) {
        test.strictEqual(size, packet.length);
        test.equals(term, 'hi');
        did++;
    });

    test.strictEqual(did, 3);
    test.done();
};

exports.testWriteBerpToFD = function(test) {
    var buf = '';
    var fd = {
        send: function (data) {
            buf += data;
        }
    };

    bertrpc.write(fd, 'hello world');
    var packet = bert.encode('hello world');
    var berp = bert.int_to_bytes(packet.length, 4) + packet;
    test.strictEqual(buf, berp);
    test.done();
};

<commit_msg>[tests] fix testWriteBerpToFD test<commit_after>var nodeunit = require('nodeunit');

var bertrpc = require('../src/bertrpc');
var bert = require('../src/bert');

var TestModule = {
    foo: function (a, b) {
        return ['foo', 'bar', a, b];
    },

    other: 'hello'
};

exports.testExpose = function(test) {
    bertrpc.expose('test', TestModule);
    test.equals(bertrpc.modules.test, TestModule);
    test.done();
};

exports.testDispatch = function(test) {
    var res = bertrpc.dispatch('call', 'test', 'foo', [1, 2]);
    test.strictEqual(res[0], 'foo');
    test.strictEqual(res[1], 'bar');
    test.strictEqual(res[2], 1);
    test.strictEqual(res[3], 2);
    test.done();
};

//exports.testDispatchMissingArgs = function(test) {
//    test.throws(function() {
//        bertrpc.dispatch('call', 'test', 'foo', []);
//    });
//    test.done();
//};

exports.testDispatchBadModule = function(test) {
    test.throws(function() {
        bertrpc.dispatch('call', 'foo', 'bar', []);
    });
    test.done();
};

exports.testDispatchBadAttribute = function(test) {
    test.throws(function() {
        bertrpc.dispatch('call', 'test', 'bar', []);
    });
    test.done();
};

exports.testDispatchNonFunction = function(test) {
    test.throws(function() {
        bertrpc.dispatch('call', 'test', 'other', []);
    });
    test.done();
};

exports.testReadBerpFromFD = function(test) {
    var packet = bert.encode('hi');
    var did = 0;
    var berp = bert.int_to_bytes(packet.length, 4) + packet;

    var fd = {
        addListener: function (event, callback) {
            test.equals(event, 'receive');
            callback(berp + berp + berp);
        }
    };

    bertrpc.read(fd, function (size, term) {
        test.strictEqual(size, packet.length);
        test.equals(term, 'hi');
        did++;
    });

    test.strictEqual(did, 3);
    test.done();
};

exports.testWriteBerpToFD = function(test) {
    var buf = '';
    var fd = {
        write: function (data) {
            buf += data.toString('binary');
        }
    };

    bertrpc.write(fd, 'hello world');
    var packet = bert.encode('hello world');
    var berp = bert.int_to_bytes(packet.length, 4) + packet;
    test.strictEqual(buf, berp);
    test.done();
};

<|endoftext|>