@intlayer/babel 9.4.4 → 9.5.1

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 (93) hide show
  1. package/README.md +0 -2
  2. package/dist/cjs/analyzeContentUsage.cjs +301 -0
  3. package/dist/cjs/analyzeContentUsage.cjs.map +1 -0
  4. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +5 -4
  5. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
  6. package/dist/cjs/babel-plugin-intlayer-optimize.cjs +171 -282
  7. package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
  8. package/dist/cjs/babel-plugin-intlayer-purge.cjs +4 -3
  9. package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -1
  10. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs +49 -699
  11. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
  12. package/dist/cjs/compat/namespaceResolution.cjs +124 -0
  13. package/dist/cjs/compat/namespaceResolution.cjs.map +1 -0
  14. package/dist/cjs/compat/optimizePass.cjs +144 -0
  15. package/dist/cjs/compat/optimizePass.cjs.map +1 -0
  16. package/dist/cjs/compat/usageAnalysis.cjs +195 -0
  17. package/dist/cjs/compat/usageAnalysis.cjs.map +1 -0
  18. package/dist/cjs/dictionaryImports.cjs +40 -0
  19. package/dist/cjs/dictionaryImports.cjs.map +1 -0
  20. package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs +1 -1
  21. package/dist/cjs/getExtractPluginOptions.cjs +1 -1
  22. package/dist/cjs/getOptimizePluginOptions.cjs +2 -6
  23. package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
  24. package/dist/cjs/getPurgePluginOptions.cjs +1 -1
  25. package/dist/cjs/index.cjs +9 -5
  26. package/dist/cjs/nativeCallers.cjs +41 -0
  27. package/dist/cjs/nativeCallers.cjs.map +1 -0
  28. package/dist/cjs/pruneContext.cjs +79 -0
  29. package/dist/cjs/pruneContext.cjs.map +1 -0
  30. package/dist/cjs/staticAstReaders.cjs +140 -0
  31. package/dist/cjs/staticAstReaders.cjs.map +1 -0
  32. package/dist/cjs/transformers.cjs +2 -1
  33. package/dist/cjs/transformers.cjs.map +1 -1
  34. package/dist/esm/analyzeContentUsage.mjs +300 -0
  35. package/dist/esm/analyzeContentUsage.mjs.map +1 -0
  36. package/dist/esm/babel-plugin-intlayer-field-rename.mjs +3 -2
  37. package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
  38. package/dist/esm/babel-plugin-intlayer-optimize.mjs +171 -282
  39. package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
  40. package/dist/esm/babel-plugin-intlayer-purge.mjs +3 -2
  41. package/dist/esm/babel-plugin-intlayer-purge.mjs.map +1 -1
  42. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs +43 -694
  43. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
  44. package/dist/esm/compat/namespaceResolution.mjs +120 -0
  45. package/dist/esm/compat/namespaceResolution.mjs.map +1 -0
  46. package/dist/esm/compat/optimizePass.mjs +143 -0
  47. package/dist/esm/compat/optimizePass.mjs.map +1 -0
  48. package/dist/esm/compat/usageAnalysis.mjs +193 -0
  49. package/dist/esm/compat/usageAnalysis.mjs.map +1 -0
  50. package/dist/esm/dictionaryImports.mjs +38 -0
  51. package/dist/esm/dictionaryImports.mjs.map +1 -0
  52. package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs +1 -1
  53. package/dist/esm/getExtractPluginOptions.mjs +1 -1
  54. package/dist/esm/getOptimizePluginOptions.mjs +2 -6
  55. package/dist/esm/getOptimizePluginOptions.mjs.map +1 -1
  56. package/dist/esm/getPurgePluginOptions.mjs +1 -1
  57. package/dist/esm/index.mjs +5 -2
  58. package/dist/esm/nativeCallers.mjs +38 -0
  59. package/dist/esm/nativeCallers.mjs.map +1 -0
  60. package/dist/esm/pruneContext.mjs +76 -0
  61. package/dist/esm/pruneContext.mjs.map +1 -0
  62. package/dist/esm/staticAstReaders.mjs +129 -0
  63. package/dist/esm/staticAstReaders.mjs.map +1 -0
  64. package/dist/esm/transformers.mjs +2 -1
  65. package/dist/esm/transformers.mjs.map +1 -1
  66. package/dist/types/analyzeContentUsage.d.ts +18 -0
  67. package/dist/types/analyzeContentUsage.d.ts.map +1 -0
  68. package/dist/types/babel-plugin-intlayer-field-rename.d.ts +2 -1
  69. package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
  70. package/dist/types/babel-plugin-intlayer-optimize.d.ts +9 -15
  71. package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
  72. package/dist/types/babel-plugin-intlayer-purge.d.ts +3 -2
  73. package/dist/types/babel-plugin-intlayer-purge.d.ts.map +1 -1
  74. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts +20 -187
  75. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
  76. package/dist/types/compat/namespaceResolution.d.ts +66 -0
  77. package/dist/types/compat/namespaceResolution.d.ts.map +1 -0
  78. package/dist/types/compat/optimizePass.d.ts +58 -0
  79. package/dist/types/compat/optimizePass.d.ts.map +1 -0
  80. package/dist/types/compat/usageAnalysis.d.ts +75 -0
  81. package/dist/types/compat/usageAnalysis.d.ts.map +1 -0
  82. package/dist/types/dictionaryImports.d.ts +46 -0
  83. package/dist/types/dictionaryImports.d.ts.map +1 -0
  84. package/dist/types/index.d.ts +5 -2
  85. package/dist/types/nativeCallers.d.ts +33 -0
  86. package/dist/types/nativeCallers.d.ts.map +1 -0
  87. package/dist/types/pruneContext.d.ts +152 -0
  88. package/dist/types/pruneContext.d.ts.map +1 -0
  89. package/dist/types/staticAstReaders.d.ts +84 -0
  90. package/dist/types/staticAstReaders.d.ts.map +1 -0
  91. package/dist/types/transformers.d.ts +2 -1
  92. package/dist/types/transformers.d.ts.map +1 -1
  93. package/package.json +10 -10
@@ -1,8 +1,9 @@
1
+ import { readStaticString } from "./staticAstReaders.mjs";
2
+ import { createDictionaryImportRegistry } from "./dictionaryImports.mjs";
1
3
  import { getNormalizedFilesListSet } from "./normalizedFilesList.mjs";
4
+ import { createCompatOptimizePass } from "./compat/optimizePass.mjs";
2
5
  import { dirname, join, relative } from "node:path";
3
- import { getPathHash } from "@intlayer/engine/utils";
4
6
  import { normalizePath } from "@intlayer/config/utils";
5
- import { getRewritableCallers } from "@intlayer/config/callers";
6
7
 
7
8
  //#region src/babel-plugin-intlayer-optimize.ts
8
9
  const PACKAGE_LIST = [
@@ -28,10 +29,10 @@ const CALLER_LIST = [
28
29
  "getIntlayer",
29
30
  "getIntlayerAsync"
30
31
  ];
31
- /**
32
- * Packages that support dynamic import
33
- */
34
- const PACKAGE_LIST_DYNAMIC = [
32
+ /** Membership sets for the tables above — hit once per import and per call. */
33
+ const NATIVE_PACKAGE_SET = new Set(PACKAGE_LIST);
34
+ const CALLER_NAME_SET = new Set(CALLER_LIST);
35
+ const DYNAMIC_PACKAGE_SET = /* @__PURE__ */ new Set([
35
36
  "react-intlayer",
36
37
  "react-intlayer/client",
37
38
  "react-intlayer/server",
@@ -45,7 +46,7 @@ const PACKAGE_LIST_DYNAMIC = [
45
46
  "angular-intlayer",
46
47
  "lit-intlayer",
47
48
  "vanilla-intlayer"
48
- ];
49
+ ]);
49
50
  const STATIC_IMPORT_FUNCTION = {
50
51
  getIntlayer: "getDictionary",
51
52
  getIntlayerAsync: "getDictionaryAsync",
@@ -66,15 +67,6 @@ const DYNAMIC_HELPER_MAP = {
66
67
  */
67
68
  const SSR_STATIC_IMPORT_SOURCE = { "solid-intlayer": "solid-intlayer/server" };
68
69
  /**
69
- * Replicates the xxHash64 → Base-62 algorithm used by the SWC version
70
- * and prefixes an underscore so the generated identifiers never collide
71
- * with user-defined ones.
72
- */
73
- const makeIdent = (key, t) => {
74
- const hash = getPathHash(key);
75
- return t.identifier(`_${hash}`);
76
- };
77
- /**
78
70
  * Builds the module specifier pointing at `targetPath` from `fromFile`, with
79
71
  * forward slashes and an explicit `./` prefix so bundlers never treat it as a
80
72
  * bare package specifier.
@@ -96,66 +88,26 @@ const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchD
96
88
  if (importMode === "dynamic") dictionaryPath = join(dynamicDictionariesDir, `${key}.mjs`);
97
89
  return toRelativeSpecifier(fromFile, dictionaryPath);
98
90
  };
99
- const getKeyFromArgument = (arg, t) => {
100
- if (arg && t.isStringLiteral(arg)) return arg.value;
101
- if (arg && t.isTemplateLiteral(arg) && arg.expressions.length === 0 && arg.quasis.length === 1) return arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;
102
- };
103
- const isCallerName = (name) => CALLER_LIST.includes(name);
91
+ const isCallerName = (name) => CALLER_NAME_SET.has(name);
92
+ const isDynamicPackage = (packageName) => DYNAMIC_PACKAGE_SET.has(packageName);
93
+ /** The name an import specifier brings in, whether written as an identifier or a string. */
94
+ const importedSpecifierName = (babelTypes, specifier) => babelTypes.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value;
95
+ const EMPTY_KEY_SET = /* @__PURE__ */ new Set();
104
96
  /**
105
- * Splits a namespace string at the first `.` to separate the dictionary key
106
- * from an optional key prefix for nested namespaces, mirroring the SWC
107
- * plugin's `split_namespace`.
108
- *
109
- * `'about'` → `{ dictionaryKey: 'about', keyPrefix: '' }`
110
- * `'about.counter'` → `{ dictionaryKey: 'about', keyPrefix: 'counter' }`
97
+ * `nestingDictionaryKeys` as a set, cached by array reference: Babel reuses one
98
+ * options object for the whole build, so the set is built once instead of once
99
+ * per transformed file.
111
100
  */
112
- const splitNamespace = (namespace) => {
113
- const dotPosition = namespace.indexOf(".");
114
- if (dotPosition === -1) return {
115
- dictionaryKey: namespace,
116
- keyPrefix: ""
117
- };
118
- return {
119
- dictionaryKey: namespace.slice(0, dotPosition),
120
- keyPrefix: namespace.slice(dotPosition + 1)
121
- };
122
- };
123
- /**
124
- * Statically resolves the namespace of a compat caller call-site from its
125
- * descriptor's `namespaceSources` (argument / option / fixed — the
126
- * per-message-id `path-first-segment` form cannot bind one dictionary to the
127
- * call site and is skipped). Returns `undefined` when the namespace is absent
128
- * or dynamic, in which case the call is left untouched and resolves through
129
- * the runtime dictionary registry.
130
- */
131
- const resolveCompatNamespaceMatch = (t, callArguments, descriptor) => {
132
- for (const source of descriptor.namespaceSources) {
133
- if (source.from === "fixed") return { fullNamespace: source.value };
134
- if (source.from === "argument") {
135
- const namespace = getKeyFromArgument(callArguments[source.index], t);
136
- if (namespace !== void 0) return {
137
- fullNamespace: namespace,
138
- argumentIndex: source.index
139
- };
140
- continue;
141
- }
142
- if (source.from === "option") {
143
- const optionsArgument = callArguments[source.argumentIndex];
144
- if (!optionsArgument || !t.isObjectExpression(optionsArgument)) continue;
145
- for (const property of optionsArgument.properties) {
146
- if (!t.isObjectProperty(property)) continue;
147
- if (!(t.isIdentifier(property.key) && property.key.name === source.property || t.isStringLiteral(property.key) && property.key.value === source.property)) continue;
148
- const namespace = getKeyFromArgument(property.value, t);
149
- if (namespace !== void 0) return {
150
- fullNamespace: namespace,
151
- optionProperty: property,
152
- optionsObject: optionsArgument
153
- };
154
- }
155
- }
101
+ const nestingKeysCache = /* @__PURE__ */ new WeakMap();
102
+ const getNestingDictionaryKeySet = (nestingDictionaryKeys) => {
103
+ if (!nestingDictionaryKeys) return EMPTY_KEY_SET;
104
+ let keySet = nestingKeysCache.get(nestingDictionaryKeys);
105
+ if (!keySet) {
106
+ keySet = new Set(nestingDictionaryKeys);
107
+ nestingKeysCache.set(nestingDictionaryKeys, keySet);
156
108
  }
109
+ return keySet;
157
110
  };
158
- const isDynamicPackage = (packageName) => PACKAGE_LIST_DYNAMIC.includes(packageName);
159
111
  /**
160
112
  * Decides, once per package import, which helper family applies to this file.
161
113
  * The import rewrite and the per-call rewrite must both derive from this
@@ -171,6 +123,29 @@ const resolveHelperPlan = (packageName, importMode, isServer, packageHasDynamicC
171
123
  return "static";
172
124
  };
173
125
  /**
126
+ * Builds the dictionary import declarations the rewrite accumulated for one
127
+ * file — the compiled JSON (or its `nest()` companion) for static reads, and
128
+ * the generated per-locale loader for dynamic and fetch ones.
129
+ */
130
+ const buildDictionaryImportDeclarations = (babelTypes, state, imports) => {
131
+ const { dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, nestingDictionaryKeys } = state.opts;
132
+ const fromFile = state.file.opts.filename;
133
+ const nestingKeys = getNestingDictionaryKeySet(nestingDictionaryKeys);
134
+ const importDeclarations = [];
135
+ for (const [key, ident] of imports.staticImports) {
136
+ const hasNestedDictionaries = nestingKeys.has(key);
137
+ const specifier = computeImport(fromFile, dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, key, "static", hasNestedDictionaries);
138
+ const importDeclaration = babelTypes.importDeclaration([babelTypes.importDefaultSpecifier(babelTypes.identifier(ident.name))], babelTypes.stringLiteral(specifier));
139
+ if (!hasNestedDictionaries) importDeclaration.attributes = [babelTypes.importAttribute(babelTypes.identifier("type"), babelTypes.stringLiteral("json"))];
140
+ importDeclarations.push(importDeclaration);
141
+ }
142
+ for (const [key, ident] of imports.dynamicImports) {
143
+ const mode = ident.name.endsWith("_fetch") ? "fetch" : "dynamic";
144
+ importDeclarations.push(babelTypes.importDeclaration([babelTypes.importDefaultSpecifier(babelTypes.identifier(ident.name))], babelTypes.stringLiteral(computeImport(fromFile, dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, key, mode))));
145
+ }
146
+ return importDeclarations;
147
+ };
148
+ /**
174
149
  * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.
175
150
  *
176
151
  * This plugin transforms calls to `useIntlayer()`, `getIntlayer()` and
@@ -271,13 +246,7 @@ const intlayerOptimizeBabelPlugin = (babel) => {
271
246
  return {
272
247
  name: "babel-plugin-intlayer-transform",
273
248
  pre() {
274
- this._newStaticImports = /* @__PURE__ */ new Map();
275
- this._newDynamicImports = /* @__PURE__ */ new Map();
276
- this._callerMap = /* @__PURE__ */ new Map();
277
- this._callerPackageMap = /* @__PURE__ */ new Map();
278
- this._compatCallerMap = /* @__PURE__ */ new Map();
279
249
  this._isIncluded = true;
280
- this._hasValidImport = false;
281
250
  this._isDictEntry = false;
282
251
  if (this.opts.optimize === false) {
283
252
  this._isIncluded = false;
@@ -295,16 +264,9 @@ const intlayerOptimizeBabelPlugin = (babel) => {
295
264
  enter(programPath, state) {
296
265
  const filename = state.file.opts.filename ? normalizePath(state.file.opts.filename) : void 0;
297
266
  const dictionariesEntryPath = state.opts.dictionariesEntryPath ? normalizePath(state.opts.dictionariesEntryPath) : void 0;
298
- if (state.opts.replaceDictionaryEntry && filename === dictionariesEntryPath) {
267
+ if (state.opts.replaceDictionaryEntry && filename && filename === dictionariesEntryPath) {
299
268
  state._isDictEntry = true;
300
- programPath.traverse({
301
- ImportDeclaration(path) {
302
- path.remove();
303
- },
304
- VariableDeclarator(path) {
305
- if (t.isObjectExpression(path.node.init)) path.node.init.properties = [];
306
- }
307
- });
269
+ programPath.node.body = [t.exportDefaultDeclaration(t.objectExpression([])), t.exportNamedDeclaration(t.variableDeclaration("const", [t.variableDeclarator(t.identifier("getDictionaries"), t.arrowFunctionExpression([], t.objectExpression([])))]))];
308
270
  }
309
271
  },
310
272
  /**
@@ -318,215 +280,142 @@ const intlayerOptimizeBabelPlugin = (babel) => {
318
280
  exit(programPath, state) {
319
281
  if (state._isDictEntry) return;
320
282
  if (!state._isIncluded) return;
321
- const rewritableCompatCallers = getRewritableCallers(state.opts.compatCallers ?? []);
322
- programPath.traverse({ ImportDeclaration(path) {
323
- const src = path.node.source.value;
324
- const isNativePackage = PACKAGE_LIST.includes(src);
325
- const compatCallersForSource = rewritableCompatCallers.filter((descriptor) => descriptor.importSources.includes(src));
326
- if (!isNativePackage && compatCallersForSource.length === 0) return;
327
- state._hasValidImport = true;
328
- for (const spec of path.node.specifiers) {
283
+ const imports = createDictionaryImportRegistry(t);
284
+ const compat = createCompatOptimizePass(t, state.opts.compatCallers ?? [], imports, {
285
+ importMode: state.opts.importMode,
286
+ dictionaryModeMap: state.opts.dictionaryModeMap
287
+ });
288
+ const programBody = programPath.node.body;
289
+ const nativeImportNodes = [];
290
+ const compatImportNodes = [];
291
+ /** Local alias → the native caller it was imported as. */
292
+ const callerMap = /* @__PURE__ */ new Map();
293
+ /** Local alias → the intlayer package it was imported from. */
294
+ const callerPackageMap = /* @__PURE__ */ new Map();
295
+ /** Whether the file imported any native or compat caller at all. */
296
+ let hasValidImport = false;
297
+ for (const statement of programBody) {
298
+ if (!t.isImportDeclaration(statement)) continue;
299
+ const src = statement.source.value;
300
+ const isNativePackage = NATIVE_PACKAGE_SET.has(src);
301
+ const isCompatPackage = compat?.ownsImportSource(src) ?? false;
302
+ if (!isNativePackage && !isCompatPackage) continue;
303
+ hasValidImport = true;
304
+ if (isNativePackage) nativeImportNodes.push(statement);
305
+ if (isCompatPackage) compatImportNodes.push(statement);
306
+ for (const spec of statement.specifiers) {
329
307
  if (!t.isImportSpecifier(spec)) continue;
330
- const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
308
+ const importedName = importedSpecifierName(t, spec);
331
309
  if (isNativePackage && isCallerName(importedName)) {
332
- state._callerMap?.set(spec.local.name, importedName);
333
- state._callerPackageMap?.set(spec.local.name, src);
310
+ callerMap.set(spec.local.name, importedName);
311
+ callerPackageMap.set(spec.local.name, src);
334
312
  }
335
- const compatDescriptor = compatCallersForSource.find((descriptor) => descriptor.callerName === importedName);
336
- if (compatDescriptor) state._compatCallerMap?.set(spec.local.name, compatDescriptor);
313
+ if (isCompatPackage) compat?.noteImport(src, importedName, spec.local.name);
337
314
  }
315
+ }
316
+ const nativeCallNodes = [];
317
+ const compatCallNodes = [];
318
+ if (callerMap.size > 0 || compat?.hasCallers()) programPath.traverse({ CallExpression(path) {
319
+ const callee = path.node.callee;
320
+ if (!t.isIdentifier(callee)) return;
321
+ if (callerMap.has(callee.name)) nativeCallNodes.push(path.node);
322
+ else if (compat?.ownsLocalName(callee.name)) compatCallNodes.push(path.node);
338
323
  } });
339
324
  const packagesWithDynamicCall = /* @__PURE__ */ new Set();
340
325
  const packagesWithFetchCall = /* @__PURE__ */ new Set();
341
- let compatHasDynamicCall = false;
342
- const unresolvableCompatLocalNames = /* @__PURE__ */ new Set();
343
- programPath.traverse({ CallExpression(path) {
344
- const callee = path.node.callee;
345
- if (!t.isIdentifier(callee)) return;
346
- const compatDescriptor = state._compatCallerMap?.get(callee.name);
347
- if (compatDescriptor) {
348
- const namespaceMatch = resolveCompatNamespaceMatch(t, path.node.arguments, compatDescriptor);
349
- if (!namespaceMatch) {
350
- unresolvableCompatLocalNames.add(callee.name);
351
- return;
326
+ for (const callNode of nativeCallNodes) {
327
+ const callee = callNode.callee;
328
+ if (callerMap.get(callee.name) !== "useIntlayer") continue;
329
+ const callerPackage = callerPackageMap.get(callee.name);
330
+ if (!callerPackage) continue;
331
+ const key = readStaticString(t, callNode.arguments[0]);
332
+ if (!key) continue;
333
+ const overrideMode = state.opts.dictionaryModeMap?.[key];
334
+ if (overrideMode === "dynamic") packagesWithDynamicCall.add(callerPackage);
335
+ else if (overrideMode === "fetch") packagesWithFetchCall.add(callerPackage);
336
+ }
337
+ compat?.analyzeCalls(compatCallNodes);
338
+ const helperPlanCache = /* @__PURE__ */ new Map();
339
+ const getHelperPlan = (packageName) => {
340
+ let plan = helperPlanCache.get(packageName);
341
+ if (plan === void 0) {
342
+ plan = resolveHelperPlan(packageName, state.opts.importMode, state.opts.isServer, packagesWithDynamicCall.has(packageName), packagesWithFetchCall.has(packageName));
343
+ helperPlanCache.set(packageName, plan);
344
+ }
345
+ return plan;
346
+ };
347
+ const serverImportsByAnchor = /* @__PURE__ */ new Map();
348
+ const emptiedImportNodes = /* @__PURE__ */ new Set();
349
+ for (const importNode of compatImportNodes) compat?.rewriteImportSpecifiers(importNode);
350
+ for (const importNode of nativeImportNodes) {
351
+ const helperPlan = getHelperPlan(importNode.source.value);
352
+ const serverSource = helperPlan === "ssrStatic" ? SSR_STATIC_IMPORT_SOURCE[importNode.source.value] : void 0;
353
+ const helperMap = helperPlan === "dynamic" ? DYNAMIC_HELPER_MAP : STATIC_IMPORT_FUNCTION;
354
+ const serverSpecifiers = [];
355
+ for (const spec of importNode.specifiers) {
356
+ if (!t.isImportSpecifier(spec)) continue;
357
+ const importedName = importedSpecifierName(t, spec);
358
+ if (!isCallerName(importedName)) continue;
359
+ if (serverSource && importedName === "useIntlayer") {
360
+ spec.imported = t.identifier("useDictionary");
361
+ serverSpecifiers.push(spec);
362
+ continue;
352
363
  }
353
- const { dictionaryKey } = splitNamespace(namespaceMatch.fullNamespace);
354
- const compatOverrideMode = state.opts.dictionaryModeMap?.[dictionaryKey];
355
- if (compatOverrideMode === "dynamic" || compatOverrideMode === "fetch") compatHasDynamicCall = true;
356
- return;
364
+ const newIdentifier = helperMap[importedName];
365
+ if (newIdentifier) spec.imported = t.identifier(newIdentifier);
357
366
  }
358
- if (state._callerMap?.get(callee.name) !== "useIntlayer") return;
359
- const callerPackage = state._callerPackageMap?.get(callee.name);
360
- if (!callerPackage) return;
361
- const key = getKeyFromArgument(path.node.arguments[0], t);
362
- if (!key) return;
367
+ if (serverSpecifiers.length > 0 && serverSource) {
368
+ serverImportsByAnchor.set(importNode, t.importDeclaration(serverSpecifiers, t.stringLiteral(serverSource)));
369
+ const serverSpecifierSet = new Set(serverSpecifiers);
370
+ importNode.specifiers = importNode.specifiers.filter((spec) => !serverSpecifierSet.has(spec));
371
+ if (importNode.specifiers.length === 0) emptiedImportNodes.add(importNode);
372
+ }
373
+ }
374
+ for (const callNode of compatCallNodes) compat?.rewriteCall(callNode);
375
+ for (const callNode of nativeCallNodes) {
376
+ const callee = callNode.callee;
377
+ const originalImportedName = callerMap.get(callee.name);
378
+ const key = readStaticString(t, callNode.arguments[0]);
379
+ if (!key) continue;
380
+ const callerPackage = callerPackageMap.get(callee.name);
381
+ const importMode = state.opts.importMode;
382
+ const isUseIntlayer = originalImportedName === "useIntlayer";
383
+ const isGetIntlayerAsync = originalImportedName === "getIntlayerAsync";
363
384
  const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
364
- if (dictionaryOverrideMode === "dynamic") packagesWithDynamicCall.add(callerPackage);
365
- else if (dictionaryOverrideMode === "fetch") packagesWithFetchCall.add(callerPackage);
366
- } });
367
- for (const localName of unresolvableCompatLocalNames) state._compatCallerMap?.delete(localName);
368
- const getHelperPlan = (packageName) => resolveHelperPlan(packageName, state.opts.importMode, state.opts.isServer, packagesWithDynamicCall.has(packageName), packagesWithFetchCall.has(packageName));
369
- const compatUseDynamicHelpers = state.opts.importMode === "dynamic" || state.opts.importMode === "fetch" || compatHasDynamicCall;
370
- programPath.traverse({
371
- ImportDeclaration(path) {
372
- const src = path.node.source.value;
373
- for (const spec of path.node.specifiers) {
374
- if (!t.isImportSpecifier(spec)) continue;
375
- const compatDescriptor = state._compatCallerMap?.get(spec.local.name);
376
- if (!compatDescriptor) continue;
377
- if (!compatDescriptor.importSources.includes(src)) continue;
378
- spec.imported = t.identifier(compatUseDynamicHelpers ? compatDescriptor.dynamicReplacement : compatDescriptor.staticReplacement);
379
- }
380
- if (!PACKAGE_LIST.includes(src)) return;
381
- const helperPlan = getHelperPlan(src);
382
- const serverSource = helperPlan === "ssrStatic" ? SSR_STATIC_IMPORT_SOURCE[src] : void 0;
383
- const helperMap = helperPlan === "dynamic" ? DYNAMIC_HELPER_MAP : STATIC_IMPORT_FUNCTION;
384
- const serverSpecifiers = [];
385
- for (const spec of path.node.specifiers) {
386
- if (!t.isImportSpecifier(spec)) continue;
387
- const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
388
- if (!isCallerName(importedName)) continue;
389
- if (serverSource && importedName === "useIntlayer") {
390
- spec.imported = t.identifier("useDictionary");
391
- serverSpecifiers.push(spec);
392
- continue;
393
- }
394
- const newIdentifier = helperMap[importedName];
395
- if (newIdentifier) spec.imported = t.identifier(newIdentifier);
396
- }
397
- if (serverSpecifiers.length > 0 && serverSource) {
398
- path.insertAfter(t.importDeclaration(serverSpecifiers, t.stringLiteral(serverSource)));
399
- path.node.specifiers = path.node.specifiers.filter((spec) => !serverSpecifiers.includes(spec));
400
- if (path.node.specifiers.length === 0) path.remove();
401
- }
402
- },
403
- CallExpression(path) {
404
- const callee = path.node.callee;
405
- if (!t.isIdentifier(callee)) return;
406
- const compatDescriptor = state._compatCallerMap?.get(callee.name);
407
- if (compatDescriptor) {
408
- const callArguments = path.node.arguments;
409
- const namespaceMatch = resolveCompatNamespaceMatch(t, callArguments, compatDescriptor);
410
- if (!namespaceMatch) return;
411
- state._hasValidImport = true;
412
- const { dictionaryKey, keyPrefix } = splitNamespace(namespaceMatch.fullNamespace);
413
- const compatOverrideMode = state.opts.dictionaryModeMap?.[dictionaryKey];
414
- let compatCallMode = "static";
415
- if (compatUseDynamicHelpers) {
416
- if (compatOverrideMode === "dynamic" || compatOverrideMode === "fetch") compatCallMode = compatOverrideMode;
417
- else if (state.opts.importMode === "dynamic" || state.opts.importMode === "fetch") compatCallMode = state.opts.importMode;
418
- else compatCallMode = "dynamic";
419
- }
420
- let dictionaryIdent;
421
- if (compatCallMode === "static") {
422
- let staticIdent = state._newStaticImports?.get(dictionaryKey);
423
- if (!staticIdent) {
424
- staticIdent = makeIdent(dictionaryKey, t);
425
- state._newStaticImports?.set(dictionaryKey, staticIdent);
426
- }
427
- dictionaryIdent = staticIdent;
428
- } else {
429
- let dynamicIdent = state._newDynamicImports?.get(dictionaryKey);
430
- if (!dynamicIdent) {
431
- const hash = getPathHash(dictionaryKey);
432
- const suffix = compatCallMode === "fetch" ? "fetch" : "dyn";
433
- dynamicIdent = t.identifier(`_${hash}_${suffix}`);
434
- state._newDynamicImports?.set(dictionaryKey, dynamicIdent);
435
- }
436
- dictionaryIdent = dynamicIdent;
437
- }
438
- if (namespaceMatch.argumentIndex !== void 0) {
439
- callArguments[namespaceMatch.argumentIndex] = t.identifier(dictionaryIdent.name);
440
- const insertAt = namespaceMatch.argumentIndex + 1;
441
- const insertedArguments = [];
442
- if (compatCallMode !== "static") insertedArguments.push(t.stringLiteral(dictionaryKey));
443
- if (keyPrefix) insertedArguments.push(t.stringLiteral(keyPrefix));
444
- callArguments.splice(insertAt, 0, ...insertedArguments);
445
- } else if (compatCallMode !== "static") callArguments.unshift(t.identifier(dictionaryIdent.name), t.stringLiteral(dictionaryKey));
446
- else callArguments.unshift(t.identifier(dictionaryIdent.name));
447
- if (namespaceMatch.optionProperty && namespaceMatch.optionsObject) {
448
- if (keyPrefix) namespaceMatch.optionProperty.value = t.stringLiteral(keyPrefix);
449
- else namespaceMatch.optionsObject.properties = namespaceMatch.optionsObject.properties.filter((property) => property !== namespaceMatch.optionProperty);
450
- }
451
- return;
452
- }
453
- const originalImportedName = state._callerMap?.get(callee.name);
454
- if (!originalImportedName) return;
455
- state._hasValidImport = true;
456
- const key = getKeyFromArgument(path.node.arguments[0], t);
457
- if (!key) return;
458
- const callerPackage = state._callerPackageMap?.get(callee.name);
459
- const importMode = state.opts.importMode;
460
- const isUseIntlayer = originalImportedName === "useIntlayer";
461
- const isGetIntlayerAsync = originalImportedName === "getIntlayerAsync";
462
- const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
463
- const helperPlan = callerPackage === void 0 ? "static" : getHelperPlan(callerPackage);
464
- let perCallMode = "static";
465
- if (isGetIntlayerAsync) perCallMode = dictionaryOverrideMode === "fetch" ? "fetch" : "dynamic";
466
- else if (isUseIntlayer && helperPlan === "dynamic") {
467
- if (dictionaryOverrideMode) perCallMode = dictionaryOverrideMode;
468
- else if (importMode === "dynamic" || importMode === "fetch") perCallMode = importMode;
469
- } else if (isUseIntlayer && helperPlan === "static") {
470
- if (dictionaryOverrideMode === "dynamic" || dictionaryOverrideMode === "fetch") perCallMode = dictionaryOverrideMode;
471
- }
472
- let ident;
473
- if (perCallMode === "fetch") {
474
- let dynamicIdent = state._newDynamicImports?.get(key);
475
- if (!dynamicIdent) {
476
- const hash = getPathHash(key);
477
- dynamicIdent = t.identifier(`_${hash}_fetch`);
478
- state._newDynamicImports?.set(key, dynamicIdent);
479
- }
480
- ident = dynamicIdent;
481
- path.node.arguments = [t.identifier(ident.name), ...path.node.arguments];
482
- } else if (perCallMode === "dynamic") {
483
- let dynamicIdent = state._newDynamicImports?.get(key);
484
- if (!dynamicIdent) {
485
- const hash = getPathHash(key);
486
- dynamicIdent = t.identifier(`_${hash}_dyn`);
487
- state._newDynamicImports?.set(key, dynamicIdent);
488
- }
489
- ident = dynamicIdent;
490
- path.node.arguments = [t.identifier(ident.name), ...path.node.arguments];
491
- } else {
492
- let staticIdent = state._newStaticImports?.get(key);
493
- if (!staticIdent) {
494
- staticIdent = makeIdent(key, t);
495
- state._newStaticImports?.set(key, staticIdent);
496
- }
497
- ident = staticIdent;
498
- path.node.arguments[0] = t.identifier(ident.name);
499
- }
385
+ const helperPlan = callerPackage === void 0 ? "static" : getHelperPlan(callerPackage);
386
+ let perCallMode = "static";
387
+ if (isGetIntlayerAsync) perCallMode = dictionaryOverrideMode === "fetch" ? "fetch" : "dynamic";
388
+ else if (isUseIntlayer && helperPlan === "dynamic") {
389
+ if (dictionaryOverrideMode) perCallMode = dictionaryOverrideMode;
390
+ else if (importMode === "dynamic" || importMode === "fetch") perCallMode = importMode;
391
+ } else if (isUseIntlayer && helperPlan === "static") {
392
+ if (dictionaryOverrideMode === "dynamic" || dictionaryOverrideMode === "fetch") perCallMode = dictionaryOverrideMode;
500
393
  }
501
- });
502
- if (!state._hasValidImport) return;
503
- const file = state.file.opts.filename;
504
- const dictionariesDir = state.opts.dictionariesDir;
505
- const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;
506
- const fetchDictionariesDir = state.opts.fetchDictionariesDir;
507
- const imports = [];
508
- const nestingDictionaryKeys = new Set(state.opts.nestingDictionaryKeys ?? []);
509
- for (const [key, ident] of state._newStaticImports) {
510
- const hasNestedDictionaries = nestingDictionaryKeys.has(key);
511
- const rel = computeImport(file, dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, key, "static", hasNestedDictionaries);
512
- const importDeclarationNode = t.importDeclaration([t.importDefaultSpecifier(t.identifier(ident.name))], t.stringLiteral(rel));
513
- if (!hasNestedDictionaries) importDeclarationNode.attributes = [t.importAttribute(t.identifier("type"), t.stringLiteral("json"))];
514
- imports.push(importDeclarationNode);
394
+ const ident = imports.identFor(key, perCallMode);
395
+ if (perCallMode === "static") callNode.arguments[0] = t.identifier(ident.name);
396
+ else callNode.arguments = [t.identifier(ident.name), ...callNode.arguments];
515
397
  }
516
- for (const [key, ident] of state._newDynamicImports) {
517
- const modeForThisIdent = ident.name.endsWith("_fetch") ? "fetch" : "dynamic";
518
- const rel = computeImport(file, dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, key, modeForThisIdent);
519
- imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(ident.name))], t.stringLiteral(rel)));
398
+ const dictionaryImports = hasValidImport ? buildDictionaryImportDeclarations(t, state, imports) : [];
399
+ const hasImportMoves = serverImportsByAnchor.size > 0 || emptiedImportNodes.size > 0;
400
+ if (dictionaryImports.length === 0 && !hasImportMoves) return;
401
+ const nextBody = [];
402
+ for (const statement of programBody) {
403
+ if (t.isImportDeclaration(statement) && emptiedImportNodes.has(statement)) {
404
+ const serverImport = serverImportsByAnchor.get(statement);
405
+ if (serverImport) nextBody.push(serverImport);
406
+ continue;
407
+ }
408
+ nextBody.push(statement);
409
+ if (t.isImportDeclaration(statement)) {
410
+ const serverImport = serverImportsByAnchor.get(statement);
411
+ if (serverImport) nextBody.push(serverImport);
412
+ }
520
413
  }
521
- if (!imports.length) return;
522
- const bodyPaths = programPath.get("body");
523
414
  let insertPos = 0;
524
- for (const stmtPath of bodyPaths) {
525
- const stmt = stmtPath.node;
526
- if (t.isExpressionStatement(stmt) && t.isStringLiteral(stmt.expression) && !stmt.expression.value.startsWith("import") && !stmt.expression.value.startsWith("require")) insertPos += 1;
527
- else break;
528
- }
529
- programPath.node.body.splice(insertPos, 0, ...imports);
415
+ for (const statement of nextBody) if (t.isExpressionStatement(statement) && t.isStringLiteral(statement.expression) && !statement.expression.value.startsWith("import") && !statement.expression.value.startsWith("require")) insertPos += 1;
416
+ else break;
417
+ nextBody.splice(insertPos, 0, ...dictionaryImports);
418
+ programPath.node.body = nextBody;
530
419
  }
531
420
  } }
532
421
  };