getRefreshGlobal.js 2.64 KB
const Template = require('webpack/lib/Template');
const { refreshGlobal } = require('../globals');

/**
 * @typedef {Object} RuntimeTemplate
 * @property {function(string, string[]): string} basicFunction
 * @property {function(): boolean} supportsConst
 * @property {function(string, string=): string} returningFunction
 */

/** @type {RuntimeTemplate} */
const FALLBACK_RUNTIME_TEMPLATE = {
  basicFunction(args, body) {
    return `function(${args}) {\n${Template.indent(body)}\n}`;
  },
  supportsConst() {
    return false;
  },
  returningFunction(returnValue, args = '') {
    return `function(${args}) { return ${returnValue}; }`;
  },
};

/**
 * Generates the refresh global runtime template.
 * @param {RuntimeTemplate} [runtimeTemplate] The runtime template helpers.
 * @returns {string} The refresh global runtime template.
 */
function getRefreshGlobal(runtimeTemplate = FALLBACK_RUNTIME_TEMPLATE) {
  const declaration = runtimeTemplate.supportsConst() ? 'const' : 'var';
  return Template.asString([
    `${refreshGlobal} = {`,
    Template.indent([
      `init: ${runtimeTemplate.basicFunction('', [
        `${refreshGlobal}.cleanup = ${runtimeTemplate.returningFunction(
          'undefined',
        )};`,
        `${refreshGlobal}.register = ${runtimeTemplate.returningFunction(
          'undefined',
        )};`,
        `${refreshGlobal}.runtime = {};`,
        `${refreshGlobal}.signature = ${runtimeTemplate.returningFunction(
          runtimeTemplate.returningFunction('type', 'type'),
        )};`,
      ])},`,
      `setup: ${runtimeTemplate.basicFunction('currentModuleId', [
        `${declaration} prevCleanup = ${refreshGlobal}.cleanup;`,
        `${declaration} prevReg = ${refreshGlobal}.register;`,
        `${declaration} prevSig = ${refreshGlobal}.signature;`,
        '',
        `${refreshGlobal}.register = ${runtimeTemplate.basicFunction(
          'type, id',
          [
            `${declaration} typeId = currentModuleId + " " + id;`,
            `${refreshGlobal}.runtime.register(type, typeId);`,
          ],
        )}`,
        '',
        `${refreshGlobal}.signature = ${refreshGlobal}.runtime.createSignatureFunctionForTransform;`,
        '',
        `${refreshGlobal}.cleanup = ${runtimeTemplate.basicFunction(
          'cleanupModuleId',
          [
            'if (currentModuleId === cleanupModuleId) {',
            Template.indent([
              `${refreshGlobal}.register = prevReg;`,
              `${refreshGlobal}.signature = prevSig;`,
              `${refreshGlobal}.cleanup = prevCleanup;`,
            ]),
            '}',
          ],
        )}`,
      ])},`,
    ]),
    '};',
  ]);
}

module.exports = getRefreshGlobal;