@intlify/unplugin-vue-i18n 5.0.0-beta.0 → 5.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.mjs CHANGED
@@ -1,13 +1,129 @@
1
1
  import { createUnplugin } from 'unplugin';
2
- import { normalize, parse } from 'pathe';
3
2
  import createDebug from 'debug';
3
+ import fs, { promises } from 'node:fs';
4
+ import pc from 'picocolors';
5
+ import module from 'node:module';
6
+ import path from 'node:path';
7
+ import { normalize, parse } from 'pathe';
8
+ import { isArray, isString, isBoolean, assign, isNumber, isEmptyObject, generateCodeFrame } from '@intlify/shared';
4
9
  import fg from 'fast-glob';
5
- import { isArray, isString, isBoolean, isObject, isNumber, isEmptyObject, assign, generateCodeFrame } from '@intlify/shared';
6
10
  import { createFilter } from '@rollup/pluginutils';
7
- import { checkInstallPackage, generateJSON, generateYAML, generateJavaScript } from '@intlify/bundle-utils';
8
- import { parse as parse$1 } from '@vue/compiler-sfc';
9
- import { promises } from 'fs';
10
- import pc from 'picocolors';
11
+ import { generateJSON, generateYAML, generateJavaScript } from '@intlify/bundle-utils';
12
+ import { parse as parse$1 } from 'vue/compiler-sfc';
13
+ import { transformVTDirective } from '@intlify/vue-i18n-extensions';
14
+ import { analyze } from '@typescript-eslint/scope-manager';
15
+ import { parse as parse$2, simpleTraverse, AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
16
+ import eslintUitls from '@eslint-community/eslint-utils';
17
+
18
+ const _require = module.createRequire(import.meta.url);
19
+ function checkInstallPackage(debug) {
20
+ const pkgInfo = resolvePkgPath("vue-i18n", debug) || resolvePkgPath("petite-vue-i18n", debug);
21
+ if (!pkgInfo) {
22
+ throw new Error(
23
+ `requires 'vue-i18n' or 'petite-vue-i18n' to be present in the dependency tree.`
24
+ );
25
+ }
26
+ debug("installed package info:", pkgInfo);
27
+ return pkgInfo;
28
+ }
29
+ function resolvePkgPath(id, debug) {
30
+ try {
31
+ const resolvedPath = _require.resolve(id);
32
+ const pkgPath = path.dirname(resolvedPath);
33
+ const pkgJson = JSON.parse(
34
+ fs.readFileSync(path.join(pkgPath, "package.json"), "utf-8")
35
+ );
36
+ const pkgName = pkgJson.name.startsWith("vue-i18n") ? "vue-i18n" : pkgJson.name.startsWith("petite-vue-i18n") ? "petite-vue-i18n" : "";
37
+ return pkgJson ? { alias: id, pkg: pkgName } : null;
38
+ } catch (e) {
39
+ debug(`cannot find '${id}'`, e);
40
+ return null;
41
+ }
42
+ }
43
+ function resolveNamespace(name) {
44
+ return `unplugin-vue-i18n:${name}`;
45
+ }
46
+ function warn(...args) {
47
+ console.warn(pc.yellow(pc.bold(`[unplugin-vue-i18n] `)), ...args);
48
+ }
49
+ function error(...args) {
50
+ console.error(pc.red(pc.bold(`[unplugin-vue-i18n] `)), ...args);
51
+ }
52
+ async function getRaw(path2) {
53
+ return promises.readFile(path2, { encoding: "utf-8" });
54
+ }
55
+ function raiseError(message) {
56
+ throw new Error(`[unplugin-vue-i18n] ${message}`);
57
+ }
58
+ function getVitePlugin(config, name) {
59
+ return config.plugins.find((p) => p.name === name);
60
+ }
61
+ function checkVuePlugin(vuePlugin) {
62
+ if (vuePlugin == null || !vuePlugin.api) {
63
+ error(
64
+ "`@vitejs/plugin-vue` plugin is not found or invalid version. Please install `@vitejs/plugin-vue` v4.3.4 or later version."
65
+ );
66
+ return false;
67
+ }
68
+ return true;
69
+ }
70
+ const isWindows = typeof process !== "undefined" && process.platform === "win32";
71
+ const windowsSlashRE = /\\/g;
72
+ function slash(p) {
73
+ return p.replace(windowsSlashRE, "/");
74
+ }
75
+ function normalizePath(id) {
76
+ return path.posix.normalize(isWindows ? slash(id) : id);
77
+ }
78
+
79
+ function resolveOptions(options, installedPkgInfo) {
80
+ let onlyLocales = [];
81
+ if (options.onlyLocales) {
82
+ onlyLocales = isArray(options.onlyLocales) ? options.onlyLocales : [options.onlyLocales];
83
+ }
84
+ let include = options.include;
85
+ let exclude = void 0;
86
+ if (include) {
87
+ if (isArray(include)) {
88
+ include = include.map((item) => normalize(item));
89
+ } else if (isString(include)) {
90
+ include = normalize(include);
91
+ }
92
+ } else {
93
+ exclude = "**/**";
94
+ }
95
+ const forceStringify = !!options.forceStringify;
96
+ const defaultSFCLang = isString(options.defaultSFCLang) ? options.defaultSFCLang : "json";
97
+ const globalSFCScope = !!options.globalSFCScope;
98
+ const runtimeOnly = isBoolean(options.runtimeOnly) ? options.runtimeOnly : true;
99
+ const dropMessageCompiler = !!options.dropMessageCompiler;
100
+ const compositionOnly = installedPkgInfo.pkg === "vue-i18n" ? isBoolean(options.compositionOnly) ? options.compositionOnly : true : true;
101
+ const fullInstall = installedPkgInfo.pkg === "vue-i18n" ? isBoolean(options.fullInstall) ? options.fullInstall : true : false;
102
+ const ssrBuild = !!options.ssr;
103
+ const allowDynamic = !!options.allowDynamic;
104
+ const strictMessage = isBoolean(options.strictMessage) ? options.strictMessage : true;
105
+ const escapeHtml = !!options.escapeHtml;
106
+ const optimizeTranslationDirective = isString(options.optimizeTranslationDirective) || isArray(options.optimizeTranslationDirective) ? options.optimizeTranslationDirective : !!options.optimizeTranslationDirective;
107
+ const translationIdentifiers = /* @__PURE__ */ new Map();
108
+ return {
109
+ include,
110
+ exclude,
111
+ onlyLocales,
112
+ forceStringify,
113
+ defaultSFCLang,
114
+ globalSFCScope,
115
+ runtimeOnly,
116
+ dropMessageCompiler,
117
+ compositionOnly,
118
+ fullInstall,
119
+ ssrBuild,
120
+ allowDynamic,
121
+ strictMessage,
122
+ escapeHtml,
123
+ optimizeTranslationDirective,
124
+ translationIdentifiers
125
+ };
126
+ }
11
127
 
12
128
  function parseVueRequest(id) {
13
129
  const [filename, rawQuery] = id.split(`?`, 2);
@@ -47,77 +163,66 @@ function parseVueRequest(id) {
47
163
  };
48
164
  }
49
165
 
50
- function warn(...args) {
51
- console.warn(pc.yellow(pc.bold(`[unplugin-vue-i18n] `)), ...args);
166
+ function getVueCompiler(vuePlugin) {
167
+ return vuePlugin?.api?.options.compiler;
52
168
  }
53
- function error(...args) {
54
- console.error(pc.red(pc.bold(`[unplugin-vue-i18n] `)), ...args);
169
+ function getVuePluginOptions(vuePlugin) {
170
+ return {
171
+ isProduction: vuePlugin?.api?.options.isProduction,
172
+ root: vuePlugin?.api?.options.root,
173
+ template: vuePlugin?.api?.options.template,
174
+ compiler: vuePlugin?.api?.options.compiler
175
+ };
55
176
  }
56
- async function getRaw(path) {
57
- return promises.readFile(path, { encoding: "utf-8" });
177
+
178
+ function createDescriptor(filename, source, { template, compiler }) {
179
+ const { descriptor, errors } = compiler.parse(source, {
180
+ filename,
181
+ templateParseOptions: template?.compilerOptions
182
+ });
183
+ return { descriptor, errors };
58
184
  }
59
- function raiseError(message) {
60
- throw new Error(`[unplugin-vue-i18n] ${message}`);
185
+ function getDescriptor(filename, code, options) {
186
+ const { descriptor, errors } = createDescriptor(filename, code, options);
187
+ if (errors.length) {
188
+ throw errors[0];
189
+ }
190
+ return descriptor;
61
191
  }
62
192
 
63
193
  const INTLIFY_BUNDLE_IMPORT_ID = "@intlify/unplugin-vue-i18n/messages";
64
194
  const VIRTUAL_PREFIX = "\0";
65
- const debug = createDebug("unplugin-vue-i18n");
66
- const installedPkg = checkInstallPackage("@intlify/unplugin-vue-i18n", debug);
67
- const unplugin = createUnplugin((options = {}, meta) => {
68
- debug("plugin options:", options, meta.framework);
69
- if (!["vite", "webpack"].includes(meta.framework)) {
70
- raiseError(`This plugin is supported 'vite' and 'webpack' only`);
71
- }
72
- let onlyLocales = [];
73
- if (options.onlyLocales) {
74
- onlyLocales = Array.isArray(options.onlyLocales) ? options.onlyLocales : [options.onlyLocales];
75
- }
76
- let include = options.include;
77
- let exclude = null;
78
- if (include) {
79
- if (isArray(include)) {
80
- include = include.map((item) => normalize(item));
81
- } else if (isString(include)) {
82
- include = normalize(include);
83
- }
84
- } else {
85
- exclude = "**/**";
86
- }
195
+ const debug$2 = createDebug(resolveNamespace("resource"));
196
+ function resourcePlugin({
197
+ onlyLocales,
198
+ include,
199
+ exclude,
200
+ forceStringify,
201
+ defaultSFCLang,
202
+ globalSFCScope,
203
+ runtimeOnly,
204
+ dropMessageCompiler,
205
+ compositionOnly,
206
+ fullInstall,
207
+ ssrBuild,
208
+ strictMessage,
209
+ allowDynamic,
210
+ escapeHtml
211
+ }, meta, installedPkgInfo) {
87
212
  const filter = createFilter(include, exclude);
88
- const forceStringify = !!options.forceStringify;
89
- const defaultSFCLang = isString(options.defaultSFCLang) ? options.defaultSFCLang : "json";
90
- const globalSFCScope = !!options.globalSFCScope;
91
- const runtimeOnly = isBoolean(options.runtimeOnly) ? options.runtimeOnly : true;
92
- debug("runtimeOnly", runtimeOnly);
93
- const dropMessageCompiler = !!options.dropMessageCompiler;
94
- debug("dropMessageCompiler", dropMessageCompiler);
95
- const compositionOnly = installedPkg === "vue-i18n" ? isBoolean(options.compositionOnly) ? options.compositionOnly : true : true;
96
- debug("compositionOnly", compositionOnly);
97
- const fullInstall = installedPkg === "vue-i18n" ? isBoolean(options.fullInstall) ? options.fullInstall : true : false;
98
- debug("fullInstall", fullInstall);
99
- const ssrBuild = !!options.ssr;
100
- debug("ssr", ssrBuild);
101
- const useVueI18nImportName = options.useVueI18nImportName;
102
- if (useVueI18nImportName != null) {
103
- warn(`'useVueI18nImportName' option is experimental`);
104
- }
105
- debug("useVueI18nImportName", useVueI18nImportName);
106
- const getVueI18nAliasName = () => installedPkg === "petite-vue-i18n" && isBoolean(useVueI18nImportName) && useVueI18nImportName ? "vue-i18n" : installedPkg;
107
213
  const getVueI18nAliasPath = ({ ssr = false, runtimeOnly: runtimeOnly2 = false }) => {
108
- return `${installedPkg}/dist/${installedPkg}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
214
+ return `${installedPkgInfo.alias}/dist/${installedPkgInfo.pkg}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
109
215
  };
110
- const allowDynamic = !!options.allowDynamic;
111
- debug("allowDynamic", allowDynamic);
112
- const strictMessage = isBoolean(options.strictMessage) ? options.strictMessage : true;
113
- debug("strictMessage", strictMessage);
114
- const escapeHtml = !!options.escapeHtml;
115
- debug("escapeHtml", escapeHtml);
116
216
  let isProduction = false;
117
217
  let sourceMap = false;
118
- const vueI18nAliasName = getVueI18nAliasName();
218
+ const vueI18nAliasName = installedPkgInfo.alias;
219
+ debug$2(`vue-i18n alias name: ${vueI18nAliasName}`);
220
+ let vuePlugin = null;
221
+ const getSfcParser = () => {
222
+ return vuePlugin ? getVueCompiler(vuePlugin).parse : parse$1;
223
+ };
119
224
  return {
120
- name: "unplugin-vue-i18n",
225
+ name: resolveNamespace("resource"),
121
226
  /**
122
227
  * NOTE:
123
228
  *
@@ -128,70 +233,40 @@ const unplugin = createUnplugin((options = {}, meta) => {
128
233
  */
129
234
  enforce: meta.framework === "vite" ? "pre" : "post",
130
235
  vite: {
131
- config(config, { command }) {
132
- config.resolve = normalizeConfigResolveAlias(
133
- config.resolve,
134
- meta.framework
135
- );
136
- if (command === "build") {
137
- debug(`vue-i18n alias name: ${vueI18nAliasName}`);
138
- if (isArray(config.resolve.alias)) {
139
- config.resolve.alias.push({
140
- find: vueI18nAliasName,
141
- replacement: getVueI18nAliasPath({
236
+ config() {
237
+ const defineConfig = {
238
+ define: {
239
+ __VUE_I18N_LEGACY_API__: !compositionOnly,
240
+ __VUE_I18N_FULL_INSTALL__: fullInstall,
241
+ __INTLIFY_DROP_MESSAGE_COMPILER__: dropMessageCompiler,
242
+ __VUE_I18N_PROD_DEVTOOLS__: false
243
+ }
244
+ };
245
+ debug$2("define Config:", defineConfig);
246
+ const aliasConfig = {
247
+ resolve: {
248
+ alias: {
249
+ [vueI18nAliasName]: getVueI18nAliasPath({
142
250
  ssr: ssrBuild,
143
251
  runtimeOnly
144
252
  })
145
- });
146
- } else if (isObject(config.resolve.alias)) {
147
- config.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath({
148
- ssr: ssrBuild,
149
- runtimeOnly
150
- });
151
- }
152
- debug(
153
- `set ${vueI18nAliasName} runtime only: ${getVueI18nAliasPath({
154
- ssr: ssrBuild,
155
- runtimeOnly
156
- })}`
157
- );
158
- } else if (command === "serve" && installedPkg === "petite-vue-i18n" && useVueI18nImportName) {
159
- config.resolve = normalizeConfigResolveAlias(
160
- config.resolve,
161
- meta.framework
162
- );
163
- if (isArray(config.resolve.alias)) {
164
- config.resolve.alias.push({
165
- find: vueI18nAliasName,
166
- replacement: `petite-vue-i18n/dist/petite-vue-i18n.esm-bundler.js`
167
- });
168
- } else {
169
- config.resolve.alias[vueI18nAliasName] = `petite-vue-i18n/dist/petite-vue-i18n.esm-bundler.js`;
253
+ }
170
254
  }
171
- debug(`petite-vue-i18n alias name: ${vueI18nAliasName}`);
172
- }
173
- config.define = config.define || {};
174
- config.define["__VUE_I18N_LEGACY_API__"] = !compositionOnly;
175
- debug(
176
- `set __VUE_I18N_LEGACY_API__ is '${config.define["__VUE_I18N_LEGACY_API__"]}'`
177
- );
178
- config.define["__VUE_I18N_FULL_INSTALL__"] = fullInstall;
179
- debug(
180
- `set __VUE_I18N_FULL_INSTALL__ is '${config.define["__VUE_I18N_FULL_INSTALL__"]}'`
181
- );
182
- config.define["__INTLIFY_DROP_MESSAGE_COMPILER__"] = dropMessageCompiler;
183
- debug(
184
- `set __INTLIFY_DROP_MESSAGE_COMPILER__ is '${config.define["__INTLIFY_DROP_MESSAGE_COMPILER__"]}'`
185
- );
186
- config.define["__VUE_I18N_PROD_DEVTOOLS__"] = false;
255
+ };
256
+ debug$2("alias Config:", aliasConfig);
257
+ return assign(defineConfig, aliasConfig);
187
258
  },
188
259
  configResolved(config) {
260
+ vuePlugin = getVitePlugin(config, "vite:vue");
261
+ if (!checkVuePlugin(vuePlugin)) {
262
+ return;
263
+ }
189
264
  isProduction = config.isProduction;
190
265
  sourceMap = config.command === "build" ? !!config.build.sourcemap : false;
191
- debug(
266
+ debug$2(
192
267
  `configResolved: isProduction = ${isProduction}, sourceMap = ${sourceMap}`
193
268
  );
194
- const jsonPlugin = config.plugins.find((p) => p.name === "vite:json");
269
+ const jsonPlugin = getVitePlugin(config, "vite:json");
195
270
  if (jsonPlugin) {
196
271
  const orgTransform = jsonPlugin.transform;
197
272
  jsonPlugin.transform = async function(code, id) {
@@ -202,13 +277,11 @@ const unplugin = createUnplugin((options = {}, meta) => {
202
277
  if (query.vue) {
203
278
  return;
204
279
  }
205
- debug("org json plugin");
280
+ debug$2("org json plugin");
206
281
  return orgTransform.apply(this, [code, id]);
207
282
  };
208
283
  }
209
- const esbuildPlugin = config.plugins.find(
210
- (p) => p.name === "vite:esbuild"
211
- );
284
+ const esbuildPlugin = getVitePlugin(config, "vite:esbuild");
212
285
  if (esbuildPlugin) {
213
286
  const orgTransform = esbuildPlugin.transform;
214
287
  esbuildPlugin.transform = async function(code, id) {
@@ -241,10 +314,10 @@ const unplugin = createUnplugin((options = {}, meta) => {
241
314
  forceStringify
242
315
  }
243
316
  );
244
- debug("parseOptions", parseOptions);
317
+ debug$2("parseOptions", parseOptions);
245
318
  const { code: generatedCode, map } = generate(_code, parseOptions);
246
- debug("generated code", generatedCode);
247
- debug("sourcemap", map, sourceMap);
319
+ debug$2("generated code", generatedCode);
320
+ debug$2("sourcemap", map, sourceMap);
248
321
  if (_code === generatedCode)
249
322
  return;
250
323
  return {
@@ -272,26 +345,21 @@ const unplugin = createUnplugin((options = {}, meta) => {
272
345
  webpack(compiler) {
273
346
  isProduction = compiler.options.mode !== "development";
274
347
  sourceMap = !!compiler.options.devtool;
275
- debug(`webpack: isProduction = ${isProduction}, sourceMap = ${sourceMap}`);
348
+ debug$2(`webpack: isProduction = ${isProduction}, sourceMap = ${sourceMap}`);
276
349
  compiler.options.resolve = normalizeConfigResolveAlias(
277
350
  compiler.options.resolve,
278
351
  meta.framework
279
352
  );
280
- if (isProduction) {
281
- compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath({
353
+ compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath({
354
+ ssr: ssrBuild,
355
+ runtimeOnly
356
+ });
357
+ debug$2(
358
+ `set ${vueI18nAliasName}: ${getVueI18nAliasPath({
282
359
  ssr: ssrBuild,
283
360
  runtimeOnly
284
- });
285
- debug(
286
- `set ${vueI18nAliasName}: ${getVueI18nAliasPath({
287
- ssr: ssrBuild,
288
- runtimeOnly
289
- })}`
290
- );
291
- } else if (!isProduction && installedPkg === "petite-vue-i18n" && useVueI18nImportName) {
292
- compiler.options.resolve.alias[vueI18nAliasName] = `petite-vue-i18n/dist/petite-vue-i18n.esm-bundler.js`;
293
- debug(`petite-vue-i18n alias name: ${vueI18nAliasName}`);
294
- }
361
+ })}`
362
+ );
295
363
  loadWebpack().then((webpack) => {
296
364
  if (webpack) {
297
365
  compiler.options.plugins.push(
@@ -301,10 +369,10 @@ const unplugin = createUnplugin((options = {}, meta) => {
301
369
  __INTLIFY_PROD_DEVTOOLS__: "false"
302
370
  })
303
371
  );
304
- debug(`set __VUE_I18N_LEGACY_API__ is '${compositionOnly}'`);
305
- debug(`set __VUE_I18N_FULL_INSTALL__ is '${fullInstall}'`);
372
+ debug$2(`set __VUE_I18N_LEGACY_API__ is '${compositionOnly}'`);
373
+ debug$2(`set __VUE_I18N_FULL_INSTALL__ is '${fullInstall}'`);
306
374
  } else {
307
- debug("ignore vue-i18n feature flags with webpack.DefinePlugin");
375
+ debug$2("ignore vue-i18n feature flags with webpack.DefinePlugin");
308
376
  }
309
377
  });
310
378
  if (compiler.options.module) {
@@ -318,15 +386,14 @@ const unplugin = createUnplugin((options = {}, meta) => {
318
386
  }
319
387
  },
320
388
  resolveId(id, importer) {
321
- debug("resolveId", id, importer);
389
+ debug$2("resolveId", id, importer);
322
390
  if (id === INTLIFY_BUNDLE_IMPORT_ID) {
323
391
  return asVirtualId(id, meta.framework);
324
392
  }
325
393
  },
326
394
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
327
395
  async load(id) {
328
- debug("load", id);
329
- const { query } = parseVueRequest(id);
396
+ debug$2("load", id);
330
397
  if (INTLIFY_BUNDLE_IMPORT_ID === getVirtualId(id, meta.framework) && include) {
331
398
  let resourcePaths = [];
332
399
  const includePaths = isArray(include) ? include : [include];
@@ -338,7 +405,6 @@ const unplugin = createUnplugin((options = {}, meta) => {
338
405
  );
339
406
  const code = await generateBundleResources(
340
407
  resourcePaths,
341
- query,
342
408
  isProduction,
343
409
  {
344
410
  forceStringify,
@@ -353,7 +419,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
353
419
  }
354
420
  },
355
421
  transformInclude(id) {
356
- debug("transformInclude", id);
422
+ debug$2("transformInclude", id);
357
423
  if (meta.framework === "vite") {
358
424
  return true;
359
425
  } else {
@@ -363,7 +429,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
363
429
  },
364
430
  async transform(code, id) {
365
431
  const { filename, query } = parseVueRequest(id);
366
- debug("transform", id, JSON.stringify(query), filename);
432
+ debug$2("transform", id, JSON.stringify(query), filename);
367
433
  let langInfo = defaultSFCLang;
368
434
  let inSourceMap;
369
435
  if (!query.vue) {
@@ -386,10 +452,10 @@ const unplugin = createUnplugin((options = {}, meta) => {
386
452
  forceStringify
387
453
  }
388
454
  );
389
- debug("parseOptions", parseOptions);
455
+ debug$2("parseOptions", parseOptions);
390
456
  const { code: generatedCode, map } = generate(code, parseOptions);
391
- debug("generated code", generatedCode);
392
- debug("sourcemap", map, sourceMap);
457
+ debug$2("generated code", generatedCode);
458
+ debug$2("sourcemap", map, sourceMap);
393
459
  if (code === generatedCode)
394
460
  return;
395
461
  return {
@@ -405,7 +471,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
405
471
  } else if (defaultSFCLang) {
406
472
  langInfo = defaultSFCLang;
407
473
  }
408
- debug("langInfo", langInfo);
474
+ debug$2("langInfo", langInfo);
409
475
  const generate = /\.?json5?/.test(langInfo) ? generateJSON : generateYAML;
410
476
  const parseOptions = getOptions(
411
477
  filename,
@@ -422,17 +488,18 @@ const unplugin = createUnplugin((options = {}, meta) => {
422
488
  forceStringify
423
489
  }
424
490
  );
425
- debug("parseOptions", parseOptions);
491
+ debug$2("parseOptions", parseOptions);
426
492
  const source = await getCode(
427
493
  code,
428
494
  filename,
429
495
  sourceMap,
430
496
  query,
497
+ getSfcParser(),
431
498
  meta.framework
432
499
  );
433
500
  const { code: generatedCode, map } = generate(source, parseOptions);
434
- debug("generated code", generatedCode);
435
- debug("sourcemap", map, sourceMap);
501
+ debug$2("generated code", generatedCode);
502
+ debug$2("sourcemap", map, sourceMap);
436
503
  if (code === generatedCode)
437
504
  return;
438
505
  return {
@@ -444,7 +511,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
444
511
  }
445
512
  }
446
513
  };
447
- });
514
+ }
448
515
  function getGenerator(ext, defaultGen = generateJSON) {
449
516
  return /\.?json5?$/.test(ext) ? generateJSON : /\.ya?ml$/.test(ext) ? generateYAML : /\.([c|m]?js|[c|m]?ts)$/.test(ext) ? generateJavaScript : defaultGen;
450
517
  }
@@ -477,7 +544,7 @@ async function loadWebpack() {
477
544
  }
478
545
  return webpack;
479
546
  }
480
- async function generateBundleResources(resources, query, isProduction, {
547
+ async function generateBundleResources(resources, isProduction, {
481
548
  forceStringify = false,
482
549
  isGlobal = false,
483
550
  onlyLocales = [],
@@ -487,7 +554,7 @@ async function generateBundleResources(resources, query, isProduction, {
487
554
  }) {
488
555
  const codes = [];
489
556
  for (const res of resources) {
490
- debug(`${res} bundle loading ...`);
557
+ debug$2(`${res} bundle loading ...`);
491
558
  if (/\.(json5?|ya?ml)$/.test(res)) {
492
559
  const { ext, name } = parse(res);
493
560
  const source = await getRaw(res);
@@ -502,7 +569,7 @@ async function generateBundleResources(resources, query, isProduction, {
502
569
  });
503
570
  parseOptions.type = "bare";
504
571
  const { code } = generate(source, parseOptions);
505
- debug("generated code", code);
572
+ debug$2("generated code", code);
506
573
  codes.push(`${JSON.stringify(name)}: ${code}`);
507
574
  }
508
575
  }
@@ -530,24 +597,24 @@ export default mergeDeep({},
530
597
  ${codes.map((code) => `{${code}}`).join(",\n")}
531
598
  );`;
532
599
  }
533
- async function getCode(source, filename, sourceMap, query, framework = "vite") {
600
+ async function getCode(source, filename, sourceMap, query, parser, framework = "vite") {
534
601
  const { index, issuerPath } = query;
535
602
  if (!isNumber(index)) {
536
603
  raiseError(`unexpected index: ${index}`);
537
604
  }
538
605
  if (framework === "webpack") {
539
606
  if (issuerPath) {
540
- debug(`getCode (webpack) ${index} via issuerPath`, issuerPath);
607
+ debug$2(`getCode (webpack) ${index} via issuerPath`, issuerPath);
541
608
  return await getRaw(filename);
542
609
  } else {
543
- const result = parse$1(await getRaw(filename), {
610
+ const result = parser(await getRaw(filename), {
544
611
  sourceMap,
545
612
  filename
546
613
  });
547
614
  const block = result.descriptor.customBlocks[index];
548
615
  if (block) {
549
616
  const code = block.src ? await getRaw(block.src) : block.content;
550
- debug(`getCode (webpack) ${index} from SFC`, code);
617
+ debug$2(`getCode (webpack) ${index} from SFC`, code);
551
618
  return code;
552
619
  } else {
553
620
  return source;
@@ -623,4 +690,294 @@ function asVirtualId(id, framework = "vite") {
623
690
  return framework === "vite" ? VIRTUAL_PREFIX + id : id;
624
691
  }
625
692
 
693
+ const debug$1 = createDebug(resolveNamespace("directive"));
694
+ function directivePlugin({
695
+ optimizeTranslationDirective,
696
+ translationIdentifiers
697
+ }) {
698
+ let vuePlugin = null;
699
+ let vuePluginOptions = null;
700
+ return {
701
+ name: resolveNamespace("directive"),
702
+ enforce: "pre",
703
+ vite: {
704
+ config(config) {
705
+ vuePlugin = getVitePlugin(config, "vite:vue");
706
+ if (!checkVuePlugin(vuePlugin)) {
707
+ return;
708
+ }
709
+ if (optimizeTranslationDirective) {
710
+ vuePlugin.api.options = resolveVueOptions(
711
+ vuePlugin,
712
+ optimizeTranslationDirective,
713
+ translationIdentifiers
714
+ );
715
+ debug$1(`vite:vue options['template']:`, vuePlugin.api.options);
716
+ }
717
+ },
718
+ configResolved(config) {
719
+ vuePlugin = getVitePlugin(config, "vite:vue");
720
+ if (!checkVuePlugin(vuePlugin)) {
721
+ return;
722
+ }
723
+ }
724
+ },
725
+ async transform(code, id) {
726
+ const { filename } = parseVueRequest(id);
727
+ if (vuePluginOptions == null) {
728
+ vuePluginOptions = getVuePluginOptions(vuePlugin);
729
+ }
730
+ if (id.endsWith(".vue")) {
731
+ analyzeIdentifiers(
732
+ getDescriptor(filename, code, vuePluginOptions),
733
+ vuePluginOptions,
734
+ translationIdentifiers
735
+ );
736
+ }
737
+ return code;
738
+ }
739
+ };
740
+ }
741
+ function resolveVueOptions(vuePlugin, optimizeTranslationDirective, translationIdentifiers) {
742
+ var _a, _b;
743
+ const vueOptions = vuePlugin.api.options;
744
+ vueOptions.template || (vueOptions.template = {});
745
+ (_a = vueOptions.template).compilerOptions || (_a.compilerOptions = {});
746
+ (_b = vueOptions.template.compilerOptions).directiveTransforms || (_b.directiveTransforms = {});
747
+ const translationSignatureResolver = (context, baseResolver) => {
748
+ const { filename } = context;
749
+ const vuePluginOptions = getVuePluginOptions(vuePlugin);
750
+ const normalizedFilename = normalizePath(
751
+ path.relative(vuePluginOptions.root, filename)
752
+ );
753
+ const resolveIdentifier2 = translationIdentifiers.get(normalizedFilename);
754
+ debug$1("resolved vue-i18n Identifier", resolveIdentifier2);
755
+ if (resolveIdentifier2 == null) {
756
+ return void 0;
757
+ }
758
+ if (resolveIdentifier2.type === "identifier") {
759
+ return baseResolver(context, resolveIdentifier2.key);
760
+ } else {
761
+ const resolvedSignature = baseResolver(context, resolveIdentifier2.key);
762
+ return resolveIdentifier2?.style === "script-setup" ? `${resolvedSignature}.t` : resolvedSignature;
763
+ }
764
+ };
765
+ vueOptions.template.compilerOptions.directiveTransforms.t = transformVTDirective({
766
+ translationSignatures: isBoolean(optimizeTranslationDirective) ? translationSignatureResolver : optimizeTranslationDirective
767
+ });
768
+ return vueOptions;
769
+ }
770
+ function analyzeIdentifiers(descriptor, { root }, translationIdentifiers) {
771
+ const source = descriptor.scriptSetup?.content || descriptor.script?.content;
772
+ debug$1("getDescriptor content", source);
773
+ if (!source) {
774
+ return;
775
+ }
776
+ const ast = parse$2(source, { range: true });
777
+ simpleTraverse(ast, {
778
+ enter(node, parent) {
779
+ if (parent) {
780
+ node.parent = parent;
781
+ }
782
+ }
783
+ });
784
+ const scopeManager = analyze(ast, { sourceType: "module" });
785
+ const scope = getScope(scopeManager, ast);
786
+ const importLocalName = getImportLocalName(scope, "vue-i18n", "useI18n");
787
+ if (importLocalName == null) {
788
+ return;
789
+ }
790
+ debug$1("importLocalName", importLocalName);
791
+ const resolvedIdentifier = getVueI18nIdentifier(scope, importLocalName);
792
+ if (resolvedIdentifier) {
793
+ const normalizedFilename = normalizePath(
794
+ path.relative(root, descriptor.filename)
795
+ );
796
+ debug$1("set vue-i18n resolved identifier: ", resolvedIdentifier);
797
+ translationIdentifiers.set(normalizedFilename, resolvedIdentifier);
798
+ }
799
+ }
800
+ function getScope(manager, node) {
801
+ const scope = manager.acquire(node, true);
802
+ if (scope) {
803
+ if (scope.type === "function-expression-name") {
804
+ return scope.childScopes[0];
805
+ }
806
+ return scope;
807
+ }
808
+ return manager.scopes[0];
809
+ }
810
+ function getImportLocalName(scope, source, imported) {
811
+ const importDecl = getImportDeclaration(scope, source);
812
+ if (importDecl) {
813
+ const specifierNode = importDecl.specifiers.find(
814
+ (specifierNode2) => isImportedIdentifierInImportClause(specifierNode2) && specifierNode2.imported.name === imported
815
+ );
816
+ return specifierNode ? specifierNode.local.name : null;
817
+ }
818
+ return null;
819
+ }
820
+ function getImportDeclaration(scope, source) {
821
+ const tracker = new eslintUitls.ReferenceTracker(scope);
822
+ const traceMap = {
823
+ [source]: {
824
+ [eslintUitls.ReferenceTracker.ESM]: true,
825
+ [eslintUitls.ReferenceTracker.READ]: true
826
+ }
827
+ };
828
+ const refs = Array.from(tracker.iterateEsmReferences(traceMap));
829
+ return refs.length ? refs[0].node : null;
830
+ }
831
+ function isImportedIdentifierInImportClause(node) {
832
+ return "imported" in node;
833
+ }
834
+ function getVueI18nIdentifier(scope, local) {
835
+ const { callExpression, returnStatement } = getCallExpressionAndReturnStatement(scope, local);
836
+ if (callExpression == null) {
837
+ return null;
838
+ }
839
+ const id = getVariableDeclarationIdFrom(callExpression);
840
+ if (id == null) {
841
+ return null;
842
+ }
843
+ const variableIdPairs = parseVariableId(id);
844
+ debug$1("variableIdPairs:", variableIdPairs);
845
+ const returnVariableIdPairs = parseReturnStatement(returnStatement);
846
+ debug$1("returnVariableIdPairs:", returnVariableIdPairs);
847
+ return resolveIdentifier(variableIdPairs, returnVariableIdPairs);
848
+ }
849
+ const EMPTY_NODE_RETURN = {
850
+ callExpression: null,
851
+ returnStatement: null
852
+ };
853
+ function getCallExpressionAndReturnStatement(scope, local) {
854
+ const variable = eslintUitls.findVariable(scope, local);
855
+ if (variable == null) {
856
+ return EMPTY_NODE_RETURN;
857
+ }
858
+ const callExpressionRef = variable.references.find((ref) => {
859
+ return ref.identifier.parent?.type === AST_NODE_TYPES.CallExpression;
860
+ });
861
+ if (callExpressionRef == null) {
862
+ return EMPTY_NODE_RETURN;
863
+ }
864
+ let returnStatement = null;
865
+ 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") {
866
+ returnStatement = callExpressionRef.from.block.body.body.find(
867
+ (statement) => {
868
+ return statement.type === AST_NODE_TYPES.ReturnStatement;
869
+ }
870
+ );
871
+ }
872
+ return {
873
+ callExpression: callExpressionRef.identifier.parent,
874
+ returnStatement
875
+ };
876
+ }
877
+ function getVariableDeclarationIdFrom(node) {
878
+ if (node.parent?.type !== AST_NODE_TYPES.VariableDeclarator) {
879
+ return null;
880
+ }
881
+ return node.parent.id;
882
+ }
883
+ function parseVariableId(node) {
884
+ if (node.type === AST_NODE_TYPES.Identifier) {
885
+ return [{ key: node.name, value: null }];
886
+ } else {
887
+ const props = node.properties.filter(
888
+ // ignore RestElement
889
+ (prop) => prop.type === AST_NODE_TYPES.Property
890
+ );
891
+ const pairs = [];
892
+ for (const prop of props) {
893
+ if (prop?.key.type === AST_NODE_TYPES.Identifier && prop?.value.type === AST_NODE_TYPES.Identifier) {
894
+ pairs.push({ key: prop.key.name, value: prop.value.name });
895
+ }
896
+ }
897
+ return pairs;
898
+ }
899
+ }
900
+ function parseReturnStatement(node) {
901
+ const pairs = [];
902
+ if (node == null || node.argument == null) {
903
+ return pairs;
904
+ }
905
+ if (node.argument.type === AST_NODE_TYPES.ObjectExpression) {
906
+ for (const prop of node.argument.properties) {
907
+ if (prop.type === AST_NODE_TYPES.Property) {
908
+ if (prop.key.type === AST_NODE_TYPES.Identifier && prop.value.type === AST_NODE_TYPES.Identifier) {
909
+ pairs.push({ key: prop.key.name, value: prop.value.name });
910
+ } 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) {
911
+ pairs.push({
912
+ key: prop.key.name,
913
+ value: `${prop.value.object.name}.${prop.value.property.name}`
914
+ });
915
+ }
916
+ }
917
+ }
918
+ return pairs;
919
+ } else if (node.argument.type === AST_NODE_TYPES.Identifier) {
920
+ return pairs;
921
+ } else {
922
+ return pairs;
923
+ }
924
+ }
925
+ function resolveIdentifier(localVariables, returnVariable) {
926
+ if (returnVariable.length === 0) {
927
+ const variable = localVariables.find((pair) => pair.key === "t");
928
+ if (variable && variable.value) {
929
+ return { type: "identifier", key: variable.value };
930
+ }
931
+ const identifierOnly = localVariables.find((pair) => pair.value === null);
932
+ if (identifierOnly && identifierOnly.key) {
933
+ return { type: "object", key: identifierOnly.key, style: "script-setup" };
934
+ }
935
+ return null;
936
+ } else {
937
+ const variable = localVariables.find((pair) => pair.key === "t");
938
+ if (variable && variable.value) {
939
+ const returnVar = returnVariable.find(
940
+ (pair) => pair.value === variable.value
941
+ );
942
+ if (returnVar && returnVar.key) {
943
+ return { type: "identifier", key: returnVar.key };
944
+ }
945
+ }
946
+ const identifierOnly = localVariables.find((pair) => pair.value === null);
947
+ if (identifierOnly && identifierOnly.key) {
948
+ const targetKey = identifierOnly.key;
949
+ const returnVar = returnVariable.find(
950
+ (pair) => pair.value?.startsWith(targetKey)
951
+ );
952
+ if (returnVar && returnVar.key) {
953
+ return { type: "object", key: returnVar.key, style: "setup-hook" };
954
+ }
955
+ }
956
+ return null;
957
+ }
958
+ }
959
+
960
+ const debug = createDebug(resolveNamespace("root"));
961
+ const installedPkgInfo = checkInstallPackage(debug);
962
+ const unplugin = createUnplugin((options = {}, meta) => {
963
+ debug("meta framework", meta.framework);
964
+ if (!["vite", "webpack"].includes(meta.framework)) {
965
+ raiseError(`This plugin is supported 'vite' and 'webpack' only`);
966
+ }
967
+ debug("plugin options (resolving):", options);
968
+ const resolvedOptions = resolveOptions(options, installedPkgInfo);
969
+ debug("plugin options (resolved):", resolvedOptions);
970
+ const plugins = [resourcePlugin(resolvedOptions, meta, installedPkgInfo)];
971
+ if (resolvedOptions.optimizeTranslationDirective) {
972
+ if (meta.framework === "webpack") {
973
+ raiseError(
974
+ `The 'optimizeTranslationDirective' option still is not supported for webpack.
975
+ We are waiting for your Pull Request \u{1F642}.`
976
+ );
977
+ }
978
+ plugins.push(directivePlugin(resolvedOptions));
979
+ }
980
+ return plugins;
981
+ });
982
+
626
983
  export { unplugin as default, unplugin };