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