@intlayer/babel 9.0.0-canary.2 → 9.0.0-canary.20

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 (152) hide show
  1. package/dist/cjs/babel-plugin-intlayer-extract.cjs +3 -2
  2. package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
  3. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +160 -99
  4. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
  5. package/dist/cjs/babel-plugin-intlayer-minify.cjs +11 -28
  6. package/dist/cjs/babel-plugin-intlayer-minify.cjs.map +1 -1
  7. package/dist/cjs/babel-plugin-intlayer-optimize.cjs +143 -13
  8. package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
  9. package/dist/cjs/babel-plugin-intlayer-purge.cjs +38 -96
  10. package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -1
  11. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs +151 -52
  12. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
  13. package/dist/cjs/babelParser.cjs +62 -0
  14. package/dist/cjs/babelParser.cjs.map +1 -0
  15. package/dist/cjs/extractContent/babelProcessor.cjs +144 -71
  16. package/dist/cjs/extractContent/babelProcessor.cjs.map +1 -1
  17. package/dist/cjs/extractContent/contentWriter.cjs +10 -14
  18. package/dist/cjs/extractContent/contentWriter.cjs.map +1 -1
  19. package/dist/cjs/extractContent/extractContent.cjs +3 -3
  20. package/dist/cjs/extractContent/extractContent.cjs.map +1 -1
  21. package/dist/cjs/extractContent/processTsxFile.cjs +4 -7
  22. package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -1
  23. package/dist/cjs/extractContent/utils/constants.cjs +2 -2
  24. package/dist/cjs/extractContent/utils/constants.cjs.map +1 -1
  25. package/dist/cjs/extractContent/utils/detectPackageName.cjs +0 -1
  26. package/dist/cjs/extractContent/utils/detectPackageName.cjs.map +1 -1
  27. package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs +4 -4
  28. package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs.map +1 -1
  29. package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs +2 -3
  30. package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs.map +1 -1
  31. package/dist/cjs/extractContent/utils/generateKey.cjs.map +1 -1
  32. package/dist/cjs/extractContent/utils/getComponentName.cjs.map +1 -1
  33. package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs.map +1 -1
  34. package/dist/cjs/extractContent/utils/getOrGenerateKey.cjs.map +1 -1
  35. package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs +0 -1
  36. package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs.map +1 -1
  37. package/dist/cjs/extractContent/utils/shouldExtract.cjs +2 -0
  38. package/dist/cjs/extractContent/utils/shouldExtract.cjs.map +1 -1
  39. package/dist/cjs/extractScriptBlocks.cjs +0 -1
  40. package/dist/cjs/extractScriptBlocks.cjs.map +1 -1
  41. package/dist/cjs/getExtractPluginOptions.cjs +2 -2
  42. package/dist/cjs/getExtractPluginOptions.cjs.map +1 -1
  43. package/dist/cjs/getOptimizePluginOptions.cjs +2 -3
  44. package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
  45. package/dist/cjs/getPurgePluginOptions.cjs +2 -3
  46. package/dist/cjs/getPurgePluginOptions.cjs.map +1 -1
  47. package/dist/cjs/index.cjs +3 -0
  48. package/dist/cjs/normalizedFilesList.cjs +30 -0
  49. package/dist/cjs/normalizedFilesList.cjs.map +1 -0
  50. package/dist/cjs/transformers.cjs +20 -2
  51. package/dist/cjs/transformers.cjs.map +1 -1
  52. package/dist/esm/babel-plugin-intlayer-extract.mjs +3 -2
  53. package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
  54. package/dist/esm/babel-plugin-intlayer-field-rename.mjs +159 -100
  55. package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
  56. package/dist/esm/babel-plugin-intlayer-minify.mjs +12 -29
  57. package/dist/esm/babel-plugin-intlayer-minify.mjs.map +1 -1
  58. package/dist/esm/babel-plugin-intlayer-optimize.mjs +140 -9
  59. package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
  60. package/dist/esm/babel-plugin-intlayer-purge.mjs +40 -97
  61. package/dist/esm/babel-plugin-intlayer-purge.mjs.map +1 -1
  62. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs +151 -52
  63. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
  64. package/dist/esm/babelParser.mjs +60 -0
  65. package/dist/esm/babelParser.mjs.map +1 -0
  66. package/dist/esm/extractContent/babelProcessor.mjs +144 -71
  67. package/dist/esm/extractContent/babelProcessor.mjs.map +1 -1
  68. package/dist/esm/extractContent/contentWriter.mjs +6 -10
  69. package/dist/esm/extractContent/contentWriter.mjs.map +1 -1
  70. package/dist/esm/extractContent/extractContent.mjs +1 -1
  71. package/dist/esm/extractContent/extractContent.mjs.map +1 -1
  72. package/dist/esm/extractContent/processTsxFile.mjs +3 -6
  73. package/dist/esm/extractContent/processTsxFile.mjs.map +1 -1
  74. package/dist/esm/extractContent/utils/constants.mjs +2 -2
  75. package/dist/esm/extractContent/utils/constants.mjs.map +1 -1
  76. package/dist/esm/extractContent/utils/detectPackageName.mjs.map +1 -1
  77. package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs +1 -1
  78. package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs.map +1 -1
  79. package/dist/esm/extractContent/utils/extractDictionaryKey.mjs +1 -1
  80. package/dist/esm/extractContent/utils/extractDictionaryKey.mjs.map +1 -1
  81. package/dist/esm/extractContent/utils/generateKey.mjs.map +1 -1
  82. package/dist/esm/extractContent/utils/getComponentName.mjs.map +1 -1
  83. package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs.map +1 -1
  84. package/dist/esm/extractContent/utils/getOrGenerateKey.mjs.map +1 -1
  85. package/dist/esm/extractContent/utils/resolveDictionaryKey.mjs.map +1 -1
  86. package/dist/esm/extractContent/utils/shouldExtract.mjs +2 -0
  87. package/dist/esm/extractContent/utils/shouldExtract.mjs.map +1 -1
  88. package/dist/esm/extractScriptBlocks.mjs.map +1 -1
  89. package/dist/esm/getExtractPluginOptions.mjs +1 -1
  90. package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
  91. package/dist/esm/getOptimizePluginOptions.mjs +1 -1
  92. package/dist/esm/getOptimizePluginOptions.mjs.map +1 -1
  93. package/dist/esm/getPurgePluginOptions.mjs +1 -1
  94. package/dist/esm/getPurgePluginOptions.mjs.map +1 -1
  95. package/dist/esm/index.mjs +3 -3
  96. package/dist/esm/normalizedFilesList.mjs +29 -0
  97. package/dist/esm/normalizedFilesList.mjs.map +1 -0
  98. package/dist/esm/transformers.mjs +20 -2
  99. package/dist/esm/transformers.mjs.map +1 -1
  100. package/dist/types/babel-plugin-intlayer-extract.d.ts +2 -3
  101. package/dist/types/babel-plugin-intlayer-extract.d.ts.map +1 -1
  102. package/dist/types/babel-plugin-intlayer-field-rename.d.ts +29 -11
  103. package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
  104. package/dist/types/babel-plugin-intlayer-minify.d.ts +2 -3
  105. package/dist/types/babel-plugin-intlayer-minify.d.ts.map +1 -1
  106. package/dist/types/babel-plugin-intlayer-optimize.d.ts +34 -11
  107. package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
  108. package/dist/types/babel-plugin-intlayer-purge.d.ts +2 -3
  109. package/dist/types/babel-plugin-intlayer-purge.d.ts.map +1 -1
  110. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts +35 -113
  111. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
  112. package/dist/types/babelParser.d.ts +12 -0
  113. package/dist/types/babelParser.d.ts.map +1 -0
  114. package/dist/types/extractContent/babelProcessor.d.ts +5 -2
  115. package/dist/types/extractContent/babelProcessor.d.ts.map +1 -1
  116. package/dist/types/extractContent/contentWriter.d.ts +0 -1
  117. package/dist/types/extractContent/contentWriter.d.ts.map +1 -1
  118. package/dist/types/extractContent/extractContent.d.ts +1 -1
  119. package/dist/types/extractContent/extractContent.d.ts.map +1 -1
  120. package/dist/types/extractContent/index.d.ts +1 -1
  121. package/dist/types/extractContent/processTsxFile.d.ts +1 -1
  122. package/dist/types/extractContent/processTsxFile.d.ts.map +1 -1
  123. package/dist/types/extractContent/utils/constants.d.ts +3 -3
  124. package/dist/types/extractContent/utils/constants.d.ts.map +1 -1
  125. package/dist/types/extractContent/utils/detectPackageName.d.ts +0 -1
  126. package/dist/types/extractContent/utils/detectPackageName.d.ts.map +1 -1
  127. package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts +0 -1
  128. package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts.map +1 -1
  129. package/dist/types/extractContent/utils/extractDictionaryKey.d.ts.map +1 -1
  130. package/dist/types/extractContent/utils/generateKey.d.ts.map +1 -1
  131. package/dist/types/extractContent/utils/getComponentName.d.ts +0 -1
  132. package/dist/types/extractContent/utils/getComponentName.d.ts.map +1 -1
  133. package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts +8 -5
  134. package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts.map +1 -1
  135. package/dist/types/extractContent/utils/getOrGenerateKey.d.ts.map +1 -1
  136. package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts +0 -1
  137. package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts.map +1 -1
  138. package/dist/types/extractContent/utils/shouldExtract.d.ts +1 -0
  139. package/dist/types/extractContent/utils/shouldExtract.d.ts.map +1 -1
  140. package/dist/types/extractScriptBlocks.d.ts.map +1 -1
  141. package/dist/types/getExtractPluginOptions.d.ts +0 -1
  142. package/dist/types/getExtractPluginOptions.d.ts.map +1 -1
  143. package/dist/types/getOptimizePluginOptions.d.ts +0 -1
  144. package/dist/types/getOptimizePluginOptions.d.ts.map +1 -1
  145. package/dist/types/getPurgePluginOptions.d.ts +0 -1
  146. package/dist/types/getPurgePluginOptions.d.ts.map +1 -1
  147. package/dist/types/index.d.ts +6 -5
  148. package/dist/types/normalizedFilesList.d.ts +12 -0
  149. package/dist/types/normalizedFilesList.d.ts.map +1 -0
  150. package/dist/types/transformers.d.ts +7 -2
  151. package/dist/types/transformers.d.ts.map +1 -1
  152. package/package.json +31 -23
@@ -5,7 +5,7 @@ const createPruneContext = () => ({
5
5
  hasUnparsableSourceFiles: false,
6
6
  dictionaryKeysWithUntrackedBindings: /* @__PURE__ */ new Map(),
7
7
  dictionaryKeyToFieldRenameMap: /* @__PURE__ */ new Map(),
8
- dictionaryKeysWithOpaqueTopLevelFields: /* @__PURE__ */ new Map(),
8
+ dictionaryKeysWithOpaqueFields: /* @__PURE__ */ new Map(),
9
9
  dictionariesSkippingFieldRename: /* @__PURE__ */ new Set(),
10
10
  pendingFrameworkAnalysis: /* @__PURE__ */ new Map()
11
11
  });
@@ -35,8 +35,11 @@ const recordFieldUsage = (pruneContext, dictionaryKey, fieldUsage) => {
35
35
  pruneContext.dictionaryKeyToFieldUsageMap.set(dictionaryKey, "all");
36
36
  return;
37
37
  }
38
- const mergedFieldSet = existingUsage instanceof Set ? new Set([...existingUsage, ...fieldUsage]) : new Set(fieldUsage);
39
- pruneContext.dictionaryKeyToFieldUsageMap.set(dictionaryKey, mergedFieldSet);
38
+ if (existingUsage instanceof Set) {
39
+ for (const fieldName of fieldUsage) existingUsage.add(fieldName);
40
+ return;
41
+ }
42
+ pruneContext.dictionaryKeyToFieldUsageMap.set(dictionaryKey, new Set(fieldUsage));
40
43
  };
41
44
  /**
42
45
  * Analyses how the result of a single `useIntlayer('key')` / `getIntlayer('key')`
@@ -57,14 +60,18 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
57
60
  if (!existingPaths.includes(currentSourceFilePath)) pruneContext.dictionaryKeysWithUntrackedBindings.set(dictionaryKey, [...existingPaths, currentSourceFilePath]);
58
61
  recordFieldUsage(pruneContext, dictionaryKey, "all");
59
62
  };
60
- /** Record that a field value is consumed opaquely (not further destructured). */
61
- const markOpaqueField = (fieldName, line) => {
62
- const fieldToLocations = pruneContext.dictionaryKeysWithOpaqueTopLevelFields.get(dictionaryKey) ?? /* @__PURE__ */ new Map();
63
+ /** Record that the content value at `fieldPath` is consumed opaquely. */
64
+ const markOpaqueField = (fieldPath, line) => {
65
+ const pathToOccurrence = pruneContext.dictionaryKeysWithOpaqueFields.get(dictionaryKey) ?? /* @__PURE__ */ new Map();
63
66
  const location = line !== void 0 ? `${currentSourceFilePath}:${line}` : currentSourceFilePath;
64
- const locations = fieldToLocations.get(fieldName) ?? [];
65
- if (!locations.includes(location)) locations.push(location);
66
- fieldToLocations.set(fieldName, locations);
67
- pruneContext.dictionaryKeysWithOpaqueTopLevelFields.set(dictionaryKey, fieldToLocations);
67
+ const joinedFieldPath = fieldPath.join(".");
68
+ const occurrence = pathToOccurrence.get(joinedFieldPath) ?? {
69
+ fieldPath: [...fieldPath],
70
+ locations: []
71
+ };
72
+ if (!occurrence.locations.includes(location)) occurrence.locations.push(location);
73
+ pathToOccurrence.set(joinedFieldPath, occurrence);
74
+ pruneContext.dictionaryKeysWithOpaqueFields.set(dictionaryKey, pathToOccurrence);
68
75
  };
69
76
  /** Register a plain variable binding in an SFC file for a second-pass analysis. */
70
77
  const deferFrameworkAnalysis = (variableName) => {
@@ -76,37 +83,101 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
76
83
  pruneContext.pendingFrameworkAnalysis.set(currentSourceFilePath, existing);
77
84
  };
78
85
  /**
79
- * Analyses usage of a variable or member access to detect opaque
80
- * consumption (passing a dictionary field as-is to a prop or function).
86
+ * Analyses how the content value at `fieldPath` (currently referenced by
87
+ * `refPath`) is consumed, to detect opaque consumption (passing a dictionary
88
+ * value as-is to a prop or function argument).
81
89
  *
82
- * If a direct, non-chained consumption is found, it calls `markOpaqueField`.
83
- * Chained accesses (e.g. `field.sub`) are NOT considered opaque for `field`
84
- * because the renamer can safely track and update them.
90
+ * Member-access chains and destructuring are followed recursively with an
91
+ * extended field path, so the *terminal* consumption of a chain like
92
+ * `content.sections.hero` decides opacity — mirroring how far the
93
+ * source-code renamer can rewrite accesses. When the terminal consumption
94
+ * escapes static tracking, the deepest reached field path is marked opaque
95
+ * so the children of that value keep their original key names.
85
96
  */
86
- const analyzeOpaqueUsage = (refPath, fieldName) => {
97
+ const analyzeOpaqueUsage = (refPath, fieldPath) => {
87
98
  const parentNode = refPath.parent;
88
- if ((babelTypes.isMemberExpression(parentNode) || babelTypes.isOptionalMemberExpression(parentNode)) && parentNode.object === refPath.node) return;
89
- if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isObjectPattern(parentNode.id) && parentNode.init === refPath.node) return;
99
+ const parentPath = refPath.parentPath;
100
+ if (parentPath && (babelTypes.isMemberExpression(parentNode) || babelTypes.isOptionalMemberExpression(parentNode)) && parentNode.object === refPath.node) {
101
+ const memberNode = parentNode;
102
+ if (memberNode.computed && babelTypes.isNumericLiteral(memberNode.property)) {
103
+ analyzeOpaqueUsage(parentPath, fieldPath);
104
+ return;
105
+ }
106
+ if (!memberNode.computed && babelTypes.isIdentifier(memberNode.property)) {
107
+ analyzeOpaqueUsage(parentPath, [...fieldPath, memberNode.property.name]);
108
+ return;
109
+ }
110
+ if (memberNode.computed && babelTypes.isStringLiteral(memberNode.property)) {
111
+ analyzeOpaqueUsage(parentPath, [...fieldPath, memberNode.property.value]);
112
+ return;
113
+ }
114
+ markOpaqueField(fieldPath, refPath.node.loc?.start.line);
115
+ return;
116
+ }
117
+ if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isObjectPattern(parentNode.id) && parentNode.init === refPath.node) {
118
+ analyzeOpaqueDestructuring(parentNode.id, refPath, fieldPath);
119
+ return;
120
+ }
90
121
  if (babelTypes.isArrayExpression(parentNode)) return;
91
- markOpaqueField(fieldName, refPath.node.loc?.start.line);
122
+ markOpaqueField(fieldPath, refPath.node.loc?.start.line);
123
+ };
124
+ /**
125
+ * Analyses a destructuring pattern applied to the content value at
126
+ * `fieldPath`, recursively following each bound local variable's references
127
+ * via {@link analyzeOpaqueUsage}.
128
+ *
129
+ * Patterns the source-code renamer cannot rewrite (rest elements, dynamic
130
+ * computed keys, array patterns) mark the corresponding path opaque.
131
+ */
132
+ const analyzeOpaqueDestructuring = (objectPattern, scopePath, fieldPath) => {
133
+ for (const property of objectPattern.properties) {
134
+ if (babelTypes.isRestElement(property)) {
135
+ markOpaqueField(fieldPath, property.loc?.start.line);
136
+ continue;
137
+ }
138
+ if (!babelTypes.isObjectProperty(property)) continue;
139
+ if (property.computed && !babelTypes.isStringLiteral(property.key)) {
140
+ markOpaqueField(fieldPath, property.loc?.start.line);
141
+ continue;
142
+ }
143
+ const keyName = babelTypes.isIdentifier(property.key) ? property.key.name : babelTypes.isStringLiteral(property.key) ? property.key.value : null;
144
+ if (!keyName) continue;
145
+ const childFieldPath = [...fieldPath, keyName];
146
+ const bindingTarget = babelTypes.isAssignmentPattern(property.value) ? property.value.left : property.value;
147
+ if (babelTypes.isObjectPattern(bindingTarget)) {
148
+ analyzeOpaqueDestructuring(bindingTarget, scopePath, childFieldPath);
149
+ continue;
150
+ }
151
+ if (babelTypes.isIdentifier(bindingTarget)) {
152
+ const localVarBinding = scopePath.scope.getBinding(bindingTarget.name);
153
+ if (!localVarBinding) continue;
154
+ for (const referencePath of localVarBinding.referencePaths) analyzeOpaqueUsage(referencePath, childFieldPath);
155
+ continue;
156
+ }
157
+ markOpaqueField(childFieldPath, property.loc?.start.line);
158
+ }
92
159
  };
93
160
  /**
94
161
  * Helper to collect field names from an ObjectPattern (destructuring).
95
- * Returns true if successful, false if a rest element was found (meaning 'all').
162
+ * Returns true if successful, false when the accessed fields cannot be
163
+ * determined statically (rest element or dynamic computed key → 'all').
96
164
  */
97
165
  const collectFieldsFromObjectPattern = (pattern, initPath, targetSet) => {
98
166
  if (pattern.properties.some((prop) => babelTypes.isRestElement(prop))) return false;
99
167
  for (const property of pattern.properties) {
168
+ if (!babelTypes.isObjectProperty(property)) continue;
169
+ if (property.computed && !babelTypes.isStringLiteral(property.key)) return false;
100
170
  let fieldName;
101
- if (babelTypes.isObjectProperty(property) && babelTypes.isIdentifier(property.key)) fieldName = property.key.name;
102
- else if (babelTypes.isObjectProperty(property) && babelTypes.isStringLiteral(property.key)) fieldName = property.key.value;
103
- if (fieldName) {
104
- targetSet.add(fieldName);
105
- if (babelTypes.isObjectProperty(property) && babelTypes.isIdentifier(property.value)) {
106
- const variableBinding = initPath.scope.getBinding(property.value.name);
107
- if (variableBinding) for (const refPath of variableBinding.referencePaths) analyzeOpaqueUsage(refPath, fieldName);
108
- }
109
- }
171
+ if (!property.computed && babelTypes.isIdentifier(property.key)) fieldName = property.key.name;
172
+ else if (babelTypes.isStringLiteral(property.key)) fieldName = property.key.value;
173
+ if (!fieldName) continue;
174
+ targetSet.add(fieldName);
175
+ const bindingTarget = babelTypes.isAssignmentPattern(property.value) ? property.value.left : property.value;
176
+ if (babelTypes.isIdentifier(bindingTarget)) {
177
+ const variableBinding = initPath.scope.getBinding(bindingTarget.name);
178
+ if (variableBinding) for (const refPath of variableBinding.referencePaths) analyzeOpaqueUsage(refPath, [fieldName]);
179
+ } else if (babelTypes.isObjectPattern(bindingTarget)) analyzeOpaqueDestructuring(bindingTarget, initPath, [fieldName]);
180
+ else markOpaqueField([fieldName], property.loc?.start.line);
110
181
  }
111
182
  return true;
112
183
  };
@@ -121,9 +192,9 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
121
192
  if (!parentNode.computed && babelTypes.isIdentifier(parentNode.property)) fieldName = parentNode.property.name;
122
193
  else if (parentNode.computed && babelTypes.isStringLiteral(parentNode.property)) fieldName = parentNode.property.value;
123
194
  if (fieldName) {
124
- recordFieldUsage(pruneContext, dictionaryKey, new Set([fieldName]));
195
+ recordFieldUsage(pruneContext, dictionaryKey, /* @__PURE__ */ new Set([fieldName]));
125
196
  const memberExprPath = callExpressionPath.parentPath;
126
- if (memberExprPath) analyzeOpaqueUsage(memberExprPath, fieldName);
197
+ if (memberExprPath) analyzeOpaqueUsage(memberExprPath, [fieldName]);
127
198
  } else markUntrackedBinding();
128
199
  return;
129
200
  }
@@ -146,7 +217,7 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
146
217
  if (fieldName) {
147
218
  accessedTopLevelFieldNames.add(fieldName);
148
219
  const memberExprPath = variableReferencePath.parentPath;
149
- if (memberExprPath) analyzeOpaqueUsage(memberExprPath, fieldName);
220
+ if (memberExprPath) analyzeOpaqueUsage(memberExprPath, [fieldName]);
150
221
  } else {
151
222
  hasUntrackedReferenceAccess = true;
152
223
  break;
@@ -165,7 +236,7 @@ const analyzeCallExpressionUsage = (babelTypes, pruneContext, callExpressionPath
165
236
  if (fieldName) {
166
237
  accessedTopLevelFieldNames.add(fieldName);
167
238
  const memberExprPath = callExprPath?.parentPath;
168
- if (memberExprPath) analyzeOpaqueUsage(memberExprPath, fieldName);
239
+ if (memberExprPath) analyzeOpaqueUsage(memberExprPath, [fieldName]);
169
240
  } else {
170
241
  hasUntrackedReferenceAccess = true;
171
242
  break;
@@ -250,9 +321,9 @@ const readJsxAttributeString = (babelTypes, openingElement, attributeName) => {
250
321
  };
251
322
  /**
252
323
  * Resolves the namespace (dictionary key) for a compat caller call-site from
253
- * its `CompatNamespaceSource` configuration. Returns the static key, or
254
- * `'__default__'` when the configured argument is absent (caller falls back to
255
- * its default namespace), or `undefined` when the value is present but dynamic.
324
+ * one `CallerValueSource`. Returns the static key, or `'__default__'` when the
325
+ * configured argument is absent (caller falls back to its default namespace),
326
+ * or `undefined` when the value is present but dynamic.
256
327
  */
257
328
  const resolveCompatNamespace = (babelTypes, callArguments, source) => {
258
329
  if (source.from === "fixed") return source.value;
@@ -283,13 +354,28 @@ const resolveCompatNamespace = (babelTypes, callArguments, source) => {
283
354
  return readObjectProperty(babelTypes, optionsArgument, source.property);
284
355
  };
285
356
  /**
357
+ * Resolves the namespace from a list of `CallerValueSource`s, tried in
358
+ * declaration order. The first source yielding a static string wins.
359
+ * Returns `'__default__'` when every source reports an absent value, and
360
+ * `undefined` when the namespace is present somewhere but dynamic.
361
+ */
362
+ const resolveNamespaceFromSources = (babelTypes, callArguments, sources) => {
363
+ let sawAbsentValue = false;
364
+ for (const source of sources) {
365
+ const resolved = resolveCompatNamespace(babelTypes, callArguments, source);
366
+ if (typeof resolved === "string" && resolved !== "__default__") return resolved;
367
+ if (resolved === "__default__") sawAbsentValue = true;
368
+ }
369
+ return sawAbsentValue ? "__default__" : void 0;
370
+ };
371
+ /**
286
372
  * Resolves an optional `keyPrefix` for a compat caller. Returns the static
287
373
  * prefix string, `null` when no prefix is configured/present, or `undefined`
288
374
  * when a prefix is present but dynamic.
289
375
  */
290
- const resolveCompatKeyPrefix = (babelTypes, callArguments, source) => {
291
- if (!source) return null;
292
- const resolved = resolveCompatNamespace(babelTypes, callArguments, source);
376
+ const resolveCompatKeyPrefix = (babelTypes, callArguments, sources) => {
377
+ if (!sources || sources.length === 0) return null;
378
+ const resolved = resolveNamespaceFromSources(babelTypes, callArguments, sources);
293
379
  if (resolved === "__default__") return null;
294
380
  return resolved;
295
381
  };
@@ -315,8 +401,8 @@ const unwrapAwait = (babelTypes, path) => {
315
401
  * so renaming the compiled JSON keys would break runtime lookups. Pruning
316
402
  * (top-level field removal) remains safe because it preserves field names.
317
403
  */
318
- const analyzeNamespaceCallerUsage = (babelTypes, pruneContext, callArguments, callerConfig, isSfcFile, callExpressionPath) => {
319
- const resolvedNamespace = resolveCompatNamespace(babelTypes, callArguments, callerConfig.namespace);
404
+ const analyzeNamespaceCallerUsage = (babelTypes, pruneContext, callArguments, callerConfig, isSfcFile, currentSourceFilePath, callExpressionPath, namespaceOverride) => {
405
+ const resolvedNamespace = namespaceOverride ?? resolveNamespaceFromSources(babelTypes, callArguments, callerConfig.namespaceSources);
320
406
  if (resolvedNamespace === void 0) return;
321
407
  const namespaceString = resolvedNamespace === "__default__" ? DEFAULT_COMPAT_NAMESPACE : resolvedNamespace;
322
408
  const namespaceSegments = namespaceString.split(".");
@@ -331,13 +417,18 @@ const analyzeNamespaceCallerUsage = (babelTypes, pruneContext, callArguments, ca
331
417
  recordFieldUsage(pruneContext, dictionaryKey, "all");
332
418
  return;
333
419
  }
420
+ if (callerConfig.translationFunction === "content") {
421
+ if (callExpressionPath) analyzeCallExpressionUsage(babelTypes, pruneContext, callExpressionPath, dictionaryKey, currentSourceFilePath, isSfcFile);
422
+ else recordFieldUsage(pruneContext, dictionaryKey, "all");
423
+ return;
424
+ }
334
425
  if (callerConfig.translationFunction === "self") {
335
426
  const firstArg = callArguments[0];
336
427
  if (!firstArg) {
337
428
  recordFieldUsage(pruneContext, dictionaryKey, "all");
338
429
  return;
339
430
  }
340
- if (callerConfig.namespace.from === "path-first-segment") {
431
+ if (callerConfig.namespaceSources.some((source) => source.from === "path-first-segment")) {
341
432
  let fullId;
342
433
  const staticString = readStaticString(babelTypes, firstArg);
343
434
  if (staticString !== void 0) fullId = staticString;
@@ -347,22 +438,22 @@ const analyzeNamespaceCallerUsage = (babelTypes, pruneContext, callArguments, ca
347
438
  }
348
439
  if (fullId !== void 0) {
349
440
  const field = fullId.split(".")[1];
350
- if (field !== void 0) recordFieldUsage(pruneContext, dictionaryKey, new Set([field]));
441
+ if (field !== void 0) recordFieldUsage(pruneContext, dictionaryKey, /* @__PURE__ */ new Set([field]));
351
442
  else recordFieldUsage(pruneContext, dictionaryKey, "all");
352
443
  return;
353
444
  }
354
445
  recordFieldUsage(pruneContext, dictionaryKey, "all");
355
446
  return;
356
447
  }
357
- const segment = readStaticFirstSegment(babelTypes, firstArg);
448
+ const segment = callerConfig.flatKey ? readStaticString(babelTypes, firstArg) : readStaticFirstSegment(babelTypes, firstArg);
358
449
  if (segment !== void 0) {
359
- recordFieldUsage(pruneContext, dictionaryKey, new Set([segment]));
450
+ recordFieldUsage(pruneContext, dictionaryKey, /* @__PURE__ */ new Set([segment]));
360
451
  return;
361
452
  }
362
453
  if (babelTypes.isObjectExpression(firstArg)) {
363
454
  const idValue = readObjectProperty(babelTypes, firstArg, "id");
364
455
  if (idValue !== void 0 && idValue !== "__default__") {
365
- recordFieldUsage(pruneContext, dictionaryKey, new Set([firstPathSegment(idValue)]));
456
+ recordFieldUsage(pruneContext, dictionaryKey, /* @__PURE__ */ new Set([callerConfig.flatKey ? idValue : firstPathSegment(idValue)]));
366
457
  return;
367
458
  }
368
459
  }
@@ -373,14 +464,14 @@ const analyzeNamespaceCallerUsage = (babelTypes, pruneContext, callArguments, ca
373
464
  recordFieldUsage(pruneContext, dictionaryKey, "all");
374
465
  return;
375
466
  }
376
- const explicitKeyPrefix = resolveCompatKeyPrefix(babelTypes, callArguments, callerConfig.keyPrefix);
467
+ const explicitKeyPrefix = resolveCompatKeyPrefix(babelTypes, callArguments, callerConfig.keyPrefixSources);
377
468
  if (explicitKeyPrefix === void 0) {
378
469
  recordFieldUsage(pruneContext, dictionaryKey, "all");
379
470
  return;
380
471
  }
381
472
  const effectivePrefix = namespacePrefix ?? explicitKeyPrefix;
382
473
  if (effectivePrefix !== null) {
383
- recordFieldUsage(pruneContext, dictionaryKey, new Set([firstPathSegment(effectivePrefix)]));
474
+ recordFieldUsage(pruneContext, dictionaryKey, /* @__PURE__ */ new Set([firstPathSegment(effectivePrefix)]));
384
475
  return;
385
476
  }
386
477
  let translationBinding = null;
@@ -442,9 +533,10 @@ const makeUsageAnalyzerBabelPlugin = (pruneContext, options) => ({ types: babelT
442
533
  const isSfcFile = currentSourceFilePath.endsWith(".vue") || currentSourceFilePath.endsWith(".svelte") || currentSourceFilePath.endsWith(".astro");
443
534
  const intlayerCallerLocalNameMap = /* @__PURE__ */ new Map();
444
535
  const compatCallerLocalNameMap = /* @__PURE__ */ new Map();
445
- const methodCompatCallers = compatCallers.filter((caller) => caller.matchAsMethod);
536
+ const fileImportSources = /* @__PURE__ */ new Set();
446
537
  programPath.traverse({ ImportDeclaration: (importDeclarationPath) => {
447
538
  const importSource = importDeclarationPath.node.source.value;
539
+ fileImportSources.add(importSource);
448
540
  for (const importSpecifier of importDeclarationPath.node.specifiers) {
449
541
  if (!babelTypes.isImportSpecifier(importSpecifier)) continue;
450
542
  const importedName = babelTypes.isIdentifier(importSpecifier.imported) ? importSpecifier.imported.name : importSpecifier.imported.value;
@@ -456,6 +548,7 @@ const makeUsageAnalyzerBabelPlugin = (pruneContext, options) => ({ types: babelT
456
548
  if (compatCaller) compatCallerLocalNameMap.set(importSpecifier.local.name, compatCaller);
457
549
  }
458
550
  } });
551
+ const methodCompatCallers = compatCallers.filter((caller) => caller.matchAsMethod && (!caller.requiresImport || caller.importSources.some((source) => fileImportSources.has(source))));
459
552
  const hasNativeCallers = intlayerCallerLocalNameMap.size > 0;
460
553
  const hasCompatCallers = compatCallerLocalNameMap.size > 0 || methodCompatCallers.length > 0;
461
554
  if (!hasNativeCallers && !hasCompatCallers) return;
@@ -480,12 +573,12 @@ const makeUsageAnalyzerBabelPlugin = (pruneContext, options) => ({ types: babelT
480
573
  }
481
574
  const importedCompatCaller = compatCallerLocalNameMap.get(localCallerName);
482
575
  if (importedCompatCaller && !isMethodCall) {
483
- analyzeNamespaceCallerUsage(babelTypes, pruneContext, callExpressionPath.node.arguments, importedCompatCaller, isSfcFile, callExpressionPath);
576
+ analyzeNamespaceCallerUsage(babelTypes, pruneContext, callExpressionPath.node.arguments, importedCompatCaller, isSfcFile, currentSourceFilePath, callExpressionPath);
484
577
  return;
485
578
  }
486
579
  if (isMethodCall) {
487
580
  const methodCaller = methodCompatCallers.find((caller) => caller.callerName === localCallerName);
488
- if (methodCaller) analyzeNamespaceCallerUsage(babelTypes, pruneContext, callExpressionPath.node.arguments, methodCaller, isSfcFile, callExpressionPath);
581
+ if (methodCaller) analyzeNamespaceCallerUsage(babelTypes, pruneContext, callExpressionPath.node.arguments, methodCaller, isSfcFile, currentSourceFilePath, callExpressionPath);
489
582
  }
490
583
  },
491
584
  JSXOpeningElement: (jsxOpeningElementPath) => {
@@ -494,7 +587,13 @@ const makeUsageAnalyzerBabelPlugin = (pruneContext, options) => ({ types: babelT
494
587
  const jsxCaller = compatCallerLocalNameMap.get(nameNode.name);
495
588
  if (!jsxCaller?.jsxIdAttribute) return;
496
589
  const idNode = readJsxAttributeString(babelTypes, jsxOpeningElementPath.node, jsxCaller.jsxIdAttribute);
497
- analyzeNamespaceCallerUsage(babelTypes, pruneContext, idNode ? [idNode] : [], jsxCaller, isSfcFile);
590
+ let namespaceOverride;
591
+ if (jsxCaller.jsxNamespaceAttribute) {
592
+ const namespaceNode = readJsxAttributeString(babelTypes, jsxOpeningElementPath.node, jsxCaller.jsxNamespaceAttribute);
593
+ if (!namespaceNode) return;
594
+ namespaceOverride = namespaceNode.value;
595
+ }
596
+ analyzeNamespaceCallerUsage(babelTypes, pruneContext, idNode ? [idNode] : [], jsxCaller, isSfcFile, currentSourceFilePath, void 0, namespaceOverride);
498
597
  }
499
598
  });
500
599
  } } }