'use strict';

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

const unplugin$1 = require('unplugin');
const pathe = require('pathe');
const createDebug = require('debug');
const fg = require('fast-glob');
const shared = require('@intlify/shared');
const pluginutils = require('@rollup/pluginutils');
const bundleUtils = require('@intlify/bundle-utils');
const compilerSfc = require('@vue/compiler-sfc');
const fs = require('fs');
const pc = require('picocolors');

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

const createDebug__default = /*#__PURE__*/_interopDefaultCompat(createDebug);
const fg__default = /*#__PURE__*/_interopDefaultCompat(fg);
const pc__default = /*#__PURE__*/_interopDefaultCompat(pc);

function parseVueRequest(id) {
  const [filename, rawQuery] = id.split(`?`, 2);
  const params = new URLSearchParams(rawQuery);
  const ret = {};
  const langPart = Object.keys(Object.fromEntries(params)).find(
    (key) => /lang\./i.test(key)
  );
  ret.vue = params.has("vue");
  ret.global = params.has("global");
  ret.src = params.has("src");
  ret.raw = params.has("raw");
  if (params.has("type")) {
    ret.type = params.get("type");
  }
  if (params.has("blockType")) {
    ret.blockType = params.get("blockType");
  }
  if (params.has("index")) {
    ret.index = Number(params.get("index"));
  }
  if (params.has("locale")) {
    ret.locale = params.get("locale");
  }
  if (langPart) {
    const [, lang] = langPart.split(".");
    ret.lang = lang;
  } else if (params.has("lang")) {
    ret.lang = params.get("lang");
  }
  if (params.has("issuerPath")) {
    ret.issuerPath = params.get("issuerPath");
  }
  return {
    filename,
    query: ret
  };
}

function warn(...args) {
  console.warn(pc__default.yellow(pc__default.bold(`[unplugin-vue-i18n] `)), ...args);
}
function error(...args) {
  console.error(pc__default.red(pc__default.bold(`[unplugin-vue-i18n] `)), ...args);
}
async function getRaw(path) {
  return fs.promises.readFile(path, { encoding: "utf-8" });
}
function raiseError(message) {
  throw new Error(`[unplugin-vue-i18n] ${message}`);
}

const INTLIFY_BUNDLE_IMPORT_ID = "@intlify/unplugin-vue-i18n/messages";
const VIRTUAL_PREFIX = "\0";
const debug = createDebug__default("unplugin-vue-i18n");
const installedPkg = bundleUtils.checkInstallPackage("@intlify/unplugin-vue-i18n", debug);
const vueI18nVersion = bundleUtils.getVueI18nVersion(debug);
if (vueI18nVersion === "8") {
  warn(`vue-i18n@8 is not supported, since sinece Vue 2 was EOL on 2023.`);
}
const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
  debug("plugin options:", options, meta.framework);
  if (!["vite", "webpack"].includes(meta.framework)) {
    raiseError(`This plugin is supported 'vite' and 'webpack' only`);
  }
  let onlyLocales = [];
  if (options.onlyLocales) {
    onlyLocales = Array.isArray(options.onlyLocales) ? options.onlyLocales : [options.onlyLocales];
  }
  let include = options.include;
  let exclude = null;
  if (include) {
    if (shared.isArray(include)) {
      include = include.map((item) => pathe.normalize(item));
    } else if (shared.isString(include)) {
      include = pathe.normalize(include);
    }
  } else {
    exclude = "**/**";
  }
  const filter = pluginutils.createFilter(include, exclude);
  const forceStringify = !!options.forceStringify;
  const defaultSFCLang = shared.isString(options.defaultSFCLang) ? options.defaultSFCLang : "json";
  const globalSFCScope = !!options.globalSFCScope;
  const useClassComponent = !!options.useClassComponent;
  const runtimeOnly = shared.isBoolean(options.runtimeOnly) ? options.runtimeOnly : true;
  debug("runtimeOnly", runtimeOnly);
  const jitCompilation = shared.isBoolean(options.jitCompilation) ? options.jitCompilation : true;
  debug("jitCompilation", jitCompilation);
  const dropMessageCompiler = jitCompilation ? !!options.dropMessageCompiler : false;
  debug("dropMessageCompiler", dropMessageCompiler);
  const compositionOnly = installedPkg === "vue-i18n" ? shared.isBoolean(options.compositionOnly) ? options.compositionOnly : true : true;
  debug("compositionOnly", compositionOnly);
  const fullInstall = installedPkg === "vue-i18n" ? shared.isBoolean(options.fullInstall) ? options.fullInstall : true : false;
  debug("fullInstall", fullInstall);
  const ssrBuild = !!options.ssr;
  debug("ssr", ssrBuild);
  const useVueI18nImportName = options.useVueI18nImportName;
  if (useVueI18nImportName != null) {
    warn(`'useVueI18nImportName' option is experimental`);
  }
  debug("useVueI18nImportName", useVueI18nImportName);
  const getVueI18nAliasName = () => vueI18nVersion === "9" ? "vue-i18n" : vueI18nVersion === "unknown" && installedPkg === "petite-vue-i18n" && shared.isBoolean(useVueI18nImportName) && useVueI18nImportName ? "vue-i18n" : installedPkg;
  const getVueI18nAliasPath = (aliasName, { ssr = false, runtimeOnly: runtimeOnly2 = false }) => {
    return `${aliasName}/dist/${installedPkg}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
  };
  const allowDynamic = !!options.allowDynamic;
  debug("allowDynamic", allowDynamic);
  const strictMessage = shared.isBoolean(options.strictMessage) ? options.strictMessage : true;
  debug("strictMessage", strictMessage);
  const escapeHtml = !!options.escapeHtml;
  debug("escapeHtml", escapeHtml);
  let isProduction = false;
  let sourceMap = false;
  const vueI18nAliasName = getVueI18nAliasName();
  return {
    name: "unplugin-vue-i18n",
    /**
     * NOTE:
     *
     * For vite, If we have json (including SFC's custom block),
     * transform it first because it will be transformed into javascript code by `vite:json` plugin.
     *
     * For webpack, This plugin will handle with ‘post’, because vue-loader generate the request query.
     */
    enforce: meta.framework === "vite" ? "pre" : "post",
    vite: {
      config(config, { command }) {
        config.resolve = normalizeConfigResolveAlias(
          config.resolve,
          meta.framework
        );
        if (command === "build") {
          debug(`vue-i18n alias name: ${vueI18nAliasName}`);
          if (shared.isArray(config.resolve.alias)) {
            config.resolve.alias.push({
              find: vueI18nAliasName,
              replacement: getVueI18nAliasPath(vueI18nAliasName, {
                ssr: ssrBuild,
                runtimeOnly
              })
            });
          } else if (shared.isObject(config.resolve.alias)) {
            config.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName, {
              ssr: ssrBuild,
              runtimeOnly
            });
          }
          debug(
            `set ${vueI18nAliasName} runtime only: ${getVueI18nAliasPath(
              vueI18nAliasName,
              {
                ssr: ssrBuild,
                runtimeOnly
              }
            )}`
          );
        } else if (command === "serve" && installedPkg === "petite-vue-i18n" && useVueI18nImportName) {
          config.resolve = normalizeConfigResolveAlias(
            config.resolve,
            meta.framework
          );
          if (shared.isArray(config.resolve.alias)) {
            config.resolve.alias.push({
              find: vueI18nAliasName,
              replacement: `petite-vue-i18n/dist/petite-vue-i18n.esm-bundler.js`
            });
          } else {
            config.resolve.alias[vueI18nAliasName] = `petite-vue-i18n/dist/petite-vue-i18n.esm-bundler.js`;
          }
          debug(`petite-vue-i18n alias name: ${vueI18nAliasName}`);
        }
        config.define = config.define || {};
        config.define["__VUE_I18N_LEGACY_API__"] = !compositionOnly;
        debug(
          `set __VUE_I18N_LEGACY_API__ is '${config.define["__VUE_I18N_LEGACY_API__"]}'`
        );
        config.define["__VUE_I18N_FULL_INSTALL__"] = fullInstall;
        debug(
          `set __VUE_I18N_FULL_INSTALL__ is '${config.define["__VUE_I18N_FULL_INSTALL__"]}'`
        );
        config.define["__INTLIFY_JIT_COMPILATION__"] = jitCompilation;
        debug(
          `set __INTLIFY_JIT_COMPILATION__ is '${config.define["__INTLIFY_JIT_COMPILATION__"]}'`
        );
        config.define["__INTLIFY_DROP_MESSAGE_COMPILER__"] = dropMessageCompiler;
        debug(
          `set __INTLIFY_DROP_MESSAGE_COMPILER__ is '${config.define["__INTLIFY_DROP_MESSAGE_COMPILER__"]}'`
        );
        config.define["__VUE_I18N_PROD_DEVTOOLS__"] = false;
      },
      configResolved(config) {
        isProduction = config.isProduction;
        sourceMap = config.command === "build" ? !!config.build.sourcemap : false;
        debug(
          `configResolved: isProduction = ${isProduction}, sourceMap = ${sourceMap}`
        );
        const jsonPlugin = config.plugins.find((p) => p.name === "vite:json");
        if (jsonPlugin) {
          const orgTransform = jsonPlugin.transform;
          jsonPlugin.transform = async function(code, id) {
            if (!/\.json$/.test(id) || filter(id)) {
              return;
            }
            const { query } = parseVueRequest(id);
            if (query.vue) {
              return;
            }
            debug("org json plugin");
            return orgTransform.apply(this, [code, id]);
          };
        }
        const esbuildPlugin = config.plugins.find(
          (p) => p.name === "vite:esbuild"
        );
        if (esbuildPlugin) {
          const orgTransform = esbuildPlugin.transform;
          esbuildPlugin.transform = async function(code, id) {
            const result = await orgTransform.apply(this, [
              code,
              id
            ]);
            if (result == null) {
              return result;
            }
            const { filename, query } = parseVueRequest(id);
            if (!query.vue && filter(id) && /\.[c|m]?ts$/.test(id)) {
              const [_code, inSourceMap] = shared.isString(result) ? [result, void 0] : [result.code, result.map];
              let langInfo = defaultSFCLang;
              langInfo = pathe.parse(filename).ext;
              const generate = getGenerator(langInfo);
              const parseOptions = getOptions(
                filename,
                isProduction,
                query,
                sourceMap,
                {
                  inSourceMap,
                  isGlobal: globalSFCScope,
                  useClassComponent,
                  allowDynamic,
                  strictMessage,
                  escapeHtml,
                  jit: jitCompilation,
                  onlyLocales,
                  forceStringify
                }
              );
              debug("parseOptions", parseOptions);
              const { code: generatedCode, map } = generate(_code, parseOptions);
              debug("generated code", generatedCode);
              debug("sourcemap", map, sourceMap);
              if (_code === generatedCode)
                return;
              return {
                code: generatedCode,
                // prettier-ignore
                map: jitCompilation ? { mappings: "" } : sourceMap ? map : { mappings: "" }
                // eslint-disable-line @typescript-eslint/no-explicit-any
              };
            } else {
              return result;
            }
          };
        }
      },
      async handleHotUpdate({ file, server }) {
        if (/\.(json5?|ya?ml)$/.test(file)) {
          const module = server.moduleGraph.getModuleById(
            asVirtualId(INTLIFY_BUNDLE_IMPORT_ID, meta.framework)
          );
          if (module) {
            server.moduleGraph.invalidateModule(module);
            return [module];
          }
        }
      }
    },
    webpack(compiler) {
      isProduction = compiler.options.mode !== "development";
      sourceMap = !!compiler.options.devtool;
      debug(`webpack: isProduction = ${isProduction}, sourceMap = ${sourceMap}`);
      compiler.options.resolve = normalizeConfigResolveAlias(
        compiler.options.resolve,
        meta.framework
      );
      if (isProduction) {
        compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName, {
          ssr: ssrBuild,
          runtimeOnly
        });
        debug(
          `set ${vueI18nAliasName}: ${getVueI18nAliasPath(vueI18nAliasName, {
            ssr: ssrBuild,
            runtimeOnly
          })}`
        );
      } else if (!isProduction && installedPkg === "petite-vue-i18n" && useVueI18nImportName) {
        compiler.options.resolve.alias[vueI18nAliasName] = `petite-vue-i18n/dist/petite-vue-i18n.esm-bundler.js`;
        debug(`petite-vue-i18n alias name: ${vueI18nAliasName}`);
      }
      loadWebpack().then((webpack) => {
        if (webpack) {
          compiler.options.plugins.push(
            new webpack.DefinePlugin({
              __VUE_I18N_LEGACY_API__: JSON.stringify(compositionOnly),
              __VUE_I18N_FULL_INSTALL__: JSON.stringify(fullInstall),
              __INTLIFY_PROD_DEVTOOLS__: "false"
            })
          );
          debug(`set __VUE_I18N_LEGACY_API__ is '${compositionOnly}'`);
          debug(`set __VUE_I18N_FULL_INSTALL__ is '${fullInstall}'`);
        } else {
          debug("ignore vue-i18n feature flags with webpack.DefinePlugin");
        }
      });
      if (compiler.options.module) {
        compiler.options.module.rules.push({
          test: /\.(json5?|ya?ml)$/,
          type: "javascript/auto",
          include(resource) {
            return filter(resource);
          }
        });
      }
    },
    resolveId(id, importer) {
      debug("resolveId", id, importer);
      if (id === INTLIFY_BUNDLE_IMPORT_ID) {
        return asVirtualId(id, meta.framework);
      }
    },
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    async load(id) {
      debug("load", id);
      const { query } = parseVueRequest(id);
      if (INTLIFY_BUNDLE_IMPORT_ID === getVirtualId(id, meta.framework) && include) {
        let resourcePaths = [];
        const includePaths = shared.isArray(include) ? include : [include];
        for (const inc of includePaths) {
          resourcePaths = [...resourcePaths, ...await fg__default(inc)];
        }
        resourcePaths = resourcePaths.filter(
          (el, pos) => resourcePaths.indexOf(el) === pos
        );
        const code = await generateBundleResources(
          resourcePaths,
          query,
          isProduction,
          {
            forceStringify,
            strictMessage,
            escapeHtml,
            useClassComponent
          }
        );
        return {
          code,
          map: { mappings: "" }
        };
      }
    },
    transformInclude(id) {
      debug("transformInclude", id);
      if (meta.framework === "vite") {
        return true;
      } else {
        const { filename } = parseVueRequest(id);
        return filename.endsWith("vue") || filename.endsWith(INTLIFY_BUNDLE_IMPORT_ID) || /\.(json5?|ya?ml)$/.test(filename) && filter(filename);
      }
    },
    async transform(code, id) {
      const { filename, query } = parseVueRequest(id);
      debug("transform", id, JSON.stringify(query), filename);
      let langInfo = defaultSFCLang;
      let inSourceMap;
      if (!query.vue) {
        if (/\.(json5?|ya?ml|[c|m]?js)$/.test(id) && filter(id)) {
          langInfo = pathe.parse(filename).ext;
          const generate = getGenerator(langInfo);
          const parseOptions = getOptions(
            filename,
            isProduction,
            query,
            sourceMap,
            {
              inSourceMap,
              isGlobal: globalSFCScope,
              useClassComponent,
              allowDynamic,
              strictMessage,
              escapeHtml,
              jit: jitCompilation,
              onlyLocales,
              forceStringify
            }
          );
          debug("parseOptions", parseOptions);
          const { code: generatedCode, map } = generate(code, parseOptions);
          debug("generated code", generatedCode);
          debug("sourcemap", map, sourceMap);
          if (code === generatedCode)
            return;
          return {
            code: generatedCode,
            // prettier-ignore
            map: jitCompilation ? { mappings: "" } : sourceMap ? map : { mappings: "" }
            // eslint-disable-line @typescript-eslint/no-explicit-any
          };
        }
      } else {
        if (isCustomBlock(query)) {
          if (shared.isString(query.lang)) {
            langInfo = query.src ? query.lang === "i18n" ? defaultSFCLang : query.lang : query.lang;
          } else if (defaultSFCLang) {
            langInfo = defaultSFCLang;
          }
          debug("langInfo", langInfo);
          const generate = /\.?json5?/.test(langInfo) ? bundleUtils.generateJSON : bundleUtils.generateYAML;
          const parseOptions = getOptions(
            filename,
            isProduction,
            query,
            sourceMap,
            {
              inSourceMap,
              isGlobal: globalSFCScope,
              useClassComponent,
              jit: jitCompilation,
              strictMessage,
              escapeHtml,
              onlyLocales,
              forceStringify
            }
          );
          debug("parseOptions", parseOptions);
          const source = await getCode(
            code,
            filename,
            sourceMap,
            query,
            meta.framework
          );
          const { code: generatedCode, map } = generate(source, parseOptions);
          debug("generated code", generatedCode);
          debug("sourcemap", map, sourceMap);
          if (code === generatedCode)
            return;
          return {
            code: generatedCode,
            // prettier-ignore
            map: jitCompilation ? { mappings: "" } : sourceMap ? map : { mappings: "" }
            // eslint-disable-line @typescript-eslint/no-explicit-any
          };
        }
      }
    }
  };
});
function getGenerator(ext, defaultGen = bundleUtils.generateJSON) {
  return /\.?json5?$/.test(ext) ? bundleUtils.generateJSON : /\.ya?ml$/.test(ext) ? bundleUtils.generateYAML : /\.([c|m]?js|[c|m]?ts)$/.test(ext) ? bundleUtils.generateJavaScript : defaultGen;
}
function normalizeConfigResolveAlias(resolve, framework) {
  if (resolve && resolve.alias) {
    return resolve;
  }
  if (!resolve) {
    if (framework === "vite") {
      return { alias: [] };
    } else if (framework === "webpack") {
      return { alias: {} };
    }
  } else if (!resolve.alias) {
    if (framework === "vite") {
      resolve.alias = [];
      return resolve;
    } else if (framework === "webpack") {
      resolve.alias = {};
      return resolve;
    }
  }
}
async function loadWebpack() {
  let webpack = null;
  try {
    webpack = await import('webpack').then((m) => m.default || m);
  } catch (e) {
    warn(`webpack not found, please install webpack.`);
  }
  return webpack;
}
async function generateBundleResources(resources, query, isProduction, {
  forceStringify = false,
  isGlobal = false,
  onlyLocales = [],
  strictMessage = true,
  escapeHtml = false,
  useClassComponent = false,
  jit = false
}) {
  const codes = [];
  for (const res of resources) {
    debug(`${res} bundle loading ...`);
    if (/\.(json5?|ya?ml)$/.test(res)) {
      const { ext, name } = pathe.parse(res);
      const source = await getRaw(res);
      const generate = /json5?/.test(ext) ? bundleUtils.generateJSON : bundleUtils.generateYAML;
      const parseOptions = getOptions(res, isProduction, {}, false, {
        isGlobal,
        useClassComponent,
        jit,
        onlyLocales,
        strictMessage,
        escapeHtml,
        forceStringify
      });
      parseOptions.type = "bare";
      const { code } = generate(source, parseOptions);
      debug("generated code", code);
      codes.push(`${JSON.stringify(name)}: ${code}`);
    }
  }
  return `const isObject = (item) => item && typeof item === 'object' && !Array.isArray(item);

const mergeDeep = (target, ...sources) => {
  if (!sources.length) return target;
  const source = sources.shift();

  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }

  return mergeDeep(target, ...sources);
}

export default mergeDeep({},
  ${codes.map((code) => `{${code}}`).join(",\n")}
);`;
}
async function getCode(source, filename, sourceMap, query, framework = "vite") {
  const { index, issuerPath } = query;
  if (!shared.isNumber(index)) {
    raiseError(`unexpected index: ${index}`);
  }
  if (framework === "webpack") {
    if (issuerPath) {
      debug(`getCode (webpack) ${index} via issuerPath`, issuerPath);
      return await getRaw(filename);
    } else {
      const result = compilerSfc.parse(await getRaw(filename), {
        sourceMap,
        filename
      });
      const block = result.descriptor.customBlocks[index];
      if (block) {
        const code = block.src ? await getRaw(block.src) : block.content;
        debug(`getCode (webpack) ${index} from SFC`, code);
        return code;
      } else {
        return source;
      }
    }
  } else {
    return source;
  }
}
function isCustomBlock(query) {
  return !shared.isEmptyObject(query) && "vue" in query && (query["type"] === "custom" || // for vite (@vite-plugin-vue)
  query["type"] === "i18n" || // for webpack (vue-loader)
  query["blockType"] === "i18n");
}
function getOptions(filename, isProduction, query, sourceMap, {
  inSourceMap = void 0,
  forceStringify = false,
  isGlobal = false,
  onlyLocales = [],
  useClassComponent = false,
  allowDynamic = false,
  strictMessage = true,
  escapeHtml = false,
  jit = false
}) {
  const mode = isProduction ? "production" : "development";
  const baseOptions = {
    filename,
    sourceMap,
    inSourceMap,
    forceStringify,
    useClassComponent,
    allowDynamic,
    strictMessage,
    escapeHtml,
    jit,
    onlyLocales,
    env: mode,
    onWarn: (msg) => {
      warn(`${filename} ${msg}`);
    },
    onError: (msg, extra) => {
      const codeFrame = shared.generateCodeFrame(
        extra?.source || extra?.location?.source || "",
        extra?.location?.start.column,
        extra?.location?.end.column
      );
      const errMssage = `${msg} (error code: ${extra?.code}) in ${filename}
  target message: ${extra?.source}
  target message path: ${extra?.path}

  ${codeFrame}
`;
      error(errMssage);
      throw new Error(errMssage);
    }
  };
  if (isCustomBlock(query)) {
    return shared.assign(baseOptions, {
      type: "sfc",
      locale: shared.isString(query.locale) ? query.locale : "",
      isGlobal: isGlobal || !!query.global
    });
  } else {
    return shared.assign(baseOptions, {
      type: "plain",
      isGlobal: false
    });
  }
}
function getVirtualId(id, framework = "vite") {
  return framework === "vite" ? id.startsWith(VIRTUAL_PREFIX) ? id.slice(VIRTUAL_PREFIX.length) : "" : id;
}
function asVirtualId(id, framework = "vite") {
  return framework === "vite" ? VIRTUAL_PREFIX + id : id;
}

exports.default = unplugin;
exports.unplugin = unplugin;
