vue-i18n-extract-plugin 1.0.70 → 1.0.72

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.
Files changed (2) hide show
  1. package/lib/visitors.js +90 -4
  2. package/package.json +1 -1
package/lib/visitors.js CHANGED
@@ -56,6 +56,7 @@ function getPropKey(propNode) {
56
56
  return null;
57
57
  }
58
58
 
59
+ // 将静态属性转换为动态属性,如 <div title="xxx" /> => <div :title="$t('hashed')" />
59
60
  function transformDirectiveIfNeeded(path, parentPath) {
60
61
  let hasCreateVNode = false;
61
62
  // 属性值情况,如 title: "xxx"
@@ -152,6 +153,77 @@ function generateJSXElement(name, id, msg) {
152
153
  return t.jsxElement(openingElement, null, [], true);
153
154
  }
154
155
 
156
+ function unwrapVueCacheIfNeeded(path) {
157
+ const assignPath = path.parentPath;
158
+ if (!assignPath || !assignPath.isAssignmentExpression({ operator: "=" })) {
159
+ return false;
160
+ }
161
+
162
+ const logicalPath = assignPath.parentPath;
163
+ if (!logicalPath || !logicalPath.isLogicalExpression({ operator: "||" })) {
164
+ return false;
165
+ }
166
+
167
+ const { left, right } = logicalPath.node;
168
+
169
+ // 校验 left: _cache[x]
170
+ const isCacheMember =
171
+ t.isMemberExpression(left) &&
172
+ (t.isIdentifier(left.object, { name: "_cache" }) ||
173
+ (t.isIdentifier(left.object) && left.object.name.startsWith("_cache")));
174
+
175
+ // 校验 right: (_cache[x] = createTextVNode(...))
176
+ const isSameAssignment =
177
+ right === assignPath.node &&
178
+ t.isMemberExpression(assignPath.node.left) &&
179
+ t.isCallExpression(assignPath.node.right);
180
+
181
+ if (!isCacheMember || !isSameAssignment) {
182
+ return false;
183
+ }
184
+
185
+ // 用 createTextVNode(...) 替换整个 _cache || (...)
186
+ logicalPath.replaceWith(assignPath.node.right);
187
+ return true;
188
+ }
189
+
190
+ function unwrapVueSlotArrayCache(path) {
191
+ // 1. 找 ArrayExpression
192
+ const arrayPath = path.findParent(p => p.isArrayExpression());
193
+ if (!arrayPath) return false;
194
+
195
+ // 2. array 是 assignment 的 right
196
+ const assignPath = arrayPath.parentPath;
197
+ if (!assignPath?.isAssignmentExpression({ operator: "=" })) return false;
198
+
199
+ // 3. assignment 在 LogicalExpression || 中
200
+ const logicalPath = assignPath.parentPath;
201
+ if (!logicalPath?.isLogicalExpression({ operator: "||" })) return false;
202
+
203
+ // 4. logical 在 SpreadElement 中
204
+ const spreadPath = logicalPath.parentPath;
205
+ if (!spreadPath?.isSpreadElement()) return false;
206
+
207
+ // 5. 校验 _cache[x]
208
+ const left = logicalPath.node.left;
209
+ const isCache =
210
+ t.isMemberExpression(left) &&
211
+ t.isIdentifier(left.object) &&
212
+ left.object.name.startsWith("_cache");
213
+
214
+ if (!isCache) return false;
215
+
216
+ // unwrap:用 array.elements 替换 spread(...)
217
+ spreadPath.replaceWithMultiple(arrayPath.node.elements);
218
+
219
+ return true;
220
+ }
221
+
222
+ function isDynamicTextExpression(node) {
223
+ // 只要不是 StringLiteral,100% 是动态文本
224
+ return !t.isStringLiteral(node);
225
+ }
226
+
155
227
  function createI18nVisitor(option, i18nMap) {
156
228
  const excludedCall = [...option.excludedCall, ...EXCLUDED_CALL];
157
229
 
@@ -189,7 +261,19 @@ function createI18nVisitor(option, i18nMap) {
189
261
  path.node.arguments.push(t.stringLiteral(keyText));
190
262
  }
191
263
  },
264
+ CallExpression(path) {
265
+ if (!isVNodeCall(path, "_createTextVNode")) return;
266
+
267
+ const args = path.node.arguments;
268
+ if (!args.length) return;
192
269
 
270
+ const content = args[0];
271
+
272
+ // 是否动态文本
273
+ if (isDynamicTextExpression(content)) {
274
+ args[1] = t.numericLiteral(1); // PatchFlags.TEXT createTextVNode(" " + toDisplayString$1(text)) => createTextVNode(" " + toDisplayString$1(text), 1)
275
+ }
276
+ },
193
277
  StringLiteral(path) {
194
278
  if (option.extractFromText === false) return;
195
279
  if (!shouldTransform(path)) return;
@@ -255,10 +339,12 @@ function createI18nVisitor(option, i18nMap) {
255
339
 
256
340
  // 判断是否createTextVNode或MemberExpression(如 Vue.createTextVNode)
257
341
  if (isVNodeCall(parentPath, "_createTextVNode")) {
258
- // 如果 createTextVNode 参数只有一个,则补充第二个参数 1
259
- const args = parentPath.node.arguments;
260
- if (args.length === 1) {
261
- parentPath.node.arguments = [callExpression, t.numericLiteral(1)];
342
+ // createTextVNode强制补充第二个参数 1
343
+ parentPath.node.arguments = [callExpression, t.numericLiteral(1)];
344
+ // 先尝试 [...(_cache2[4] || (_cache2[4] = [ createTextVNode(...) ]))]
345
+ if (!unwrapVueSlotArrayCache(parentPath)) {
346
+ // 再尝试拆 _cache2[0] || (_cache2[0] = createTextVNode(...))
347
+ unwrapVueCacheIfNeeded(parentPath);
262
348
  }
263
349
  // 是否 vue.createElementVNode(...),且该 StringLiteral 是第三个参数
264
350
  } else if (isVNodeCall(parentPath, "_createElementVNode")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-i18n-extract-plugin",
3
- "version": "1.0.70",
3
+ "version": "1.0.72",
4
4
  "main": "lib/index.js",
5
5
  "types": "types/index.d.ts",
6
6
  "bin": {