"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Shared between webpack 4 and 5:
function injectRefreshFunctions(compilation, Template) {
    const hookVars = compilation.mainTemplate.hooks.localVars;
    hookVars.tap('ReactFreshWebpackPlugin', (source) => Template.asString([
        source,
        '',
        '// noop fns to prevent runtime errors during initialization',
        'if (typeof self !== "undefined") {',
        Template.indent('self.$RefreshReg$ = function () {};'),
        Template.indent('self.$RefreshSig$ = function () {'),
        Template.indent(Template.indent('return function (type) {')),
        Template.indent(Template.indent(Template.indent('return type;'))),
        Template.indent(Template.indent('};')),
        Template.indent('};'),
        '}',
    ]));
}
function webpack4(compiler) {
    const { Template } = this;
    // Webpack 4 does not have a method to handle interception of module
    // execution.
    // The closest thing we have to emulating this is mimicking the behavior of
    // `strictModuleExceptionHandling` in `MainTemplate`:
    // https://github.com/webpack/webpack/blob/4c644bf1f7cb067c748a52614500e0e2182b2700/lib/MainTemplate.js#L200
    compiler.hooks.compilation.tap('ReactFreshWebpackPlugin', (compilation) => {
        injectRefreshFunctions(compilation, Template);
        const hookRequire = compilation.mainTemplate.hooks.require;
        // @ts-ignore webpack 5 types compat
        hookRequire.tap('ReactFreshWebpackPlugin', (source) => {
            // Webpack 4 evaluates module code on the following line:
            // ```
            // modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
            // ```
            // https://github.com/webpack/webpack/blob/4c644bf1f7cb067c748a52614500e0e2182b2700/lib/MainTemplate.js#L200
            const lines = source.split('\n');
            // @ts-ignore webpack 5 types compat
            const evalIndex = lines.findIndex((l) => l.includes('modules[moduleId].call('));
            // Unable to find the module execution, that's OK:
            if (evalIndex === -1) {
                return source;
            }
            // Legacy CSS implementations will `eval` browser code in a Node.js
            // context to extract CSS. For backwards compatibility, we need to check
            // we're in a browser context before continuing.
            return Template.asString([
                ...lines.slice(0, evalIndex),
                `
        var hasRefresh = typeof self !== "undefined" && !!self.$RefreshInterceptModuleExecution$;
        var cleanup = hasRefresh
          ? self.$RefreshInterceptModuleExecution$(moduleId)
          : function() {};
        try {
        `,
                lines[evalIndex],
                `
        } finally {
          cleanup();
        }
        `,
                ...lines.slice(evalIndex + 1),
            ]);
        });
    });
}
function webpack5(compiler) {
    const { RuntimeGlobals, RuntimeModule, Template } = this;
    class ReactRefreshRuntimeModule extends RuntimeModule {
        constructor() {
            super('react refresh', 5);
        }
        generate() {
            const { runtimeTemplate } = this.compilation;
            return Template.asString([
                `if (${RuntimeGlobals.interceptModuleExecution}) {`,
                `${RuntimeGlobals.interceptModuleExecution}.push(${runtimeTemplate.basicFunction('options', [
                    `${runtimeTemplate.supportsConst() ? 'const' : 'var'} originalFactory = options.factory;`,
                    `options.factory = ${runtimeTemplate.basicFunction('moduleObject, moduleExports, webpackRequire', [
                        // Legacy CSS implementations will `eval` browser code in a Node.js
                        // context to extract CSS. For backwards compatibility, we need to check
                        // we're in a browser context before continuing.
                        `${runtimeTemplate.supportsConst() ? 'const' : 'var'} hasRefresh = typeof self !== "undefined" && !!self.$RefreshInterceptModuleExecution$;`,
                        `${runtimeTemplate.supportsConst() ? 'const' : 'var'} cleanup = hasRefresh ? self.$RefreshInterceptModuleExecution$(moduleObject.id) : ${runtimeTemplate.supportsArrowFunction()
                            ? '() => {}'
                            : 'function() {}'};`,
                        'try {',
                        Template.indent('originalFactory.call(this, moduleObject, moduleExports, webpackRequire);'),
                        '} finally {',
                        Template.indent(`cleanup();`),
                        '}',
                    ])}`,
                ])})`,
                '}',
            ]);
        }
    }
    // @ts-ignore webpack 5 types compat
    compiler.hooks.compilation.tap('ReactFreshWebpackPlugin', (compilation) => {
        injectRefreshFunctions(compilation, Template);
        compilation.hooks.additionalTreeRuntimeRequirements.tap('ReactFreshWebpackPlugin', (chunk) => {
            compilation.addRuntimeModule(chunk, new ReactRefreshRuntimeModule());
        });
    });
}
class ReactFreshWebpackPlugin {
    constructor({ version, RuntimeGlobals, RuntimeModule, Template, } = require('webpack')) {
        this.webpackMajorVersion = parseInt(version !== null && version !== void 0 ? version : '', 10);
        this.RuntimeGlobals = RuntimeGlobals;
        this.RuntimeModule = RuntimeModule;
        this.Template = Template;
    }
    apply(compiler) {
        switch (this.webpackMajorVersion) {
            case 4: {
                webpack4.call(this, compiler);
                break;
            }
            case 5: {
                webpack5.call(this, compiler);
                break;
            }
            default: {
                throw new Error(`ReactFreshWebpackPlugin does not support webpack v${this.webpackMajorVersion}.`);
            }
        }
    }
}
exports.default = ReactFreshWebpackPlugin;
//# sourceMappingURL=ReactRefreshWebpackPlugin.js.map