'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var path = require('path');
var esbuild = require('esbuild');
var loaderUtils = require('loader-utils');
var getTsconfig = require('get-tsconfig');
var webpackSources = require('webpack-sources');
var ModuleFilenameHelpers_js = require('webpack/lib/ModuleFilenameHelpers.js');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var path__default = /*#__PURE__*/_interopDefaultLegacy(path);

let foundTsconfig;
let fileMatcher;
async function ESBuildLoader(source) {
  var _a, _b, _c;
  const done = this.async();
  const options = loaderUtils.getOptions(this);
  const {
    implementation,
    tsconfig,
    ...esbuildTransformOptions
  } = options;
  if (implementation && typeof implementation.transform !== "function") {
    done(
      new TypeError(
        `esbuild-loader: options.implementation.transform must be an ESBuild transform function. Received ${typeof implementation.transform}`
      )
    );
    return;
  }
  const transform = (_a = implementation == null ? void 0 : implementation.transform) != null ? _a : esbuild.transform;
  const transformOptions = {
    ...esbuildTransformOptions,
    target: (_b = options.target) != null ? _b : "es2015",
    loader: (_c = options.loader) != null ? _c : "default",
    sourcemap: this.sourceMap,
    sourcefile: this.resourcePath
  };
  if (!("tsconfigRaw" in transformOptions)) {
    if (!fileMatcher) {
      const tsconfigPath = tsconfig && path__default["default"].resolve(tsconfig);
      foundTsconfig = tsconfigPath ? {
        config: getTsconfig.parseTsconfig(tsconfigPath),
        path: tsconfigPath
      } : getTsconfig.getTsconfig();
      if (foundTsconfig) {
        fileMatcher = getTsconfig.createFilesMatcher(foundTsconfig);
      }
    }
    if (fileMatcher) {
      transformOptions.tsconfigRaw = fileMatcher(
        this.resourcePath
      );
    }
  }
  try {
    const { code, map } = await transform(source, transformOptions);
    done(null, code, map && JSON.parse(map));
  } catch (error) {
    done(error);
  }
}

var version = "3.0.1";

const isJsFile = /\.[cm]?js(?:\?.*)?$/i;
const isCssFile = /\.css(?:\?.*)?$/i;
const pluginName = "EsbuildPlugin";
const transformAssets = async (options, transform, compilation, useSourceMap) => {
  const { compiler } = compilation;
  const sources = "webpack" in compiler && compiler.webpack.sources;
  const SourceMapSource = sources ? sources.SourceMapSource : webpackSources.SourceMapSource;
  const RawSource = sources ? sources.RawSource : webpackSources.RawSource;
  const {
    css: minifyCss,
    include,
    exclude,
    ...transformOptions
  } = options;
  const assets = compilation.getAssets().filter((asset) => !asset.info.minimized && (isJsFile.test(asset.name) || minifyCss && isCssFile.test(asset.name)) && ModuleFilenameHelpers_js.matchObject(
    { include, exclude },
    asset.name
  ));
  await Promise.all(assets.map(async (asset) => {
    const assetIsCss = isCssFile.test(asset.name);
    let source;
    let map = null;
    if (useSourceMap) {
      if (asset.source.sourceAndMap) {
        const sourceAndMap = asset.source.sourceAndMap();
        source = sourceAndMap.source;
        map = sourceAndMap.map;
      } else {
        source = asset.source.source();
        if (asset.source.map) {
          map = asset.source.map();
        }
      }
    } else {
      source = asset.source.source();
    }
    const sourceAsString = source.toString();
    const result = await transform(sourceAsString, {
      ...transformOptions,
      loader: assetIsCss ? "css" : transformOptions.loader,
      sourcemap: useSourceMap,
      sourcefile: asset.name
    });
    if (result.legalComments) {
      compilation.emitAsset(
        `${asset.name}.LEGAL.txt`,
        new RawSource(result.legalComments)
      );
    }
    compilation.updateAsset(
      asset.name,
      result.map ? new SourceMapSource(
        result.code,
        asset.name,
        result.map,
        sourceAsString,
        map,
        true
      ) : new RawSource(result.code),
      {
        ...asset.info,
        minimized: true
      }
    );
  }));
};
function EsbuildPlugin({
  implementation,
  ...options
} = {}) {
  var _a;
  if (implementation && typeof implementation.transform !== "function") {
    throw new TypeError(
      `[${pluginName}] implementation.transform must be an esbuild transform function. Received ${typeof implementation.transform}`
    );
  }
  const transform = (_a = implementation == null ? void 0 : implementation.transform) != null ? _a : esbuild.transform;
  const hasGranularMinificationConfig = "minifyIdentifiers" in options || "minifySyntax" in options || "minifyWhitespace" in options;
  if (!hasGranularMinificationConfig) {
    options.minify = true;
  }
  return {
    apply(compiler) {
      if (!("format" in options)) {
        const { target } = compiler.options;
        const isWebTarget = Array.isArray(target) ? target.includes("web") : target === "web";
        const wontGenerateHelpers = !options.target || (Array.isArray(options.target) ? options.target.length === 1 && options.target[0] === "esnext" : options.target === "esnext");
        if (isWebTarget && !wontGenerateHelpers) {
          options.format = "iife";
        }
      }
      compiler.hooks.compilation.tap(pluginName, (compilation) => {
        const meta = JSON.stringify({
          name: "esbuild-loader",
          version,
          options
        });
        compilation.hooks.chunkHash.tap(
          pluginName,
          (_, hash) => hash.update(meta)
        );
        let useSourceMap = false;
        compilation.hooks.finishModules.tap(
          pluginName,
          (modules) => {
            const firstModule = Array.isArray(modules) ? modules[0] : modules.values().next().value;
            useSourceMap = firstModule.useSourceMap;
          }
        );
        if ("processAssets" in compilation.hooks) {
          compilation.hooks.processAssets.tapPromise(
            {
              name: pluginName,
              stage: compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
              additionalAssets: true
            },
            () => transformAssets(options, transform, compilation, useSourceMap)
          );
          compilation.hooks.statsPrinter.tap(pluginName, (statsPrinter) => {
            statsPrinter.hooks.print.for("asset.info.minimized").tap(
              pluginName,
              (minimized, { green, formatFlag }) => minimized ? green(formatFlag("minimized")) : void 0
            );
          });
        } else {
          compilation.hooks.optimizeChunkAssets.tapPromise(
            pluginName,
            () => transformAssets(options, transform, compilation, useSourceMap)
          );
        }
      });
    }
  };
}

exports.EsbuildPlugin = EsbuildPlugin;
exports["default"] = ESBuildLoader;
