"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.ChunksToHermesBytecodePlugin = void 0;
var _nodeFs = _interopRequireDefault(require("node:fs"));
var _nodePath = _interopRequireDefault(require("node:path"));
var _index = require("./utils/index.js");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
 * {@link ChunksToHermesBytecodePlugin} configuration options.
 */

/**
 * Enable Hermes bytecode compilation for the given chunks.
 * This plugin is intended to be used with the `webpack-bundle` command.
 * It will transform the bundle into Hermes bytecode and replace the original bundle with the bytecode.
 * It will also compose the source maps generated by webpack and Hermes.
 *
 * Note: This plugin should only be used for production builds.
 * It is not possible to use this plugin for development builds.
 *
 * Note: You should exclude `index.bundle` from being transformed.
 * The `index.bundle` file is transformed by `react-native` after enabling Hermes in your project.
 *
 * @example ```js
 * // webpack.config.mjs
 * import * as Repack from '@callstack/repack';
 *
 * // ...
 * plugins: [
 *   new Repack.ChunksToHermesBytecodePlugin({
 *    enabled: mode === 'production',
 *    test: /\.(js)?bundle$/,
 *    exclude: /index.bundle$/,
 *   }),
 * ]
 * ```
 *
 * @category Webpack Plugin
 */
class ChunksToHermesBytecodePlugin {
  constructor(config) {
    this.config = config;
  }
  apply(compiler) {
    const logger = compiler.getInfrastructureLogger('RepackChunksToHermesBytecodePlugin');
    if (!this.config.enabled) {
      logger.debug('Skipping hermes compilation');
      return;
    }

    /**
     * This plugin will only transform assets that are emitted after the compilation.
     * To ensure that asset is always emitted we disable the `compareBeforeEmit` option
     * which is enabled by default in Webpack.
     *
     * `compareBeforeEmit` option is used to skip emitting assets that are identical to the
     * ones present in build directory, which might result in transformation being
     * skipped when there is a untransformed bundle present in the build directory.
     */
    compiler.options.output.compareBeforeEmit = !!this.config.compareBeforeEmit;
    const reactNativePath = this.config.reactNativePath || _nodePath.default.join(compiler.context, 'node_modules', 'react-native');
    const hermesCLIPath = this.config.hermesCLIPath || (0, _index.getHermesCLIPath)(reactNativePath);
    compiler.hooks.assetEmitted.tapPromise({
      name: 'RepackChunksToHermesBytecodePlugin',
      stage: 10
    }, async (file, {
      outputPath
    }) => {
      const shouldTransformAsset = compiler.webpack.ModuleFilenameHelpers.matchObject({
        test: this.config.test,
        include: this.config.include,
        exclude: this.config.exclude
      }, file);
      if (!shouldTransformAsset) {
        return;
      }
      const bundlePath = _nodePath.default.join(outputPath, file);
      const sourceMapPath = `${bundlePath}.map`;
      const useSourceMaps = await _nodeFs.default.promises.access(sourceMapPath).then(() => true).catch(() => false);
      logger.debug(`Starting hermes compilation for asset: ${bundlePath}`);
      const {
        sourceMap: hermesSourceMapPath
      } = await (0, _index.transformBundleToHermesBytecode)({
        hermesCLIPath,
        useSourceMaps,
        bundlePath
      });
      logger.info(`Asset transformed: ${file}`);
      if (useSourceMaps) {
        await (0, _index.composeSourceMaps)({
          reactNativePath,
          packagerMapPath: sourceMapPath,
          compilerMapPath: hermesSourceMapPath
        });
        logger.info(`Asset sourceMap transformed: ${file}.map`);
      }
    });
  }
}
exports.ChunksToHermesBytecodePlugin = ChunksToHermesBytecodePlugin;
//# sourceMappingURL=ChunksToHermesBytecodePlugin.js.map