@intlayer/babel 9.3.0 → 9.3.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.
Files changed (76) hide show
  1. package/README.md +24 -24
  2. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
  3. package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
  4. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +66 -8
  5. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
  6. package/dist/cjs/babel-plugin-intlayer-optimize.cjs +9 -5
  7. package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
  8. package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -1
  9. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs +142 -54
  10. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
  11. package/dist/cjs/babelParser.cjs.map +1 -1
  12. package/dist/cjs/extractContent/babelProcessor.cjs +57 -57
  13. package/dist/cjs/extractContent/babelProcessor.cjs.map +1 -1
  14. package/dist/cjs/extractContent/contentWriter.cjs +3 -2
  15. package/dist/cjs/extractContent/contentWriter.cjs.map +1 -1
  16. package/dist/cjs/extractContent/extractContent.cjs +7 -6
  17. package/dist/cjs/extractContent/extractContent.cjs.map +1 -1
  18. package/dist/cjs/extractContent/index.cjs +0 -1
  19. package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -1
  20. package/dist/cjs/extractContent/utils/constants.cjs +0 -14
  21. package/dist/cjs/extractContent/utils/constants.cjs.map +1 -1
  22. package/dist/cjs/extractContent/utils/detectPackageName.cjs.map +1 -1
  23. package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs +5 -3
  24. package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs.map +1 -1
  25. package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs.map +1 -1
  26. package/dist/cjs/extractContent/utils/generateKey.cjs +0 -1
  27. package/dist/cjs/extractContent/utils/generateKey.cjs.map +1 -1
  28. package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs.map +1 -1
  29. package/dist/cjs/extractContent/utils/index.cjs +1 -4
  30. package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs.map +1 -1
  31. package/dist/cjs/extractScriptBlocks.cjs.map +1 -1
  32. package/dist/cjs/getExtractPluginOptions.cjs +4 -2
  33. package/dist/cjs/getExtractPluginOptions.cjs.map +1 -1
  34. package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
  35. package/dist/cjs/getPurgePluginOptions.cjs.map +1 -1
  36. package/dist/cjs/index.cjs +1 -1
  37. package/dist/cjs/transformers.cjs.map +1 -1
  38. package/dist/esm/babel-plugin-intlayer-field-rename.mjs +67 -9
  39. package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
  40. package/dist/esm/babel-plugin-intlayer-optimize.mjs +9 -5
  41. package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
  42. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs +142 -54
  43. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
  44. package/dist/esm/extractContent/babelProcessor.mjs +51 -51
  45. package/dist/esm/extractContent/babelProcessor.mjs.map +1 -1
  46. package/dist/esm/extractContent/contentWriter.mjs +3 -2
  47. package/dist/esm/extractContent/contentWriter.mjs.map +1 -1
  48. package/dist/esm/extractContent/extractContent.mjs +5 -4
  49. package/dist/esm/extractContent/extractContent.mjs.map +1 -1
  50. package/dist/esm/extractContent/index.mjs +2 -2
  51. package/dist/esm/extractContent/utils/constants.mjs +1 -13
  52. package/dist/esm/extractContent/utils/constants.mjs.map +1 -1
  53. package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs +5 -3
  54. package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs.map +1 -1
  55. package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs.map +1 -1
  56. package/dist/esm/extractContent/utils/index.mjs +2 -3
  57. package/dist/esm/getExtractPluginOptions.mjs +4 -2
  58. package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
  59. package/dist/esm/index.mjs +3 -3
  60. package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
  61. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts +16 -1
  62. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
  63. package/dist/types/extractContent/babelProcessor.d.ts.map +1 -1
  64. package/dist/types/extractContent/extractContent.d.ts.map +1 -1
  65. package/dist/types/extractContent/index.d.ts +2 -2
  66. package/dist/types/extractContent/utils/constants.d.ts +1 -7
  67. package/dist/types/extractContent/utils/constants.d.ts.map +1 -1
  68. package/dist/types/extractContent/utils/index.d.ts +2 -3
  69. package/dist/types/index.d.ts +3 -3
  70. package/package.json +9 -10
  71. package/dist/cjs/extractContent/utils/shouldExtract.cjs +0 -39
  72. package/dist/cjs/extractContent/utils/shouldExtract.cjs.map +0 -1
  73. package/dist/esm/extractContent/utils/shouldExtract.mjs +0 -37
  74. package/dist/esm/extractContent/utils/shouldExtract.mjs.map +0 -1
  75. package/dist/types/extractContent/utils/shouldExtract.d.ts +0 -15
  76. package/dist/types/extractContent/utils/shouldExtract.d.ts.map +0 -1
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/babel-plugin-intlayer-usage-analyzer.ts
4
3
  const createPruneContext = () => ({
5
4
  dictionaryKeyToFieldUsageMap: /* @__PURE__ */ new Map(),
@@ -55,6 +54,21 @@ const preserveNestedDictionaryFields = (pruneContext, nestedDictionaryReferences
55
54
  for (const nestedField of nestedFields) currentFieldUsage.add(nestedField);
56
55
  }
57
56
  };
57
+ /**
58
+ * Methods the runtime attaches to a resolved content object rather than fields
59
+ * declared in a `.content` file.
60
+ *
61
+ * `vanilla-intlayer`'s `useIntlayer` / `useDictionary` assign `onChange` onto
62
+ * the content they return, so `useIntlayer('app').onChange(cb)` is a
63
+ * subscription — not a read of a field named `onChange`. Without this list the
64
+ * analyser records `onChange` as the only consumed field and the purge pass
65
+ * strips every real field from the compiled dictionary.
66
+ *
67
+ * The analyser looks *through* these calls: the callback parameter is analysed
68
+ * as a fresh content root, and the call result is analysed again because the
69
+ * helpers return the content object for chaining.
70
+ */
71
+ const CHAINABLE_RUNTIME_METHOD_NAMES = /* @__PURE__ */ new Set(["onChange"]);
58
72
  /** Canonical intlayer caller names that trigger usage analysis. */
59
73
  const INTLAYER_CALLER_NAMES = ["useIntlayer", "getIntlayer"];
60
74
  /**
@@ -99,7 +113,6 @@ const recordFieldUsage = (pruneContext, dictionaryKey, fieldUsage) => {
99
113
  * const result = useIntlayer('key') → records 'all' (untracked binding)
100
114
  */
101
115
  const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath, dictionaryKey, currentSourceFilePath, isSfcFile) => {
102
- const parentNode = callExpressionPath.parent;
103
116
  /** Mark the dictionary key as having an untracked binding in this file. */
104
117
  const markUntrackedBinding = () => {
105
118
  const existingPaths = pruneContext.dictionaryKeysWithUntrackedBindings.get(dictionaryKey) ?? [];
@@ -227,32 +240,64 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
227
240
  }
228
241
  return true;
229
242
  };
230
- if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isObjectPattern(parentNode.id)) {
231
- const accessedFieldNames = /* @__PURE__ */ new Set();
232
- if (collectFieldsFromObjectPattern(parentNode.id, callExpressionPath, accessedFieldNames)) recordFieldUsage(pruneContext, dictionaryKey, accessedFieldNames);
233
- else recordFieldUsage(pruneContext, dictionaryKey, "all");
234
- return;
235
- }
236
- if ((babelTypes.isMemberExpression(parentNode) || babelTypes.isOptionalMemberExpression(parentNode)) && parentNode.object === callExpressionPath.node) {
237
- let fieldName;
238
- if (!parentNode.computed && babelTypes.isIdentifier(parentNode.property)) fieldName = parentNode.property.name;
239
- else if (parentNode.computed && babelTypes.isStringLiteral(parentNode.property)) fieldName = parentNode.property.value;
240
- if (fieldName) {
241
- recordFieldUsage(pruneContext, dictionaryKey, /* @__PURE__ */ new Set([fieldName]));
242
- const memberExprPath = callExpressionPath.parentPath;
243
- if (memberExprPath) analyzeOpaqueUsage(memberExprPath, [fieldName]);
244
- } else markUntrackedBinding();
245
- return;
246
- }
247
- if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isIdentifier(parentNode.id)) {
248
- const variableName = parentNode.id.name;
249
- const variableBinding = callExpressionPath.scope.getBinding(variableName);
250
- if (!variableBinding) {
243
+ /**
244
+ * Returns the call path when `memberExprPath` is a chainable runtime helper
245
+ * being invoked (`content.onChange(cb)`), otherwise `undefined`.
246
+ *
247
+ * See {@link CHAINABLE_RUNTIME_METHOD_NAMES}: a bare `content.onChange`
248
+ * reference that is never called is treated as an ordinary field access, so
249
+ * only the invoked form is looked through.
250
+ */
251
+ const getChainedRuntimeCallPath = (memberExprPath, fieldName) => {
252
+ if (!CHAINABLE_RUNTIME_METHOD_NAMES.has(fieldName)) return void 0;
253
+ if (!memberExprPath) return void 0;
254
+ const callPath = memberExprPath.parentPath;
255
+ if (!callPath) return void 0;
256
+ if (!callPath.isCallExpression() && !callPath.isOptionalCallExpression()) return;
257
+ if (callPath.node.callee !== memberExprPath.node) return;
258
+ return callPath;
259
+ };
260
+ /**
261
+ * Analyses the callbacks handed to a chainable runtime helper.
262
+ *
263
+ * The callback receives the freshly-resolved content root, so its parameter
264
+ * is walked exactly like `const content = useIntlayer('key')` — either as a
265
+ * plain binding or as a destructuring pattern.
266
+ */
267
+ const analyzeChainedCallbackArguments = (callPath) => {
268
+ const argumentPaths = callPath.get("arguments");
269
+ for (const argumentPath of argumentPaths) {
270
+ if (!argumentPath.isArrowFunctionExpression() && !argumentPath.isFunctionExpression()) continue;
271
+ const [firstParameterPath] = argumentPath.get("params");
272
+ if (!firstParameterPath) continue;
273
+ if (firstParameterPath.isIdentifier()) {
274
+ const parameterBinding = argumentPath.scope.getBinding(firstParameterPath.node.name);
275
+ if (!parameterBinding) {
276
+ markUntrackedBinding();
277
+ continue;
278
+ }
279
+ const accessedFieldNames = /* @__PURE__ */ new Set();
280
+ if (analyzeContentBindingReferences(parameterBinding, accessedFieldNames)) markUntrackedBinding();
281
+ else recordFieldUsage(pruneContext, dictionaryKey, accessedFieldNames);
282
+ continue;
283
+ }
284
+ if (firstParameterPath.isObjectPattern()) {
285
+ const accessedFieldNames = /* @__PURE__ */ new Set();
286
+ if (collectFieldsFromObjectPattern(firstParameterPath.node, argumentPath, accessedFieldNames)) recordFieldUsage(pruneContext, dictionaryKey, accessedFieldNames);
287
+ else recordFieldUsage(pruneContext, dictionaryKey, "all");
288
+ continue;
289
+ }
251
290
  markUntrackedBinding();
252
- return;
253
291
  }
254
- const accessedTopLevelFieldNames = /* @__PURE__ */ new Set();
255
- let hasUntrackedReferenceAccess = false;
292
+ };
293
+ /**
294
+ * Walks every reference of a local binding holding the content root,
295
+ * collecting the top-level fields it reads into `accessedTopLevelFieldNames`.
296
+ *
297
+ * @returns `true` when a reference escaped static tracking, meaning the whole
298
+ * dictionary must be kept.
299
+ */
300
+ const analyzeContentBindingReferences = (variableBinding, accessedTopLevelFieldNames) => {
256
301
  for (const variableReferencePath of variableBinding.referencePaths) {
257
302
  const referenceParentNode = variableReferencePath.parent;
258
303
  if ((babelTypes.isMemberExpression(referenceParentNode) || babelTypes.isOptionalMemberExpression(referenceParentNode)) && referenceParentNode.object === variableReferencePath.node) {
@@ -261,17 +306,18 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
261
306
  if (!memberExpressionNode.computed && babelTypes.isIdentifier(memberExpressionNode.property)) fieldName = memberExpressionNode.property.name;
262
307
  else if (memberExpressionNode.computed && babelTypes.isStringLiteral(memberExpressionNode.property)) fieldName = memberExpressionNode.property.value;
263
308
  if (fieldName) {
264
- accessedTopLevelFieldNames.add(fieldName);
265
309
  const memberExprPath = variableReferencePath.parentPath;
310
+ const chainedCallPath = getChainedRuntimeCallPath(memberExprPath, fieldName);
311
+ if (chainedCallPath) {
312
+ analyzeChainedCallbackArguments(chainedCallPath);
313
+ analyzeContentRoot(chainedCallPath);
314
+ continue;
315
+ }
316
+ accessedTopLevelFieldNames.add(fieldName);
266
317
  if (memberExprPath) analyzeOpaqueUsage(memberExprPath, [fieldName]);
267
- } else {
268
- hasUntrackedReferenceAccess = true;
269
- break;
270
- }
271
- } else if (babelTypes.isArrayExpression(referenceParentNode)) {
272
- hasUntrackedReferenceAccess = true;
273
- break;
274
- } else if ((babelTypes.isCallExpression(referenceParentNode) || babelTypes.isOptionalCallExpression(referenceParentNode)) && referenceParentNode.callee === variableReferencePath.node) {
318
+ } else return true;
319
+ } else if (babelTypes.isArrayExpression(referenceParentNode)) return true;
320
+ else if ((babelTypes.isCallExpression(referenceParentNode) || babelTypes.isOptionalCallExpression(referenceParentNode)) && referenceParentNode.callee === variableReferencePath.node) {
275
321
  const callExprPath = variableReferencePath.parentPath;
276
322
  const callParent = callExprPath?.parent;
277
323
  if (callParent && (babelTypes.isMemberExpression(callParent) || babelTypes.isOptionalMemberExpression(callParent)) && callParent.object === callExprPath?.node) {
@@ -280,30 +326,71 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
280
326
  if (!memberExpr.computed && babelTypes.isIdentifier(memberExpr.property)) fieldName = memberExpr.property.name;
281
327
  else if (memberExpr.computed && babelTypes.isStringLiteral(memberExpr.property)) fieldName = memberExpr.property.value;
282
328
  if (fieldName) {
283
- accessedTopLevelFieldNames.add(fieldName);
284
329
  const memberExprPath = callExprPath?.parentPath;
330
+ const chainedCallPath = getChainedRuntimeCallPath(memberExprPath, fieldName);
331
+ if (chainedCallPath) {
332
+ analyzeChainedCallbackArguments(chainedCallPath);
333
+ analyzeContentRoot(chainedCallPath);
334
+ continue;
335
+ }
336
+ accessedTopLevelFieldNames.add(fieldName);
285
337
  if (memberExprPath) analyzeOpaqueUsage(memberExprPath, [fieldName]);
286
- } else {
287
- hasUntrackedReferenceAccess = true;
288
- break;
289
- }
290
- } else if (callParent && babelTypes.isVariableDeclarator(callParent) && babelTypes.isObjectPattern(callParent.id) && callExprPath && collectFieldsFromObjectPattern(callParent.id, callExprPath, accessedTopLevelFieldNames)) {} else {
291
- hasUntrackedReferenceAccess = true;
292
- break;
338
+ } else return true;
339
+ } else if (callParent && babelTypes.isVariableDeclarator(callParent) && babelTypes.isObjectPattern(callParent.id) && callExprPath && collectFieldsFromObjectPattern(callParent.id, callExprPath, accessedTopLevelFieldNames)) {} else return true;
340
+ } else return true;
341
+ }
342
+ return false;
343
+ };
344
+ /**
345
+ * Analyses how the content root referenced by `rootPath` is consumed.
346
+ *
347
+ * `rootPath` is the `useIntlayer('key')` call itself, or any expression that
348
+ * evaluates back to the same content object — currently the result of a
349
+ * chainable runtime helper such as `.onChange(…)`.
350
+ */
351
+ const analyzeContentRoot = (rootPath) => {
352
+ const parentNode = rootPath.parent;
353
+ if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isObjectPattern(parentNode.id)) {
354
+ const accessedFieldNames = /* @__PURE__ */ new Set();
355
+ if (collectFieldsFromObjectPattern(parentNode.id, rootPath, accessedFieldNames)) recordFieldUsage(pruneContext, dictionaryKey, accessedFieldNames);
356
+ else recordFieldUsage(pruneContext, dictionaryKey, "all");
357
+ return;
358
+ }
359
+ if ((babelTypes.isMemberExpression(parentNode) || babelTypes.isOptionalMemberExpression(parentNode)) && parentNode.object === rootPath.node) {
360
+ let fieldName;
361
+ if (!parentNode.computed && babelTypes.isIdentifier(parentNode.property)) fieldName = parentNode.property.name;
362
+ else if (parentNode.computed && babelTypes.isStringLiteral(parentNode.property)) fieldName = parentNode.property.value;
363
+ if (fieldName) {
364
+ const memberExprPath = rootPath.parentPath;
365
+ const chainedCallPath = getChainedRuntimeCallPath(memberExprPath, fieldName);
366
+ if (chainedCallPath) {
367
+ analyzeChainedCallbackArguments(chainedCallPath);
368
+ analyzeContentRoot(chainedCallPath);
369
+ return;
293
370
  }
294
- } else {
295
- hasUntrackedReferenceAccess = true;
296
- break;
371
+ recordFieldUsage(pruneContext, dictionaryKey, /* @__PURE__ */ new Set([fieldName]));
372
+ if (memberExprPath) analyzeOpaqueUsage(memberExprPath, [fieldName]);
373
+ } else markUntrackedBinding();
374
+ return;
375
+ }
376
+ if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isIdentifier(parentNode.id)) {
377
+ const variableName = parentNode.id.name;
378
+ const variableBinding = rootPath.scope.getBinding(variableName);
379
+ if (!variableBinding) {
380
+ markUntrackedBinding();
381
+ return;
297
382
  }
383
+ const accessedTopLevelFieldNames = /* @__PURE__ */ new Set();
384
+ if (analyzeContentBindingReferences(variableBinding, accessedTopLevelFieldNames)) markUntrackedBinding();
385
+ else if (isSfcFile) deferFrameworkAnalysis(variableName);
386
+ else if (variableBinding.referencePaths.length === 0) markUntrackedBinding();
387
+ else recordFieldUsage(pruneContext, dictionaryKey, accessedTopLevelFieldNames);
388
+ return;
298
389
  }
299
- if (hasUntrackedReferenceAccess) markUntrackedBinding();
300
- else if (isSfcFile) deferFrameworkAnalysis(variableName);
301
- else if (variableBinding.referencePaths.length === 0) markUntrackedBinding();
302
- else recordFieldUsage(pruneContext, dictionaryKey, accessedTopLevelFieldNames);
303
- return;
304
- }
305
- if (babelTypes.isExpressionStatement(parentNode)) return;
306
- markUntrackedBinding();
390
+ if (babelTypes.isExpressionStatement(parentNode)) return;
391
+ markUntrackedBinding();
392
+ };
393
+ analyzeContentRoot(callExpressionPath);
307
394
  };
308
395
  /**
309
396
  * Reads a fully-static string from an AST node. Returns `undefined` for
@@ -647,6 +734,7 @@ const makeUsageAnalyzerBabelPlugin = (pruneContext, options) => ({ types: babelT
647
734
  };
648
735
 
649
736
  //#endregion
737
+ exports.CHAINABLE_RUNTIME_METHOD_NAMES = CHAINABLE_RUNTIME_METHOD_NAMES;
650
738
  exports.DEFAULT_COMPAT_CALLERS = DEFAULT_COMPAT_CALLERS;
651
739
  exports.INTLAYER_CALLER_NAMES = INTLAYER_CALLER_NAMES;
652
740
  exports.createPruneContext = createPruneContext;