@intlayer/babel 9.0.0-canary.8 → 9.0.0

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