990 lines
32 KiB
JavaScript
990 lines
32 KiB
JavaScript
|
|
import { createUnplugin } from 'unplugin';
|
|||
|
|
import createDebug from 'debug';
|
|||
|
|
import pc from 'picocolors';
|
|||
|
|
import path from 'node:path';
|
|||
|
|
import { normalize, parse } from 'pathe';
|
|||
|
|
import { isArray, isString, isBoolean, assign, isNumber, isEmptyObject, generateCodeFrame } from '@intlify/shared';
|
|||
|
|
import { generateJSON, generateYAML, generateJavaScript } from '@intlify/bundle-utils';
|
|||
|
|
import { createFilter } from '@rollup/pluginutils';
|
|||
|
|
import fg from 'fast-glob';
|
|||
|
|
import { promises } from 'node:fs';
|
|||
|
|
import { parse as parse$1 } from 'vue/compiler-sfc';
|
|||
|
|
import { transformVTDirective } from '@intlify/vue-i18n-extensions';
|
|||
|
|
import { analyze } from '@typescript-eslint/scope-manager';
|
|||
|
|
import { parse as parse$2, simpleTraverse, AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
|
|||
|
|
import eslintUitls from '@eslint-community/eslint-utils';
|
|||
|
|
|
|||
|
|
const PKG_NAME = "unplugin-vue-i18n";
|
|||
|
|
|
|||
|
|
function warn(...args) {
|
|||
|
|
console.warn(pc.yellow(pc.bold(`[${PKG_NAME}] `)), ...args);
|
|||
|
|
}
|
|||
|
|
function error(...args) {
|
|||
|
|
console.error(pc.red(pc.bold(`[${PKG_NAME}] `)), ...args);
|
|||
|
|
}
|
|||
|
|
function raiseError(message) {
|
|||
|
|
throw new Error(`[${PKG_NAME}] ${message}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function resolveNamespace(name) {
|
|||
|
|
return `${PKG_NAME}:${name}`;
|
|||
|
|
}
|
|||
|
|
function getVitePlugin(config, name) {
|
|||
|
|
return config.plugins.find((p) => p.name === name);
|
|||
|
|
}
|
|||
|
|
function checkVuePlugin(vuePlugin) {
|
|||
|
|
if (vuePlugin == null || !vuePlugin.api) {
|
|||
|
|
error(
|
|||
|
|
"`@vitejs/plugin-vue` plugin is not found or invalid version. Please install `@vitejs/plugin-vue` v4.3.4 or later version."
|
|||
|
|
);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
const isWindows = typeof process !== "undefined" && process.platform === "win32";
|
|||
|
|
const windowsSlashRE = /\\/g;
|
|||
|
|
function slash(p) {
|
|||
|
|
return p.replace(windowsSlashRE, "/");
|
|||
|
|
}
|
|||
|
|
function normalizePath(id) {
|
|||
|
|
return path.posix.normalize(isWindows ? slash(id) : id);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function resolveOptions(options) {
|
|||
|
|
const moduleType = options.module || "vue-i18n";
|
|||
|
|
let onlyLocales = [];
|
|||
|
|
if (options.onlyLocales) {
|
|||
|
|
onlyLocales = isArray(options.onlyLocales) ? options.onlyLocales : [options.onlyLocales];
|
|||
|
|
}
|
|||
|
|
let include = options.include;
|
|||
|
|
let exclude = void 0;
|
|||
|
|
if (include) {
|
|||
|
|
if (isArray(include)) {
|
|||
|
|
include = include.map((item) => normalize(item));
|
|||
|
|
} else if (isString(include)) {
|
|||
|
|
include = normalize(include);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
exclude = "**/**";
|
|||
|
|
}
|
|||
|
|
const forceStringify = !!options.forceStringify;
|
|||
|
|
const defaultSFCLang = isString(options.defaultSFCLang) ? options.defaultSFCLang : "json";
|
|||
|
|
const globalSFCScope = !!options.globalSFCScope;
|
|||
|
|
const runtimeOnly = isBoolean(options.runtimeOnly) ? options.runtimeOnly : true;
|
|||
|
|
const dropMessageCompiler = !!options.dropMessageCompiler;
|
|||
|
|
const compositionOnly = moduleType === "vue-i18n" ? isBoolean(options.compositionOnly) ? options.compositionOnly : true : true;
|
|||
|
|
const fullInstall = moduleType === "vue-i18n" ? isBoolean(options.fullInstall) ? options.fullInstall : true : false;
|
|||
|
|
const ssrBuild = !!options.ssr;
|
|||
|
|
const allowDynamic = !!options.allowDynamic;
|
|||
|
|
const strictMessage = isBoolean(options.strictMessage) ? options.strictMessage : true;
|
|||
|
|
const escapeHtml = !!options.escapeHtml;
|
|||
|
|
const optimizeTranslationDirective = isString(options.optimizeTranslationDirective) || isArray(options.optimizeTranslationDirective) ? options.optimizeTranslationDirective : !!options.optimizeTranslationDirective;
|
|||
|
|
const translationIdentifiers = /* @__PURE__ */ new Map();
|
|||
|
|
const transformI18nBlock = typeof options.transformI18nBlock === "function" ? options.transformI18nBlock : null;
|
|||
|
|
return {
|
|||
|
|
include,
|
|||
|
|
exclude,
|
|||
|
|
module: moduleType,
|
|||
|
|
onlyLocales,
|
|||
|
|
forceStringify,
|
|||
|
|
defaultSFCLang,
|
|||
|
|
globalSFCScope,
|
|||
|
|
runtimeOnly,
|
|||
|
|
dropMessageCompiler,
|
|||
|
|
compositionOnly,
|
|||
|
|
fullInstall,
|
|||
|
|
ssrBuild,
|
|||
|
|
allowDynamic,
|
|||
|
|
strictMessage,
|
|||
|
|
escapeHtml,
|
|||
|
|
optimizeTranslationDirective,
|
|||
|
|
translationIdentifiers,
|
|||
|
|
transformI18nBlock
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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 getVueCompiler(vuePlugin) {
|
|||
|
|
return vuePlugin?.api?.options.compiler;
|
|||
|
|
}
|
|||
|
|
function getVuePluginOptions(vuePlugin) {
|
|||
|
|
return {
|
|||
|
|
isProduction: vuePlugin?.api?.options.isProduction,
|
|||
|
|
root: vuePlugin?.api?.options.root,
|
|||
|
|
template: vuePlugin?.api?.options.template,
|
|||
|
|
compiler: vuePlugin?.api?.options.compiler
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function createDescriptor(filename, source, { template, compiler }) {
|
|||
|
|
const { descriptor, errors } = compiler.parse(source, {
|
|||
|
|
filename,
|
|||
|
|
templateParseOptions: template?.compilerOptions
|
|||
|
|
});
|
|||
|
|
return { descriptor, errors };
|
|||
|
|
}
|
|||
|
|
function getDescriptor(filename, code, options) {
|
|||
|
|
const { descriptor, errors } = createDescriptor(filename, code, options);
|
|||
|
|
if (errors.length) {
|
|||
|
|
throw errors[0];
|
|||
|
|
}
|
|||
|
|
return descriptor;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const INTLIFY_BUNDLE_IMPORT_ID = "@intlify/unplugin-vue-i18n/messages";
|
|||
|
|
const VIRTUAL_PREFIX = "\0";
|
|||
|
|
const debug$2 = createDebug(resolveNamespace("resource"));
|
|||
|
|
function resourcePlugin({
|
|||
|
|
onlyLocales,
|
|||
|
|
include,
|
|||
|
|
exclude,
|
|||
|
|
module,
|
|||
|
|
forceStringify,
|
|||
|
|
defaultSFCLang,
|
|||
|
|
globalSFCScope,
|
|||
|
|
runtimeOnly,
|
|||
|
|
dropMessageCompiler,
|
|||
|
|
compositionOnly,
|
|||
|
|
fullInstall,
|
|||
|
|
ssrBuild,
|
|||
|
|
strictMessage,
|
|||
|
|
allowDynamic,
|
|||
|
|
escapeHtml,
|
|||
|
|
transformI18nBlock
|
|||
|
|
}, meta) {
|
|||
|
|
const filter = createFilter(include, exclude);
|
|||
|
|
const getVueI18nAliasPath = ({ ssr = false, runtimeOnly: runtimeOnly2 = false }) => {
|
|||
|
|
return `${module}/dist/${module}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
|
|||
|
|
};
|
|||
|
|
let isProduction = false;
|
|||
|
|
let sourceMap = false;
|
|||
|
|
const vueI18nAliasName = module;
|
|||
|
|
debug$2(`vue-i18n alias name: ${vueI18nAliasName}`);
|
|||
|
|
let vuePlugin = null;
|
|||
|
|
const getSfcParser = () => {
|
|||
|
|
return vuePlugin ? getVueCompiler(vuePlugin).parse : parse$1;
|
|||
|
|
};
|
|||
|
|
return {
|
|||
|
|
name: resolveNamespace("resource"),
|
|||
|
|
/**
|
|||
|
|
* 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() {
|
|||
|
|
const defineConfig = {
|
|||
|
|
define: {
|
|||
|
|
__VUE_I18N_LEGACY_API__: !compositionOnly,
|
|||
|
|
__VUE_I18N_FULL_INSTALL__: fullInstall,
|
|||
|
|
__INTLIFY_DROP_MESSAGE_COMPILER__: dropMessageCompiler,
|
|||
|
|
__VUE_I18N_PROD_DEVTOOLS__: false
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
debug$2("define Config:", defineConfig);
|
|||
|
|
const aliasConfig = {
|
|||
|
|
resolve: {
|
|||
|
|
alias: {
|
|||
|
|
[vueI18nAliasName]: getVueI18nAliasPath({
|
|||
|
|
ssr: ssrBuild,
|
|||
|
|
runtimeOnly
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
debug$2("alias Config:", aliasConfig);
|
|||
|
|
return assign(defineConfig, aliasConfig);
|
|||
|
|
},
|
|||
|
|
configResolved(config) {
|
|||
|
|
vuePlugin = getVitePlugin(config, "vite:vue");
|
|||
|
|
if (!checkVuePlugin(vuePlugin)) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
isProduction = config.isProduction;
|
|||
|
|
sourceMap = config.command === "build" ? !!config.build.sourcemap : false;
|
|||
|
|
debug$2(
|
|||
|
|
`configResolved: isProduction = ${isProduction}, sourceMap = ${sourceMap}`
|
|||
|
|
);
|
|||
|
|
const jsonPlugin = getVitePlugin(config, "vite:json");
|
|||
|
|
if (jsonPlugin) {
|
|||
|
|
const orgTransform = "handler" in jsonPlugin.transform ? jsonPlugin.transform.handler : jsonPlugin.transform;
|
|||
|
|
async function overrideJson(code, id) {
|
|||
|
|
if (!/\.json$/.test(id) || filter(id)) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const { query } = parseVueRequest(id);
|
|||
|
|
if (query.vue) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
debug$2("org json plugin");
|
|||
|
|
return orgTransform.apply(this, [code, id]);
|
|||
|
|
}
|
|||
|
|
if ("handler" in jsonPlugin.transform) {
|
|||
|
|
jsonPlugin.transform.handler = overrideJson;
|
|||
|
|
}
|
|||
|
|
jsonPlugin.transform = overrideJson;
|
|||
|
|
}
|
|||
|
|
const esbuildPlugin = getVitePlugin(config, "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] = isString(result) ? [result, void 0] : [result.code, result.map];
|
|||
|
|
let langInfo = defaultSFCLang;
|
|||
|
|
langInfo = parse(filename).ext;
|
|||
|
|
const generate = getGenerator(langInfo);
|
|||
|
|
const parseOptions = getOptions(
|
|||
|
|
filename,
|
|||
|
|
isProduction,
|
|||
|
|
query,
|
|||
|
|
sourceMap,
|
|||
|
|
{
|
|||
|
|
inSourceMap,
|
|||
|
|
isGlobal: globalSFCScope,
|
|||
|
|
allowDynamic,
|
|||
|
|
strictMessage,
|
|||
|
|
escapeHtml,
|
|||
|
|
jit: true,
|
|||
|
|
onlyLocales,
|
|||
|
|
forceStringify
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
debug$2("parseOptions", parseOptions);
|
|||
|
|
const { code: generatedCode, map } = generate(_code, parseOptions);
|
|||
|
|
debug$2("generated code", generatedCode);
|
|||
|
|
debug$2("sourcemap", map, sourceMap);
|
|||
|
|
if (_code === generatedCode)
|
|||
|
|
return;
|
|||
|
|
return {
|
|||
|
|
code: generatedCode,
|
|||
|
|
map: { mappings: "" }
|
|||
|
|
};
|
|||
|
|
} else {
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
async handleHotUpdate({ file, server }) {
|
|||
|
|
if (/\.(json5?|ya?ml)$/.test(file)) {
|
|||
|
|
const module2 = server.moduleGraph.getModuleById(
|
|||
|
|
asVirtualId(INTLIFY_BUNDLE_IMPORT_ID, meta.framework)
|
|||
|
|
);
|
|||
|
|
if (module2) {
|
|||
|
|
server.moduleGraph.invalidateModule(module2);
|
|||
|
|
return [module2];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
webpack(compiler) {
|
|||
|
|
isProduction = compiler.options.mode !== "development";
|
|||
|
|
sourceMap = !!compiler.options.devtool;
|
|||
|
|
debug$2(`webpack: isProduction = ${isProduction}, sourceMap = ${sourceMap}`);
|
|||
|
|
compiler.options.resolve = normalizeConfigResolveAlias(
|
|||
|
|
compiler.options.resolve,
|
|||
|
|
meta.framework
|
|||
|
|
);
|
|||
|
|
compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath({
|
|||
|
|
ssr: ssrBuild,
|
|||
|
|
runtimeOnly
|
|||
|
|
});
|
|||
|
|
debug$2(
|
|||
|
|
`set ${vueI18nAliasName}: ${getVueI18nAliasPath({
|
|||
|
|
ssr: ssrBuild,
|
|||
|
|
runtimeOnly
|
|||
|
|
})}`
|
|||
|
|
);
|
|||
|
|
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$2(`set __VUE_I18N_LEGACY_API__ is '${compositionOnly}'`);
|
|||
|
|
debug$2(`set __VUE_I18N_FULL_INSTALL__ is '${fullInstall}'`);
|
|||
|
|
} else {
|
|||
|
|
debug$2("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$2("resolveId", id, importer);
|
|||
|
|
if (id === INTLIFY_BUNDLE_IMPORT_ID) {
|
|||
|
|
return asVirtualId(id, meta.framework);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
async load(id) {
|
|||
|
|
debug$2("load", id);
|
|||
|
|
if (INTLIFY_BUNDLE_IMPORT_ID === getVirtualId(id, meta.framework) && include) {
|
|||
|
|
let resourcePaths = [];
|
|||
|
|
const includePaths = isArray(include) ? include : [include];
|
|||
|
|
for (const inc of includePaths) {
|
|||
|
|
resourcePaths = [...resourcePaths, ...await fg(inc)];
|
|||
|
|
}
|
|||
|
|
resourcePaths = resourcePaths.filter(
|
|||
|
|
(el, pos) => resourcePaths.indexOf(el) === pos
|
|||
|
|
);
|
|||
|
|
const code = await generateBundleResources(
|
|||
|
|
resourcePaths,
|
|||
|
|
isProduction,
|
|||
|
|
{
|
|||
|
|
forceStringify,
|
|||
|
|
strictMessage,
|
|||
|
|
escapeHtml
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
return {
|
|||
|
|
code,
|
|||
|
|
map: { mappings: "" }
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
transformInclude(id) {
|
|||
|
|
debug$2("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$2("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 = parse(filename).ext;
|
|||
|
|
const generate = getGenerator(langInfo);
|
|||
|
|
const parseOptions = getOptions(
|
|||
|
|
filename,
|
|||
|
|
isProduction,
|
|||
|
|
query,
|
|||
|
|
sourceMap,
|
|||
|
|
{
|
|||
|
|
inSourceMap,
|
|||
|
|
isGlobal: globalSFCScope,
|
|||
|
|
allowDynamic,
|
|||
|
|
strictMessage,
|
|||
|
|
escapeHtml,
|
|||
|
|
jit: true,
|
|||
|
|
onlyLocales,
|
|||
|
|
forceStringify
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
debug$2("parseOptions", parseOptions);
|
|||
|
|
const { code: generatedCode, map } = generate(code, parseOptions);
|
|||
|
|
debug$2("generated code", generatedCode);
|
|||
|
|
debug$2("sourcemap", map, sourceMap);
|
|||
|
|
if (code === generatedCode)
|
|||
|
|
return;
|
|||
|
|
return {
|
|||
|
|
code: generatedCode,
|
|||
|
|
// prettier-ignore
|
|||
|
|
map: { mappings: "" }
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
if (isCustomBlock(query)) {
|
|||
|
|
if (isString(query.lang)) {
|
|||
|
|
langInfo = query.src ? query.lang === "i18n" ? defaultSFCLang : query.lang : query.lang;
|
|||
|
|
} else if (defaultSFCLang) {
|
|||
|
|
langInfo = defaultSFCLang;
|
|||
|
|
}
|
|||
|
|
debug$2("langInfo", langInfo);
|
|||
|
|
const generate = /\.?json5?/.test(langInfo) ? generateJSON : generateYAML;
|
|||
|
|
const parseOptions = getOptions(
|
|||
|
|
filename,
|
|||
|
|
isProduction,
|
|||
|
|
query,
|
|||
|
|
sourceMap,
|
|||
|
|
{
|
|||
|
|
inSourceMap,
|
|||
|
|
isGlobal: globalSFCScope,
|
|||
|
|
jit: true,
|
|||
|
|
strictMessage,
|
|||
|
|
escapeHtml,
|
|||
|
|
onlyLocales,
|
|||
|
|
forceStringify
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
debug$2("parseOptions", parseOptions);
|
|||
|
|
let source = await getCode(
|
|||
|
|
code,
|
|||
|
|
filename,
|
|||
|
|
sourceMap,
|
|||
|
|
query,
|
|||
|
|
getSfcParser(),
|
|||
|
|
meta.framework
|
|||
|
|
);
|
|||
|
|
if (typeof transformI18nBlock === "function") {
|
|||
|
|
const modifiedSource = transformI18nBlock(source);
|
|||
|
|
if (modifiedSource && typeof modifiedSource === "string") {
|
|||
|
|
source = modifiedSource;
|
|||
|
|
} else {
|
|||
|
|
warn("transformI18nBlock should return a string");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const { code: generatedCode, map } = generate(source, parseOptions);
|
|||
|
|
debug$2("generated code", generatedCode);
|
|||
|
|
debug$2("sourcemap", map, sourceMap);
|
|||
|
|
if (code === generatedCode)
|
|||
|
|
return;
|
|||
|
|
return {
|
|||
|
|
code: generatedCode,
|
|||
|
|
// prettier-ignore
|
|||
|
|
map: { mappings: "" }
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function getGenerator(ext, defaultGen = generateJSON) {
|
|||
|
|
return /\.?json5?$/.test(ext) ? generateJSON : /\.ya?ml$/.test(ext) ? generateYAML : /\.([c|m]?js|[c|m]?ts)$/.test(ext) ? 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, isProduction, {
|
|||
|
|
forceStringify = false,
|
|||
|
|
isGlobal = false,
|
|||
|
|
onlyLocales = [],
|
|||
|
|
strictMessage = true,
|
|||
|
|
escapeHtml = false,
|
|||
|
|
jit = true,
|
|||
|
|
transformI18nBlock = void 0
|
|||
|
|
}) {
|
|||
|
|
const codes = [];
|
|||
|
|
for (const res of resources) {
|
|||
|
|
debug$2(`${res} bundle loading ...`);
|
|||
|
|
if (/\.(json5?|ya?ml)$/.test(res)) {
|
|||
|
|
const { ext, name } = parse(res);
|
|||
|
|
const source = await getRaw(res);
|
|||
|
|
const generate = /json5?/.test(ext) ? generateJSON : generateYAML;
|
|||
|
|
const parseOptions = getOptions(res, isProduction, {}, false, {
|
|||
|
|
isGlobal,
|
|||
|
|
jit,
|
|||
|
|
onlyLocales,
|
|||
|
|
strictMessage,
|
|||
|
|
escapeHtml,
|
|||
|
|
forceStringify,
|
|||
|
|
transformI18nBlock
|
|||
|
|
});
|
|||
|
|
parseOptions.type = "bare";
|
|||
|
|
const { code } = generate(source, parseOptions);
|
|||
|
|
debug$2("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, parser, framework = "vite") {
|
|||
|
|
const { index, issuerPath } = query;
|
|||
|
|
if (!isNumber(index)) {
|
|||
|
|
raiseError(`unexpected index: ${index}`);
|
|||
|
|
}
|
|||
|
|
if (framework === "webpack") {
|
|||
|
|
if (issuerPath) {
|
|||
|
|
debug$2(`getCode (webpack) ${index} via issuerPath`, issuerPath);
|
|||
|
|
return await getRaw(filename);
|
|||
|
|
} else {
|
|||
|
|
const result = parser(await getRaw(filename), {
|
|||
|
|
sourceMap,
|
|||
|
|
filename
|
|||
|
|
});
|
|||
|
|
const block = result.descriptor.customBlocks[index];
|
|||
|
|
if (block) {
|
|||
|
|
const code = block.src ? await getRaw(block.src) : block.content;
|
|||
|
|
debug$2(`getCode (webpack) ${index} from SFC`, code);
|
|||
|
|
return code;
|
|||
|
|
} else {
|
|||
|
|
return source;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
return source;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function isCustomBlock(query) {
|
|||
|
|
return !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 = [],
|
|||
|
|
allowDynamic = false,
|
|||
|
|
strictMessage = true,
|
|||
|
|
escapeHtml = false,
|
|||
|
|
jit = true,
|
|||
|
|
transformI18nBlock = null
|
|||
|
|
}) {
|
|||
|
|
const mode = isProduction ? "production" : "development";
|
|||
|
|
const baseOptions = {
|
|||
|
|
filename,
|
|||
|
|
sourceMap,
|
|||
|
|
inSourceMap,
|
|||
|
|
forceStringify,
|
|||
|
|
allowDynamic,
|
|||
|
|
strictMessage,
|
|||
|
|
escapeHtml,
|
|||
|
|
jit,
|
|||
|
|
onlyLocales,
|
|||
|
|
env: mode,
|
|||
|
|
transformI18nBlock,
|
|||
|
|
onWarn: (msg) => {
|
|||
|
|
warn(`${filename} ${msg}`);
|
|||
|
|
},
|
|||
|
|
onError: (msg, extra) => {
|
|||
|
|
const codeFrame = 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 assign(baseOptions, {
|
|||
|
|
type: "sfc",
|
|||
|
|
locale: isString(query.locale) ? query.locale : "",
|
|||
|
|
isGlobal: isGlobal || !!query.global
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
return 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;
|
|||
|
|
}
|
|||
|
|
async function getRaw(path) {
|
|||
|
|
return promises.readFile(path, { encoding: "utf-8" });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const debug$1 = createDebug(resolveNamespace("directive"));
|
|||
|
|
function directivePlugin({
|
|||
|
|
optimizeTranslationDirective,
|
|||
|
|
translationIdentifiers
|
|||
|
|
}) {
|
|||
|
|
let vuePlugin = null;
|
|||
|
|
let vuePluginOptions = null;
|
|||
|
|
const excludeLangs = ["pug", "jsx", "tsx"];
|
|||
|
|
return {
|
|||
|
|
name: resolveNamespace("directive"),
|
|||
|
|
enforce: "pre",
|
|||
|
|
vite: {
|
|||
|
|
config(config) {
|
|||
|
|
vuePlugin = getVitePlugin(config, "vite:vue");
|
|||
|
|
if (!checkVuePlugin(vuePlugin)) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (optimizeTranslationDirective) {
|
|||
|
|
vuePlugin.api.options = resolveVueOptions(
|
|||
|
|
vuePlugin,
|
|||
|
|
optimizeTranslationDirective,
|
|||
|
|
translationIdentifiers
|
|||
|
|
);
|
|||
|
|
debug$1(`vite:vue options['template']:`, vuePlugin.api.options);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
configResolved(config) {
|
|||
|
|
vuePlugin = getVitePlugin(config, "vite:vue");
|
|||
|
|
if (!checkVuePlugin(vuePlugin)) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
async transform(code, id) {
|
|||
|
|
if (id.endsWith(".vue")) {
|
|||
|
|
const { filename, query } = parseVueRequest(id);
|
|||
|
|
if (!excludeLangs.includes(query.lang ?? "")) {
|
|||
|
|
if (vuePluginOptions == null) {
|
|||
|
|
vuePluginOptions = getVuePluginOptions(vuePlugin);
|
|||
|
|
}
|
|||
|
|
if (vuePluginOptions?.compiler) {
|
|||
|
|
analyzeIdentifiers(
|
|||
|
|
getDescriptor(filename, code, vuePluginOptions),
|
|||
|
|
vuePluginOptions,
|
|||
|
|
translationIdentifiers
|
|||
|
|
);
|
|||
|
|
return {
|
|||
|
|
code,
|
|||
|
|
map: { version: 3, mappings: "", sources: [] }
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function resolveVueOptions(vuePlugin, optimizeTranslationDirective, translationIdentifiers) {
|
|||
|
|
var _a, _b;
|
|||
|
|
const vueOptions = vuePlugin.api.options;
|
|||
|
|
vueOptions.template || (vueOptions.template = {});
|
|||
|
|
(_a = vueOptions.template).compilerOptions || (_a.compilerOptions = {});
|
|||
|
|
(_b = vueOptions.template.compilerOptions).directiveTransforms || (_b.directiveTransforms = {});
|
|||
|
|
const translationSignatureResolver = (context, baseResolver) => {
|
|||
|
|
const { filename } = context;
|
|||
|
|
const vuePluginOptions = getVuePluginOptions(vuePlugin);
|
|||
|
|
const normalizedFilename = normalizePath(
|
|||
|
|
path.relative(vuePluginOptions.root, filename)
|
|||
|
|
);
|
|||
|
|
const resolveIdentifier2 = translationIdentifiers.get(normalizedFilename);
|
|||
|
|
debug$1("resolved vue-i18n Identifier", resolveIdentifier2);
|
|||
|
|
if (resolveIdentifier2 == null) {
|
|||
|
|
return void 0;
|
|||
|
|
}
|
|||
|
|
if (resolveIdentifier2.type === "identifier") {
|
|||
|
|
return baseResolver(context, resolveIdentifier2.key);
|
|||
|
|
} else {
|
|||
|
|
const resolvedSignature = baseResolver(context, resolveIdentifier2.key);
|
|||
|
|
return resolveIdentifier2?.style === "script-setup" ? `${resolvedSignature}.t` : resolvedSignature;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
vueOptions.template.compilerOptions.directiveTransforms.t = transformVTDirective({
|
|||
|
|
translationSignatures: isBoolean(optimizeTranslationDirective) ? translationSignatureResolver : optimizeTranslationDirective
|
|||
|
|
});
|
|||
|
|
return vueOptions;
|
|||
|
|
}
|
|||
|
|
function analyzeIdentifiers(descriptor, { root }, translationIdentifiers) {
|
|||
|
|
const source = descriptor.scriptSetup?.content || descriptor.script?.content;
|
|||
|
|
debug$1("getDescriptor content", source);
|
|||
|
|
if (!source) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const ast = parse$2(source, { range: true });
|
|||
|
|
simpleTraverse(ast, {
|
|||
|
|
enter(node, parent) {
|
|||
|
|
if (parent) {
|
|||
|
|
node.parent = parent;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
const scopeManager = analyze(ast, { sourceType: "module" });
|
|||
|
|
const scope = getScope(scopeManager, ast);
|
|||
|
|
const importLocalName = getImportLocalName(scope, "vue-i18n", "useI18n");
|
|||
|
|
if (importLocalName == null) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
debug$1("importLocalName", importLocalName);
|
|||
|
|
const resolvedIdentifier = getVueI18nIdentifier(scope, importLocalName);
|
|||
|
|
if (resolvedIdentifier) {
|
|||
|
|
const normalizedFilename = normalizePath(
|
|||
|
|
path.relative(root, descriptor.filename)
|
|||
|
|
);
|
|||
|
|
debug$1("set vue-i18n resolved identifier: ", resolvedIdentifier);
|
|||
|
|
translationIdentifiers.set(normalizedFilename, resolvedIdentifier);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function getScope(manager, node) {
|
|||
|
|
const scope = manager.acquire(node, true);
|
|||
|
|
if (scope) {
|
|||
|
|
if (scope.type === "function-expression-name") {
|
|||
|
|
return scope.childScopes[0];
|
|||
|
|
}
|
|||
|
|
return scope;
|
|||
|
|
}
|
|||
|
|
return manager.scopes[0];
|
|||
|
|
}
|
|||
|
|
function getImportLocalName(scope, source, imported) {
|
|||
|
|
const importDecl = getImportDeclaration(scope, source);
|
|||
|
|
if (importDecl) {
|
|||
|
|
const specifierNode = importDecl.specifiers.find(
|
|||
|
|
(specifierNode2) => isImportedIdentifierInImportClause(specifierNode2) && specifierNode2.imported.name === imported
|
|||
|
|
);
|
|||
|
|
return specifierNode ? specifierNode.local.name : null;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
function getImportDeclaration(scope, source) {
|
|||
|
|
const tracker = new eslintUitls.ReferenceTracker(scope);
|
|||
|
|
const traceMap = {
|
|||
|
|
[source]: {
|
|||
|
|
[eslintUitls.ReferenceTracker.ESM]: true,
|
|||
|
|
[eslintUitls.ReferenceTracker.READ]: true
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
const refs = Array.from(tracker.iterateEsmReferences(traceMap));
|
|||
|
|
return refs.length ? refs[0].node : null;
|
|||
|
|
}
|
|||
|
|
function isImportedIdentifierInImportClause(node) {
|
|||
|
|
return "imported" in node;
|
|||
|
|
}
|
|||
|
|
function getVueI18nIdentifier(scope, local) {
|
|||
|
|
const { callExpression, returnStatement } = getCallExpressionAndReturnStatement(scope, local);
|
|||
|
|
if (callExpression == null) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
const id = getVariableDeclarationIdFrom(callExpression);
|
|||
|
|
if (id == null) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
const variableIdPairs = parseVariableId(id);
|
|||
|
|
debug$1("variableIdPairs:", variableIdPairs);
|
|||
|
|
const returnVariableIdPairs = parseReturnStatement(returnStatement);
|
|||
|
|
debug$1("returnVariableIdPairs:", returnVariableIdPairs);
|
|||
|
|
return resolveIdentifier(variableIdPairs, returnVariableIdPairs);
|
|||
|
|
}
|
|||
|
|
const EMPTY_NODE_RETURN = {
|
|||
|
|
callExpression: null,
|
|||
|
|
returnStatement: null
|
|||
|
|
};
|
|||
|
|
function getCallExpressionAndReturnStatement(scope, local) {
|
|||
|
|
const variable = eslintUitls.findVariable(scope, local);
|
|||
|
|
if (variable == null) {
|
|||
|
|
return EMPTY_NODE_RETURN;
|
|||
|
|
}
|
|||
|
|
const callExpressionRef = variable.references.find((ref) => {
|
|||
|
|
return ref.identifier.parent?.type === AST_NODE_TYPES.CallExpression;
|
|||
|
|
});
|
|||
|
|
if (callExpressionRef == null) {
|
|||
|
|
return EMPTY_NODE_RETURN;
|
|||
|
|
}
|
|||
|
|
let returnStatement = null;
|
|||
|
|
if (callExpressionRef.from.type === "function" && callExpressionRef.from.block.type === AST_NODE_TYPES.FunctionExpression && callExpressionRef.from.block.parent.type === AST_NODE_TYPES.Property && callExpressionRef.from.block.parent.key.type === AST_NODE_TYPES.Identifier && callExpressionRef.from.block.parent.key.name === "setup") {
|
|||
|
|
returnStatement = callExpressionRef.from.block.body.body.find(
|
|||
|
|
(statement) => {
|
|||
|
|
return statement.type === AST_NODE_TYPES.ReturnStatement;
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
return {
|
|||
|
|
callExpression: callExpressionRef.identifier.parent,
|
|||
|
|
returnStatement
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function getVariableDeclarationIdFrom(node) {
|
|||
|
|
if (node.parent?.type !== AST_NODE_TYPES.VariableDeclarator) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
return node.parent.id;
|
|||
|
|
}
|
|||
|
|
function parseVariableId(node) {
|
|||
|
|
if (node.type === AST_NODE_TYPES.Identifier) {
|
|||
|
|
return [{ key: node.name, value: null }];
|
|||
|
|
} else {
|
|||
|
|
const props = node.properties.filter(
|
|||
|
|
// ignore RestElement
|
|||
|
|
(prop) => prop.type === AST_NODE_TYPES.Property
|
|||
|
|
);
|
|||
|
|
const pairs = [];
|
|||
|
|
for (const prop of props) {
|
|||
|
|
if (prop?.key.type === AST_NODE_TYPES.Identifier && prop?.value.type === AST_NODE_TYPES.Identifier) {
|
|||
|
|
pairs.push({ key: prop.key.name, value: prop.value.name });
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return pairs;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function parseReturnStatement(node) {
|
|||
|
|
const pairs = [];
|
|||
|
|
if (node == null || node.argument == null) {
|
|||
|
|
return pairs;
|
|||
|
|
}
|
|||
|
|
if (node.argument.type === AST_NODE_TYPES.ObjectExpression) {
|
|||
|
|
for (const prop of node.argument.properties) {
|
|||
|
|
if (prop.type === AST_NODE_TYPES.Property) {
|
|||
|
|
if (prop.key.type === AST_NODE_TYPES.Identifier && prop.value.type === AST_NODE_TYPES.Identifier) {
|
|||
|
|
pairs.push({ key: prop.key.name, value: prop.value.name });
|
|||
|
|
} else if (prop.key.type === AST_NODE_TYPES.Identifier && prop.value.type === AST_NODE_TYPES.MemberExpression && prop.value.object.type === AST_NODE_TYPES.Identifier && prop.value.property.type === AST_NODE_TYPES.Identifier) {
|
|||
|
|
pairs.push({
|
|||
|
|
key: prop.key.name,
|
|||
|
|
value: `${prop.value.object.name}.${prop.value.property.name}`
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return pairs;
|
|||
|
|
} else if (node.argument.type === AST_NODE_TYPES.Identifier) {
|
|||
|
|
return pairs;
|
|||
|
|
} else {
|
|||
|
|
return pairs;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function resolveIdentifier(localVariables, returnVariable) {
|
|||
|
|
if (returnVariable.length === 0) {
|
|||
|
|
const variable = localVariables.find((pair) => pair.key === "t");
|
|||
|
|
if (variable && variable.value) {
|
|||
|
|
return { type: "identifier", key: variable.value };
|
|||
|
|
}
|
|||
|
|
const identifierOnly = localVariables.find((pair) => pair.value === null);
|
|||
|
|
if (identifierOnly && identifierOnly.key) {
|
|||
|
|
return { type: "object", key: identifierOnly.key, style: "script-setup" };
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
} else {
|
|||
|
|
const variable = localVariables.find((pair) => pair.key === "t");
|
|||
|
|
if (variable && variable.value) {
|
|||
|
|
const returnVar = returnVariable.find(
|
|||
|
|
(pair) => pair.value === variable.value
|
|||
|
|
);
|
|||
|
|
if (returnVar && returnVar.key) {
|
|||
|
|
return { type: "identifier", key: returnVar.key };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const identifierOnly = localVariables.find((pair) => pair.value === null);
|
|||
|
|
if (identifierOnly && identifierOnly.key) {
|
|||
|
|
const targetKey = identifierOnly.key;
|
|||
|
|
const returnVar = returnVariable.find(
|
|||
|
|
(pair) => pair.value?.startsWith(targetKey)
|
|||
|
|
);
|
|||
|
|
if (returnVar && returnVar.key) {
|
|||
|
|
return { type: "object", key: returnVar.key, style: "setup-hook" };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const debug = createDebug(resolveNamespace("root"));
|
|||
|
|
const unpluginFactory = (options = {}, meta) => {
|
|||
|
|
debug("meta framework", meta.framework);
|
|||
|
|
if (!["vite", "webpack"].includes(meta.framework)) {
|
|||
|
|
raiseError(`This plugin is supported 'vite' and 'webpack' only`);
|
|||
|
|
}
|
|||
|
|
debug("plugin options (resolving):", options);
|
|||
|
|
const resolvedOptions = resolveOptions(options);
|
|||
|
|
debug("plugin options (resolved):", resolvedOptions);
|
|||
|
|
const plugins = [resourcePlugin(resolvedOptions, meta)];
|
|||
|
|
if (resolvedOptions.optimizeTranslationDirective) {
|
|||
|
|
if (meta.framework === "webpack") {
|
|||
|
|
raiseError(
|
|||
|
|
`The 'optimizeTranslationDirective' option still is not supported for webpack.
|
|||
|
|
We are waiting for your Pull Request \u{1F642}.`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
plugins.push(directivePlugin(resolvedOptions));
|
|||
|
|
}
|
|||
|
|
return plugins;
|
|||
|
|
};
|
|||
|
|
const unplugin = /* @__PURE__ */ createUnplugin(unpluginFactory);
|
|||
|
|
|
|||
|
|
export { unplugin as default, unplugin, unpluginFactory };
|