import * as server from './server.js';
import wrap from './wrap.js';
import FirstPassCache from './first-pass-cache.js';
import through from 'through2';

import clientTemplate from 'raw-loader!./client.tpl.js';
import coreLib from 'raw-loader!ng-hot-reload-core';

module.exports = ngHotReloadStandalone;
module.exports.default = ngHotReloadStandalone;

function ngHotReloadStandalone({
    start = true,
    port = 3100,
    angular = 'angular',
} = {}) {
    let fileServer;

    function startServer() {
        fileServer = server.start(port);
    }

    const
        wrapInitial = wrap({
            firstPassed: false,
            port,
            angular,
        }),
        wrapReload = wrap({
            firstPassed: true,
            port,
            angular,
        });

    /**
     * Reload changed file.
     * @param {string} path Path to the file.
     * @param {string} file File contents.
     * @param {boolean=} [includeClient=false] If true, the standalone client
     *      is appended to the output.
     */
    function reload(path, file, includeClient = false) {
        file = wrapReload(path, file);
        if (includeClient) {
            file = client + file;
        }
        fileServer.reload(path, file);
    }

    function stream(options) {
        let initial, reload, includeClient,
            clientIncluded = false, firstPassCache;

        if (!options) {
            initial = reload = includeClient = true;
        } else {
            initial = Boolean(options.initial);
            reload = Boolean(options.reload);
            includeClient = Boolean(options.includeClient);

            // Sanity checks
            if (!initial && !reload) {
                const msg =
                    `Invalid options in ${JSON.stringify(options)}. At least` +
                    `one of "initial" or "reload" must be set to true!`;
                throw new Error(msg);
            }
        }

        if (initial && reload) {
            firstPassCache = new FirstPassCache();
        }

        return through.obj(function(file, enc, cb) {
            if (/node_modules/.test(file.path)) {
                cb(null, file);
                return;
            }

            let contents = String(file.contents);
            const firstRun =
                initial && (!reload || firstPassCache.pass(file.path));
            const shouldAddClient = includeClient && !clientIncluded;

            if (firstRun) {
                // If we are supposed to handle first runs and this is
                // a first run, wrap the contents with wrapInitial.
                contents = wrapInitial(file.path, contents);
                if (shouldAddClient) {
                    contents = client + contents;
                    clientIncluded = true;
                }
                file.contents = Buffer.from(contents);
            } else {
                // If we are not supposed to handle first runs or the
                // first run has already ended, pass to reload instead.
                reload(file.path, contents, shouldAddClient);
            }

            cb(null, file);
        });
    }

    const clientOptions = {
        ns: 'ng-hot-reload-standalone',
        port,
    };

    const client =
        `;(function(options) {
            options.root = typeof window !== 'undefined' ? window : this;
            if (options.root) {
                if (options.root[options.ns]) return;
                else options.root[options.ns] = {};
            }

            ${clientTemplate}

            var module;
            var exports = options.root[options.ns];
            // Webpack's generated output for ng-hot-reload-core will load
            // the exports to options.root[options.ns]['ng-hot-reload-core']
            ${coreLib}

        })(${ JSON.stringify(clientOptions) });
        `;

    if (start) {
        startServer();
    }

    return {
        start: startServer,
        wrap: wrapInitial,
        client,
        reload,
        stream,
    };
};


@@ -347,16 +347,86 @@
 alone;%0A%0A
+const moduleRegex = /(%5C/%7C%5C%5C)(node_modules%7Cbower_components)(%5C/%7C%5C%5C)/;%0A%0A
 function
@@ -1312,24 +1312,1332 @@
 le);%0A    %7D%0A%0A
+    /**%0A     * Creates a consumer for gulp file streams.%0A     *%0A     * The source files need to be wrapped using the %60wrap%60 function%0A     * on the first load and then passed to %60reload%60 function%0A     * when there's a change.%0A     *%0A     * This function can be used in place or with the normal %60reload%60%0A     * and %60wrap%60 functions, for the initial load of the%0A     * files or for the subsequent reloads of those files,%0A     * or both.%0A     *%0A     * @param %7Bobject=%7D options Options for the consumer.%0A     *      If omitted, defaults to all options being true.%0A     * @param %7Bboolean=%7D %5Boptions.initial=true%5D Use this stream to%0A     *      wrap the files during the initial load.%0A     * @param %7Bboolean=%7D %5Boptions.reload=true%5D Use this stream to%0A     *      handle the reloads.%0A     * @param %7Bboolean=%7D %5Boptions.includeClient=true%5D Use this stream to%0A     *      include the runtime client. The client is prepended to the%0A     *      first %22valid%22 file that passes through. Note that if you%0A     *      set this option to %60false%60, you need to manually include the file%0A     *      so that it gets executed before other hot-loaded files.%0A     * @param %7Bboolean=%7D %5Boptions.ignoreModules%5D Ignore files that%0A     *      are in node_modules or bower_components.%0A     * @return %7B*%7D Handler for gulp streams.%0A     */%0A
     function
@@ -3028,17 +3028,16 @@
 ty check
-s
 %0A       
@@ -3480,22 +3480,19 @@
 if (
-/node_
 module
-s/
+Regex
 .tes

Add documentation for the stram function