@intlify/unplugin-vue-i18n 5.0.0-beta.1 → 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,53 +1,19 @@
1
1
  import { createUnplugin } from 'unplugin';
2
- import { normalize, parse } from 'pathe';
3
2
  import createDebug from 'debug';
4
- import fg from 'fast-glob';
5
- import { isArray, isString, isBoolean, assign, isNumber, isEmptyObject, generateCodeFrame } from '@intlify/shared';
6
- import { createFilter } from '@rollup/pluginutils';
7
- import { generateJSON, generateYAML, generateJavaScript } from '@intlify/bundle-utils';
8
- import { parse as parse$1 } from '@vue/compiler-sfc';
9
3
  import fs, { promises } from 'node:fs';
10
4
  import pc from 'picocolors';
11
5
  import module from 'node:module';
12
6
  import path from 'node:path';
13
-
14
- function parseVueRequest(id) {
15
- const [filename, rawQuery] = id.split(`?`, 2);
16
- const params = new URLSearchParams(rawQuery);
17
- const ret = {};
18
- const langPart = Object.keys(Object.fromEntries(params)).find(
19
- (key) => /lang\./i.test(key)
20
- );
21
- ret.vue = params.has("vue");
22
- ret.global = params.has("global");
23
- ret.src = params.has("src");
24
- ret.raw = params.has("raw");
25
- if (params.has("type")) {
26
- ret.type = params.get("type");
27
- }
28
- if (params.has("blockType")) {
29
- ret.blockType = params.get("blockType");
30
- }
31
- if (params.has("index")) {
32
- ret.index = Number(params.get("index"));
33
- }
34
- if (params.has("locale")) {
35
- ret.locale = params.get("locale");
36
- }
37
- if (langPart) {
38
- const [, lang] = langPart.split(".");
39
- ret.lang = lang;
40
- } else if (params.has("lang")) {
41
- ret.lang = params.get("lang");
42
- }
43
- if (params.has("issuerPath")) {
44
- ret.issuerPath = params.get("issuerPath");
45
- }
46
- return {
47
- filename,
48
- query: ret
49
- };
50
- }
7
+ import { normalize, parse } from 'pathe';
8
+ import { isArray, isString, isBoolean, assign, isNumber, isEmptyObject, generateCodeFrame } from '@intlify/shared';
9
+ import fg from 'fast-glob';
10
+ import { createFilter } from '@rollup/pluginutils';
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';
51
17
 
52
18
  const _require = module.createRequire(import.meta.url);
53
19
  function checkInstallPackage(debug) {
@@ -74,6 +40,9 @@ function resolvePkgPath(id, debug) {
74
40
  return null;
75
41
  }
76
42
  }
43
+ function resolveNamespace(name) {
44
+ return `unplugin-vue-i18n:${name}`;
45
+ }
77
46
  function warn(...args) {
78
47
  console.warn(pc.yellow(pc.bold(`[unplugin-vue-i18n] `)), ...args);
79
48
  }
@@ -86,22 +55,34 @@ async function getRaw(path2) {
86
55
  function raiseError(message) {
87
56
  throw new Error(`[unplugin-vue-i18n] ${message}`);
88
57
  }
89
-
90
- const INTLIFY_BUNDLE_IMPORT_ID = "@intlify/unplugin-vue-i18n/messages";
91
- const VIRTUAL_PREFIX = "\0";
92
- const debug = createDebug("unplugin-vue-i18n");
93
- const installedPkgInfo = checkInstallPackage(debug);
94
- const unplugin = createUnplugin((options = {}, meta) => {
95
- debug("plugin options:", options, meta.framework);
96
- if (!["vite", "webpack"].includes(meta.framework)) {
97
- raiseError(`This plugin is supported 'vite' and 'webpack' only`);
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;
98
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) {
99
80
  let onlyLocales = [];
100
81
  if (options.onlyLocales) {
101
- onlyLocales = Array.isArray(options.onlyLocales) ? options.onlyLocales : [options.onlyLocales];
82
+ onlyLocales = isArray(options.onlyLocales) ? options.onlyLocales : [options.onlyLocales];
102
83
  }
103
84
  let include = options.include;
104
- let exclude = null;
85
+ let exclude = void 0;
105
86
  if (include) {
106
87
  if (isArray(include)) {
107
88
  include = include.map((item) => normalize(item));
@@ -111,35 +92,137 @@ const unplugin = createUnplugin((options = {}, meta) => {
111
92
  } else {
112
93
  exclude = "**/**";
113
94
  }
114
- const filter = createFilter(include, exclude);
115
95
  const forceStringify = !!options.forceStringify;
116
96
  const defaultSFCLang = isString(options.defaultSFCLang) ? options.defaultSFCLang : "json";
117
97
  const globalSFCScope = !!options.globalSFCScope;
118
98
  const runtimeOnly = isBoolean(options.runtimeOnly) ? options.runtimeOnly : true;
119
- debug("runtimeOnly", runtimeOnly);
120
99
  const dropMessageCompiler = !!options.dropMessageCompiler;
121
- debug("dropMessageCompiler", dropMessageCompiler);
122
100
  const compositionOnly = installedPkgInfo.pkg === "vue-i18n" ? isBoolean(options.compositionOnly) ? options.compositionOnly : true : true;
123
- debug("compositionOnly", compositionOnly);
124
101
  const fullInstall = installedPkgInfo.pkg === "vue-i18n" ? isBoolean(options.fullInstall) ? options.fullInstall : true : false;
125
- debug("fullInstall", fullInstall);
126
102
  const ssrBuild = !!options.ssr;
127
- debug("ssr", ssrBuild);
128
- const getVueI18nAliasPath = ({ ssr = false, runtimeOnly: runtimeOnly2 = false }) => {
129
- return `${installedPkgInfo.alias}/dist/${installedPkgInfo.pkg}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
130
- };
131
103
  const allowDynamic = !!options.allowDynamic;
132
- debug("allowDynamic", allowDynamic);
133
104
  const strictMessage = isBoolean(options.strictMessage) ? options.strictMessage : true;
134
- debug("strictMessage", strictMessage);
135
105
  const escapeHtml = !!options.escapeHtml;
136
- debug("escapeHtml", 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
+ }
127
+
128
+ function parseVueRequest(id) {
129
+ const [filename, rawQuery] = id.split(`?`, 2);
130
+ const params = new URLSearchParams(rawQuery);
131
+ const ret = {};
132
+ const langPart = Object.keys(Object.fromEntries(params)).find(
133
+ (key) => /lang\./i.test(key)
134
+ );
135
+ ret.vue = params.has("vue");
136
+ ret.global = params.has("global");
137
+ ret.src = params.has("src");
138
+ ret.raw = params.has("raw");
139
+ if (params.has("type")) {
140
+ ret.type = params.get("type");
141
+ }
142
+ if (params.has("blockType")) {
143
+ ret.blockType = params.get("blockType");
144
+ }
145
+ if (params.has("index")) {
146
+ ret.index = Number(params.get("index"));
147
+ }
148
+ if (params.has("locale")) {
149
+ ret.locale = params.get("locale");
150
+ }
151
+ if (langPart) {
152
+ const [, lang] = langPart.split(".");
153
+ ret.lang = lang;
154
+ } else if (params.has("lang")) {
155
+ ret.lang = params.get("lang");
156
+ }
157
+ if (params.has("issuerPath")) {
158
+ ret.issuerPath = params.get("issuerPath");
159
+ }
160
+ return {
161
+ filename,
162
+ query: ret
163
+ };
164
+ }
165
+
166
+ function getVueCompiler(vuePlugin) {
167
+ return vuePlugin?.api?.options.compiler;
168
+ }
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
+ };
176
+ }
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 };
184
+ }
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;
191
+ }
192
+
193
+ const INTLIFY_BUNDLE_IMPORT_ID = "@intlify/unplugin-vue-i18n/messages";
194
+ const VIRTUAL_PREFIX = "\0";
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) {
212
+ const filter = createFilter(include, exclude);
213
+ const getVueI18nAliasPath = ({ ssr = false, runtimeOnly: runtimeOnly2 = false }) => {
214
+ return `${installedPkgInfo.alias}/dist/${installedPkgInfo.pkg}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
215
+ };
137
216
  let isProduction = false;
138
217
  let sourceMap = false;
139
218
  const vueI18nAliasName = installedPkgInfo.alias;
140
- debug(`vue-i18n alias name: ${vueI18nAliasName}`);
219
+ debug$2(`vue-i18n alias name: ${vueI18nAliasName}`);
220
+ let vuePlugin = null;
221
+ const getSfcParser = () => {
222
+ return vuePlugin ? getVueCompiler(vuePlugin).parse : parse$1;
223
+ };
141
224
  return {
142
- name: "unplugin-vue-i18n",
225
+ name: resolveNamespace("resource"),
143
226
  /**
144
227
  * NOTE:
145
228
  *
@@ -159,7 +242,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
159
242
  __VUE_I18N_PROD_DEVTOOLS__: false
160
243
  }
161
244
  };
162
- debug("define Config:", defineConfig);
245
+ debug$2("define Config:", defineConfig);
163
246
  const aliasConfig = {
164
247
  resolve: {
165
248
  alias: {
@@ -170,16 +253,20 @@ const unplugin = createUnplugin((options = {}, meta) => {
170
253
  }
171
254
  }
172
255
  };
173
- debug("alias Config:", aliasConfig);
256
+ debug$2("alias Config:", aliasConfig);
174
257
  return assign(defineConfig, aliasConfig);
175
258
  },
176
259
  configResolved(config) {
260
+ vuePlugin = getVitePlugin(config, "vite:vue");
261
+ if (!checkVuePlugin(vuePlugin)) {
262
+ return;
263
+ }
177
264
  isProduction = config.isProduction;
178
265
  sourceMap = config.command === "build" ? !!config.build.sourcemap : false;
179
- debug(
266
+ debug$2(
180
267
  `configResolved: isProduction = ${isProduction}, sourceMap = ${sourceMap}`
181
268
  );
182
- const jsonPlugin = config.plugins.find((p) => p.name === "vite:json");
269
+ const jsonPlugin = getVitePlugin(config, "vite:json");
183
270
  if (jsonPlugin) {
184
271
  const orgTransform = jsonPlugin.transform;
185
272
  jsonPlugin.transform = async function(code, id) {
@@ -190,13 +277,11 @@ const unplugin = createUnplugin((options = {}, meta) => {
190
277
  if (query.vue) {
191
278
  return;
192
279
  }
193
- debug("org json plugin");
280
+ debug$2("org json plugin");
194
281
  return orgTransform.apply(this, [code, id]);
195
282
  };
196
283
  }
197
- const esbuildPlugin = config.plugins.find(
198
- (p) => p.name === "vite:esbuild"
199
- );
284
+ const esbuildPlugin = getVitePlugin(config, "vite:esbuild");
200
285
  if (esbuildPlugin) {
201
286
  const orgTransform = esbuildPlugin.transform;
202
287
  esbuildPlugin.transform = async function(code, id) {
@@ -229,10 +314,10 @@ const unplugin = createUnplugin((options = {}, meta) => {
229
314
  forceStringify
230
315
  }
231
316
  );
232
- debug("parseOptions", parseOptions);
317
+ debug$2("parseOptions", parseOptions);
233
318
  const { code: generatedCode, map } = generate(_code, parseOptions);
234
- debug("generated code", generatedCode);
235
- debug("sourcemap", map, sourceMap);
319
+ debug$2("generated code", generatedCode);
320
+ debug$2("sourcemap", map, sourceMap);
236
321
  if (_code === generatedCode)
237
322
  return;
238
323
  return {
@@ -260,7 +345,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
260
345
  webpack(compiler) {
261
346
  isProduction = compiler.options.mode !== "development";
262
347
  sourceMap = !!compiler.options.devtool;
263
- debug(`webpack: isProduction = ${isProduction}, sourceMap = ${sourceMap}`);
348
+ debug$2(`webpack: isProduction = ${isProduction}, sourceMap = ${sourceMap}`);
264
349
  compiler.options.resolve = normalizeConfigResolveAlias(
265
350
  compiler.options.resolve,
266
351
  meta.framework
@@ -269,7 +354,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
269
354
  ssr: ssrBuild,
270
355
  runtimeOnly
271
356
  });
272
- debug(
357
+ debug$2(
273
358
  `set ${vueI18nAliasName}: ${getVueI18nAliasPath({
274
359
  ssr: ssrBuild,
275
360
  runtimeOnly
@@ -284,10 +369,10 @@ const unplugin = createUnplugin((options = {}, meta) => {
284
369
  __INTLIFY_PROD_DEVTOOLS__: "false"
285
370
  })
286
371
  );
287
- debug(`set __VUE_I18N_LEGACY_API__ is '${compositionOnly}'`);
288
- 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}'`);
289
374
  } else {
290
- debug("ignore vue-i18n feature flags with webpack.DefinePlugin");
375
+ debug$2("ignore vue-i18n feature flags with webpack.DefinePlugin");
291
376
  }
292
377
  });
293
378
  if (compiler.options.module) {
@@ -301,15 +386,14 @@ const unplugin = createUnplugin((options = {}, meta) => {
301
386
  }
302
387
  },
303
388
  resolveId(id, importer) {
304
- debug("resolveId", id, importer);
389
+ debug$2("resolveId", id, importer);
305
390
  if (id === INTLIFY_BUNDLE_IMPORT_ID) {
306
391
  return asVirtualId(id, meta.framework);
307
392
  }
308
393
  },
309
394
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
310
395
  async load(id) {
311
- debug("load", id);
312
- const { query } = parseVueRequest(id);
396
+ debug$2("load", id);
313
397
  if (INTLIFY_BUNDLE_IMPORT_ID === getVirtualId(id, meta.framework) && include) {
314
398
  let resourcePaths = [];
315
399
  const includePaths = isArray(include) ? include : [include];
@@ -321,7 +405,6 @@ const unplugin = createUnplugin((options = {}, meta) => {
321
405
  );
322
406
  const code = await generateBundleResources(
323
407
  resourcePaths,
324
- query,
325
408
  isProduction,
326
409
  {
327
410
  forceStringify,
@@ -336,7 +419,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
336
419
  }
337
420
  },
338
421
  transformInclude(id) {
339
- debug("transformInclude", id);
422
+ debug$2("transformInclude", id);
340
423
  if (meta.framework === "vite") {
341
424
  return true;
342
425
  } else {
@@ -346,7 +429,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
346
429
  },
347
430
  async transform(code, id) {
348
431
  const { filename, query } = parseVueRequest(id);
349
- debug("transform", id, JSON.stringify(query), filename);
432
+ debug$2("transform", id, JSON.stringify(query), filename);
350
433
  let langInfo = defaultSFCLang;
351
434
  let inSourceMap;
352
435
  if (!query.vue) {
@@ -369,10 +452,10 @@ const unplugin = createUnplugin((options = {}, meta) => {
369
452
  forceStringify
370
453
  }
371
454
  );
372
- debug("parseOptions", parseOptions);
455
+ debug$2("parseOptions", parseOptions);
373
456
  const { code: generatedCode, map } = generate(code, parseOptions);
374
- debug("generated code", generatedCode);
375
- debug("sourcemap", map, sourceMap);
457
+ debug$2("generated code", generatedCode);
458
+ debug$2("sourcemap", map, sourceMap);
376
459
  if (code === generatedCode)
377
460
  return;
378
461
  return {
@@ -388,7 +471,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
388
471
  } else if (defaultSFCLang) {
389
472
  langInfo = defaultSFCLang;
390
473
  }
391
- debug("langInfo", langInfo);
474
+ debug$2("langInfo", langInfo);
392
475
  const generate = /\.?json5?/.test(langInfo) ? generateJSON : generateYAML;
393
476
  const parseOptions = getOptions(
394
477
  filename,
@@ -405,17 +488,18 @@ const unplugin = createUnplugin((options = {}, meta) => {
405
488
  forceStringify
406
489
  }
407
490
  );
408
- debug("parseOptions", parseOptions);
491
+ debug$2("parseOptions", parseOptions);
409
492
  const source = await getCode(
410
493
  code,
411
494
  filename,
412
495
  sourceMap,
413
496
  query,
497
+ getSfcParser(),
414
498
  meta.framework
415
499
  );
416
500
  const { code: generatedCode, map } = generate(source, parseOptions);
417
- debug("generated code", generatedCode);
418
- debug("sourcemap", map, sourceMap);
501
+ debug$2("generated code", generatedCode);
502
+ debug$2("sourcemap", map, sourceMap);
419
503
  if (code === generatedCode)
420
504
  return;
421
505
  return {
@@ -427,7 +511,7 @@ const unplugin = createUnplugin((options = {}, meta) => {
427
511
  }
428
512
  }
429
513
  };
430
- });
514
+ }
431
515
  function getGenerator(ext, defaultGen = generateJSON) {
432
516
  return /\.?json5?$/.test(ext) ? generateJSON : /\.ya?ml$/.test(ext) ? generateYAML : /\.([c|m]?js|[c|m]?ts)$/.test(ext) ? generateJavaScript : defaultGen;
433
517
  }
@@ -460,7 +544,7 @@ async function loadWebpack() {
460
544
  }
461
545
  return webpack;
462
546
  }
463
- async function generateBundleResources(resources, query, isProduction, {
547
+ async function generateBundleResources(resources, isProduction, {
464
548
  forceStringify = false,
465
549
  isGlobal = false,
466
550
  onlyLocales = [],
@@ -470,7 +554,7 @@ async function generateBundleResources(resources, query, isProduction, {
470
554
  }) {
471
555
  const codes = [];
472
556
  for (const res of resources) {
473
- debug(`${res} bundle loading ...`);
557
+ debug$2(`${res} bundle loading ...`);
474
558
  if (/\.(json5?|ya?ml)$/.test(res)) {
475
559
  const { ext, name } = parse(res);
476
560
  const source = await getRaw(res);
@@ -485,7 +569,7 @@ async function generateBundleResources(resources, query, isProduction, {
485
569
  });
486
570
  parseOptions.type = "bare";
487
571
  const { code } = generate(source, parseOptions);
488
- debug("generated code", code);
572
+ debug$2("generated code", code);
489
573
  codes.push(`${JSON.stringify(name)}: ${code}`);
490
574
  }
491
575
  }
@@ -513,24 +597,24 @@ export default mergeDeep({},
513
597
  ${codes.map((code) => `{${code}}`).join(",\n")}
514
598
  );`;
515
599
  }
516
- async function getCode(source, filename, sourceMap, query, framework = "vite") {
600
+ async function getCode(source, filename, sourceMap, query, parser, framework = "vite") {
517
601
  const { index, issuerPath } = query;
518
602
  if (!isNumber(index)) {
519
603
  raiseError(`unexpected index: ${index}`);
520
604
  }
521
605
  if (framework === "webpack") {
522
606
  if (issuerPath) {
523
- debug(`getCode (webpack) ${index} via issuerPath`, issuerPath);
607
+ debug$2(`getCode (webpack) ${index} via issuerPath`, issuerPath);
524
608
  return await getRaw(filename);
525
609
  } else {
526
- const result = parse$1(await getRaw(filename), {
610
+ const result = parser(await getRaw(filename), {
527
611
  sourceMap,
528
612
  filename
529
613
  });
530
614
  const block = result.descriptor.customBlocks[index];
531
615
  if (block) {
532
616
  const code = block.src ? await getRaw(block.src) : block.content;
533
- debug(`getCode (webpack) ${index} from SFC`, code);
617
+ debug$2(`getCode (webpack) ${index} from SFC`, code);
534
618
  return code;
535
619
  } else {
536
620
  return source;
@@ -606,4 +690,294 @@ function asVirtualId(id, framework = "vite") {
606
690
  return framework === "vite" ? VIRTUAL_PREFIX + id : id;
607
691
  }
608
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
+
609
983
  export { unplugin as default, unplugin };