<commit_before>var widgetLookup = require('./util').$__widgetLookup;
var nextRepeatedId = require('./nextRepeatedId');
var repeatedRegExp = /\[\]$/;
var WidgetsContext = require('./WidgetsContext');

var WIDGETS_BEGIN_ASYNC_ADDED_KEY = '$wa';

function resolveWidgetRef(out, ref, scope) {
    if (ref.charAt(0) === '#') {
        return ref.substring(1);
    } else {
        var resolvedId;

        if (repeatedRegExp.test(ref)) {
            resolvedId = nextRepeatedId(out, scope, ref);
        } else {
            resolvedId = scope + '-' + ref;
        }

        return resolvedId;
    }
}

function preserveWidgetEls(existingWidget, out, widgetsContext) {
    var rootEls = existingWidget.$__getRootEls({});

    for (var elId in rootEls) {
        var el = rootEls[elId];

        // We put a placeholder element in the output stream to ensure that the existing
        // DOM node is matched up correctly when using morphdom.
        out.element(el.tagName, { id: elId });

        widgetsContext.$__preserveDOMNode(elId); // Mark the element as being preserved (for morphdom)
    }

    existingWidget.$__reset(); // The widget is no longer dirty so reset internal flags
    return true;
}

function handleBeginAsync(event) {
    var parentOut = event.parentOut;
    var asyncOut = event.out;
    var widgetsContext = asyncOut.global.widgets;
    var widgetStack;

    if (widgetsContext && (widgetStack = widgetsContext.$__widgetStack)) {
        // All of the widgets in this async block should be
        // initialized after the widgets in the parent. Therefore,
        // we will create a new WidgetsContext for the nested
        // async block and will create a new widget stack where the current
        // widget in the parent block is the only widget in the nested
        // stack (to begin with). This will result in top-level widgets
        // of the async block being added as children of the widget in the
        // parent block.
        var nestedWidgetsContext = new WidgetsContext(asyncOut, widgetStack[widgetStack.length-1]);
        asyncOut.data.widgets = nestedWidgetsContext;
    }
    asyncOut.data.$w = parentOut.data.$w;
}

function createRendererFunc(templateRenderFunc, widgetProps, renderingLogic) {
    var onInput = renderingLogic && renderingLogic.onInput;
    var typeName = widgetProps.type;
    var roots = widgetProps.roots;
    var assignedId = widgetProps.id;

    return function renderer(input, out) {
        var outGlobal = out.global;

        if (!outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY]) {
            outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY] = true;
            out.on('beginAsync', handleBeginAsync);
        }

        var widgetConfig;
        var widgetBody;
        var widgetState; // This is the pending widget state that needs to be assigned to the new widget
        var finalWidgetState; // This is the final widget state

        var rootRerenderWidget = outGlobal.$w;
        var isRerender = rootRerenderWidget !== undefined;

        if (rootRerenderWidget) {
            outGlobal.$w = null;
        } else if (!input) {
            // Make sure we always have a non-null input object
            input = {};
        }

        var widgetArgs = input && input.$w;
        var customEvents;
        var scope;

        var id = assignedId;

        if (!widgetArgs) {
            widgetArgs = out.data.$w;
        }

        if (widgetArgs) {
            scope = widgetArgs[0];

            if (scope) {
                scope = scope.id;
            }

            var ref = widgetArgs[1];
            if (ref != null) {
                ref = ref.toString();
            }
            id = id || resolveWidgetRef(out, ref, scope);
            customEvents = widgetArgs[2];
            delete input.$w;
        }

        var widgetsContext = WidgetsContext.$__getWidgetsContext(out);

        if (!id) {
            id = widgetsContext.$__nextWidgetId();
        }

        var existingWidget;

        if (rootRerenderWidget) {
            existingWidget = rootRerenderWidget;
            id = rootRerenderWidget.id;
        } else if (isRerender) {
            // Look in in the DOM to see if a widget with the same ID and type already exists.
            existingWidget = widgetLookup[id];
            if (existingWidget && existingWidget.$__type !== typeName) {
                existingWidget = undefined;
            }
        }

        if (input) {
            if (onInput) {
                var updatedInput;
                if (existingWidget) {
                    updatedInput = existingWidget.onInput(input, out);
                } else {
                    var lightweightWidget = Object.create(renderingLogic);
                    updatedInput = lightweightWidget.onInput(input, out);
                    widgetState = finalWidgetState = lightweightWidget.state;
                    widgetConfig = lightweightWidget;
                    delete widgetConfig.state;
                }
                input = updatedInput === undefined ? input : updatedInput;
            }
            // Default to using the nested content as the widget body
            widgetBody = input.renderBody;
        }

        if (existingWidget) {
            var existingState = existingWidget.$__state;

            if (!widgetState) {
                finalWidgetState = existingState && existingState.$__raw;
            }

            if (!rootRerenderWidget) {
                // This is a nested widget found during a rerender. We don't want to needlessly
                // rerender the widget if that is not necessary. If the widget is a stateful
                // widget then we update the existing widget with the new state.
                var shouldPreserve;

                if (existingState) {
                    if (widgetState) {
                        // This will only be true if getInitialState was true
                        existingWidget.$__replaceState(widgetState);
                        widgetState = null;
                    }

                    shouldPreserve = !widgetBody && !existingWidget.$__isDirty;
                }

                // If the widget is not dirty (no state changes) and shouldUpdate() returns false
                // then skip rerendering the widget.
                if (shouldPreserve || !existingWidget.shouldUpdate(input, finalWidgetState)) {
                    preserveWidgetEls(existingWidget, out, widgetsContext);
                    return;
                }
            }
        }

        var templateInput = input ||
            (existingWidget && existingWidget.input) ||
            (rootRerenderWidget && rootRerenderWidget.input) ||
            {};

        if (existingWidget) {
            existingWidget.$__emitLifecycleEvent('beforeUpdate');
            existingWidget.input = templateInput;
        }
<commit_msg>remove legacy code related to getInitialState and small refactoring<commit_after>var widgetLookup = require('./util').$__widgetLookup;
var nextRepeatedId = require('./nextRepeatedId');
var repeatedRegExp = /\[\]$/;
var WidgetsContext = require('./WidgetsContext');

var WIDGETS_BEGIN_ASYNC_ADDED_KEY = '$wa';

function resolveWidgetRef(out, ref, scope) {
    if (ref.charAt(0) === '#') {
        return ref.substring(1);
    } else {
        var resolvedId;

        if (repeatedRegExp.test(ref)) {
            resolvedId = nextRepeatedId(out, scope, ref);
        } else {
            resolvedId = scope + '-' + ref;
        }

        return resolvedId;
    }
}

function preserveWidgetEls(existingWidget, out, widgetsContext) {
    var rootEls = existingWidget.$__getRootEls({});

    for (var elId in rootEls) {
        var el = rootEls[elId];

        // We put a placeholder element in the output stream to ensure that the existing
        // DOM node is matched up correctly when using morphdom.
        out.element(el.tagName, { id: elId });

        widgetsContext.$__preserveDOMNode(elId); // Mark the element as being preserved (for morphdom)
    }

    existingWidget.$__reset(); // The widget is no longer dirty so reset internal flags
    return true;
}

function handleBeginAsync(event) {
    var parentOut = event.parentOut;
    var asyncOut = event.out;
    var widgetsContext = asyncOut.global.widgets;
    var widgetStack;

    if (widgetsContext && (widgetStack = widgetsContext.$__widgetStack)) {
        // All of the widgets in this async block should be
        // initialized after the widgets in the parent. Therefore,
        // we will create a new WidgetsContext for the nested
        // async block and will create a new widget stack where the current
        // widget in the parent block is the only widget in the nested
        // stack (to begin with). This will result in top-level widgets
        // of the async block being added as children of the widget in the
        // parent block.
        var nestedWidgetsContext = new WidgetsContext(asyncOut, widgetStack[widgetStack.length-1]);
        asyncOut.data.widgets = nestedWidgetsContext;
    }
    asyncOut.data.$w = parentOut.data.$w;
}

function createRendererFunc(templateRenderFunc, widgetProps, renderingLogic) {
    var onInput = renderingLogic && renderingLogic.onInput;
    var typeName = widgetProps.type;
    var roots = widgetProps.roots;
    var assignedId = widgetProps.id;

    return function renderer(input, out) {
        var outGlobal = out.global;

        if (!outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY]) {
            outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY] = true;
            out.on('beginAsync', handleBeginAsync);
        }

        var widgetConfig;
        var widgetBody;
        var widgetState; // This is the pending widget state that needs to be assigned to the new widget
        var finalWidgetState; // This is the final widget state

        var rootRerenderWidget = outGlobal.$w;
        var isRerender = rootRerenderWidget !== undefined;

        if (rootRerenderWidget) {
            outGlobal.$w = null;
        } else if (!input) {
            // Make sure we always have a non-null input object
            input = {};
        }

        var widgetArgs = input && input.$w || out.data.$w;
        var customEvents;
        var scope;

        var id = assignedId;

        if (widgetArgs) {
            scope = widgetArgs[0];

            if (scope) {
                scope = scope.id;
            }

            var ref = widgetArgs[1];
            if (ref != null) {
                ref = ref.toString();
            }
            id = id || resolveWidgetRef(out, ref, scope);
            customEvents = widgetArgs[2];
            delete input.$w;
        }

        var widgetsContext = WidgetsContext.$__getWidgetsContext(out);

        id = id || widgetsContext.$__nextWidgetId();

        var existingWidget;

        if (rootRerenderWidget) {
            existingWidget = rootRerenderWidget;
            id = rootRerenderWidget.id;
        } else if (isRerender) {
            // Look in in the DOM to see if a widget with the same ID and type already exists.
            existingWidget = widgetLookup[id];
            if (existingWidget && existingWidget.$__type !== typeName) {
                existingWidget = undefined;
            }
        }

        if (input) {
            if (onInput) {
                var updatedInput;
                if (existingWidget) {
                    updatedInput = existingWidget.onInput(input, out);
                } else {
                    var lightweightWidget = Object.create(renderingLogic);
                    updatedInput = lightweightWidget.onInput(input, out);
                    widgetState = finalWidgetState = lightweightWidget.state;
                    widgetConfig = lightweightWidget;
                    delete widgetConfig.state;
                }
                input = updatedInput === undefined ? input : updatedInput;
            }
            // Default to using the nested content as the widget body
            widgetBody = input.renderBody;
        }

        if (existingWidget) {
            var existingState = existingWidget.$__state;

            if (!widgetState) {
                finalWidgetState = existingState && existingState.$__raw;
            }

            if (!rootRerenderWidget) {
                // This is a nested widget found during a rerender. We don't want to needlessly
                // rerender the widget if that is not necessary. If the widget is a stateful
                // widget then we update the existing widget with the new state.
                var shouldPreserve = existingState && !widgetBody && !existingWidget.$__isDirty;

                // If the widget is not dirty (no state changes) and shouldUpdate() returns false
                // then skip rerendering the widget.
                if (shouldPreserve || !existingWidget.shouldUpdate(input, finalWidgetState)) {
                    preserveWidgetEls(existingWidget, out, widgetsContext);
                    return;
                }
            }
        }

        var templateInput = input ||
            (existingWidget && existingWidget.input) ||
            (rootRerenderWidget && rootRerenderWidget.input) ||
            {};

        if (existingWidget) {
            existingWidget.$__emitLifecycleEvent('beforeUpdate');
            existingWidget.input = templateInput;
        }

{'fraction_non_alphanumeric': 0.08557749850388989, 'fraction_numerical': 0.0008976660682226212, 'mean_word_length': 1.900629203731829, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4398392', 'n_tokens_mistral': 3474, 'n_tokens_neox': 3310, 'n_words': 1030}