<commit_before>// TODO: add an api to Reify to update cached exports for a module
const ReifyEntry = require('/node_modules/meteor/modules/node_modules/reify/lib/runtime/entry.js')

const SOURCE_URL_PREFIX = "meteor://\u{1f4bb}app";

// Due to the bundler and proxy running in the same node process
// this could possibly be ran after the next build finished
// TODO: the builder should inject a build timestamp in the bundle
let lastUpdated = Date.now();
let appliedChangeSets = [];
let reloadId = 0;

let arch = __meteor_runtime_config__.isModern ? 'web.browser' : 'web.browser.legacy';
let enabled = arch === 'web.browser';

if (!enabled) {
  console.log(`HMR is not supported in ${arch}`);
}

let pendingReload = () => Reload._reload({ immediateMigration: true });
let mustReload = false;

function handleMessage(message) {
  if (message.type === 'register-failed') {
    if (message.reason === 'wrong-app') {
      console.log('HMR: A different app is running on', Meteor.absoluteUrl());
      console.log('HMR: Once you start this app again reload the page to re-enable HMR');
    } else if (message.reason === 'wrong-secret') {
      // TODO: we could wait until the first update to use hot code push
      // instead of reloading the page immediately in case the user has any
      // client state they want to keep for now.
      console.log('HMR: Have the wrong secret, possibly because Meteor was restarted');
      console.log('HMR: Reloading page to get new secret');
      mustReload = true;
      pendingReload();
    } else {
      console.log(`HMR: Register failed for unknown reason`, message);
    }
    return;
  }

  if (message.type !== 'changes') {
    throw new Error(`Unknown HMR message type ${message.type}`);
  }

  const hasUnreloadable = message.changeSets.find(changeSet => {
    return !changeSet.reloadable;
  });

  if (
    pendingReload &&
    hasUnreloadable ||
    message.changeSets.length === 0
  ) {
    if (message.eager) {
      // This was an attempt to reload before the build finishes
      // If we can't, we will wait until the build finishes to properly handle it
      return;
    }

    console.log('HMR: Unable to do HMR. Falling back to hot code push.')
    // Complete hot code push if we can not do hot module reload
    mustReload = true;
    return pendingReload();
  }

  // In case the user changed how a module works with HMR
  // in one of the earlier change sets, we want to apply each
  // change set one at a time in order.
  const succeeded = message.changeSets.filter(changeSet => {
    return !appliedChangeSets.includes(changeSet.id)
  }).every(changeSet => {
    const applied = applyChangeset(changeSet, message.eager);

    // We don't record if a module is unreplaceable
    // during an eager update so we can retry and
    // handle the failure after the build finishes
    if (applied || !message.eager) {
      appliedChangeSets.push(changeSet.id);
    }

    return applied;
  });

  if (message.eager) {
    // We will ignore any failures at this time
    // and wait to handle them until the build finishes
    return;
  }

  if (!succeeded) {
    if (pendingReload) {
      mustReload = true;
      return pendingReload();
    }

    throw new Error('HMR failed and unable to fallback to hot code push?');
  }

  if (message.changeSets.length > 0) {
    lastUpdated = message.changeSets[message.changeSets.length - 1].linkedAt;
  }
}

let socket;
let pendingMessages = [];

function send(message) {
  if (socket) {
    socket.send(JSON.stringify(message));
  } else {
    pendingMessages.push(message);
  }
}

function connect() {
  if (mustReload) {
    // The page will reload, no reason to 
    // connect and show more logs in the console
    return;
  }

  const wsUrl = Meteor.absoluteUrl('/__meteor__hmr__/websocket').replace(/^.+\/\//, 'ws://');
  socket = new WebSocket(wsUrl);

  socket.addEventListener('close', function () {
    socket = null;
    console.log('HMR: websocket closed');
    setTimeout(connect, 2000);
  });

  socket.addEventListener('open', function () {
    console.log('HMR: connected');
    socket.send(JSON.stringify({
      type: 'register',
      arch,
      secret: __meteor_runtime_config__._hmrSecret,
      appId: __meteor_runtime_config__.appId,
    }));

    const toSend = pendingMessages.slice();
    pendingMessages = [];

    toSend.forEach(message => {
      send(message);
    });
  });

  socket.addEventListener('message', function (event) {
    handleMessage(JSON.parse(event.data));
  });

  socket.addEventListener('error', console.error);
}

connect();

function requestChanges() {
  send({
    type: 'request-changes',
    arch,
    after: lastUpdated
  });
}

function walkTree(pathParts, tree) {
  const part = pathParts.shift();
  const _module = tree.contents[part];

  if (!_module) {
    console.log(part, pathParts, _module, tree);
    throw new Error('not-exist');
  }

  if (pathParts.length === 0) {
    return _module;
  }

  return walkTree(pathParts, _module);
}

function createInlineSourceMap(map) {
  return "//# sourceMappingURL=data:application/json;base64," + btoa(JSON.stringify(map));
}

function createModuleContent (code, map) {
  return function () {
    return eval(
      // Wrap the function(require,exports,module){...} expression in
      // parentheses to force it to be parsed as an expression.
      // The sourceURL is treated as a prefix for the sources array
      // in the source map
      "(" + code + ")\n//# sourceURL=" + SOURCE_URL_PREFIX +
      "\n" + createInlineSourceMap(map)
    ).apply(this, arguments);
  }
}

function replaceFileContent(file, contents) {
  console.log('HMR: replacing module:', file.module.id);
<commit_msg>Fixes btoa unicode<commit_after>// TODO: add an api to Reify to update cached exports for a module
const ReifyEntry = require('/node_modules/meteor/modules/node_modules/reify/lib/runtime/entry.js')

const SOURCE_URL_PREFIX = "meteor://\u{1f4bb}app";

// Due to the bundler and proxy running in the same node process
// this could possibly be ran after the next build finished
// TODO: the builder should inject a build timestamp in the bundle
let lastUpdated = Date.now();
let appliedChangeSets = [];
let reloadId = 0;

let arch = __meteor_runtime_config__.isModern ? 'web.browser' : 'web.browser.legacy';
let enabled = arch === 'web.browser';

if (!enabled) {
  console.log(`HMR is not supported in ${arch}`);
}

let pendingReload = () => Reload._reload({ immediateMigration: true });
let mustReload = false;

function handleMessage(message) {
  if (message.type === 'register-failed') {
    if (message.reason === 'wrong-app') {
      console.log('HMR: A different app is running on', Meteor.absoluteUrl());
      console.log('HMR: Once you start this app again reload the page to re-enable HMR');
    } else if (message.reason === 'wrong-secret') {
      // TODO: we could wait until the first update to use hot code push
      // instead of reloading the page immediately in case the user has any
      // client state they want to keep for now.
      console.log('HMR: Have the wrong secret, possibly because Meteor was restarted');
      console.log('HMR: Reloading page to get new secret');
      mustReload = true;
      pendingReload();
    } else {
      console.log(`HMR: Register failed for unknown reason`, message);
    }
    return;
  }

  if (message.type !== 'changes') {
    throw new Error(`Unknown HMR message type ${message.type}`);
  }

  const hasUnreloadable = message.changeSets.find(changeSet => {
    return !changeSet.reloadable;
  });

  if (
    pendingReload &&
    hasUnreloadable ||
    message.changeSets.length === 0
  ) {
    if (message.eager) {
      // This was an attempt to reload before the build finishes
      // If we can't, we will wait until the build finishes to properly handle it
      return;
    }

    console.log('HMR: Unable to do HMR. Falling back to hot code push.')
    // Complete hot code push if we can not do hot module reload
    mustReload = true;
    return pendingReload();
  }

  // In case the user changed how a module works with HMR
  // in one of the earlier change sets, we want to apply each
  // change set one at a time in order.
  const succeeded = message.changeSets.filter(changeSet => {
    return !appliedChangeSets.includes(changeSet.id)
  }).every(changeSet => {
    const applied = applyChangeset(changeSet, message.eager);

    // We don't record if a module is unreplaceable
    // during an eager update so we can retry and
    // handle the failure after the build finishes
    if (applied || !message.eager) {
      appliedChangeSets.push(changeSet.id);
    }

    return applied;
  });

  if (message.eager) {
    // We will ignore any failures at this time
    // and wait to handle them until the build finishes
    return;
  }

  if (!succeeded) {
    if (pendingReload) {
      mustReload = true;
      return pendingReload();
    }

    throw new Error('HMR failed and unable to fallback to hot code push?');
  }

  if (message.changeSets.length > 0) {
    lastUpdated = message.changeSets[message.changeSets.length - 1].linkedAt;
  }
}

let socket;
let pendingMessages = [];

function send(message) {
  if (socket) {
    socket.send(JSON.stringify(message));
  } else {
    pendingMessages.push(message);
  }
}

function connect() {
  if (mustReload) {
    // The page will reload, no reason to
    // connect and show more logs in the console
    return;
  }

  const wsUrl = Meteor.absoluteUrl('/__meteor__hmr__/websocket').replace(/^.+\/\//, 'ws://');
  socket = new WebSocket(wsUrl);

  socket.addEventListener('close', function () {
    socket = null;
    console.log('HMR: websocket closed');
    setTimeout(connect, 2000);
  });

  socket.addEventListener('open', function () {
    console.log('HMR: connected');
    socket.send(JSON.stringify({
      type: 'register',
      arch,
      secret: __meteor_runtime_config__._hmrSecret,
      appId: __meteor_runtime_config__.appId,
    }));

    const toSend = pendingMessages.slice();
    pendingMessages = [];

    toSend.forEach(message => {
      send(message);
    });
  });

  socket.addEventListener('message', function (event) {
    handleMessage(JSON.parse(event.data));
  });

  socket.addEventListener('error', console.error);
}

connect();

function requestChanges() {
  send({
    type: 'request-changes',
    arch,
    after: lastUpdated
  });
}

function walkTree(pathParts, tree) {
  const part = pathParts.shift();
  const _module = tree.contents[part];

  if (!_module) {
    console.log(part, pathParts, _module, tree);
    throw new Error('not-exist');
  }

  if (pathParts.length === 0) {
    return _module;
  }

  return walkTree(pathParts, _module);
}

// btoa with unicode support
function utoa(data) {
  return btoa(unescape(encodeURIComponent(data)));
}

function createInlineSourceMap(map) {
  return "//# sourceMappingURL=data:application/json;base64," + utoa(JSON.stringify(map));
}

function createModuleContent (code, map) {
  return function () {
    return eval(
      // Wrap the function(require,exports,module){...} expression in
      // parentheses to force it to be parsed as an expression.
      // The sourceURL is treated as a prefix for the sources array
      // in the source map
      "(" + code + ")\n//# sourceURL=" + SOURCE_URL_PREFIX +
      "\n" + createInlineSourceMap(map)
    ).apply(this, arguments);
  }
}

function replaceFileContent(file, contents) {
  console.log('HMR: replacing module:', file.module.id);

{'fraction_non_alphanumeric': 0.1227765726681128, 'fraction_numerical': 0.0022559652928416485, 'mean_word_length': 3.1821480406386065, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3212937', 'n_tokens_mistral': 3525, 'n_tokens_neox': 3410, 'n_words': 1082}