@intlayer/babel 8.12.3 → 8.12.4-canary.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.
- package/dist/cjs/babel-plugin-intlayer-extract.cjs +2 -1
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs +57 -24
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs +2 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +57 -24
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/types/babel-plugin-intlayer-extract.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts +10 -5
- package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -6,6 +6,7 @@ let node_path = require("node:path");
|
|
|
6
6
|
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
7
7
|
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
8
8
|
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
9
|
+
let _intlayer_config_utils = require("@intlayer/config/utils");
|
|
9
10
|
let _babel_parser = require("@babel/parser");
|
|
10
11
|
|
|
11
12
|
//#region src/babel-plugin-intlayer-extract.ts
|
|
@@ -34,7 +35,7 @@ const intlayerExtractBabelPlugin = (_babel) => {
|
|
|
34
35
|
if (opts.enabled === false) return;
|
|
35
36
|
const filename = state.file.opts.filename;
|
|
36
37
|
if (!filename) return;
|
|
37
|
-
if (opts.filesList && !opts.filesList.includes(filename)) return;
|
|
38
|
+
if (opts.filesList && !opts.filesList.map(_intlayer_config_utils.normalizePath).includes((0, _intlayer_config_utils.normalizePath)(filename))) return;
|
|
38
39
|
const fileCode = state.file.code ?? "";
|
|
39
40
|
if (!fileCode) return;
|
|
40
41
|
const appLogger = (0, _intlayer_config_logger.getAppLogger)(opts.configuration);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["detectPackageName","extractContentSync","ANSIColors"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport type { PluginObj, PluginPass } from '@babel/core';\nimport { parse } from '@babel/parser';\nimport type * as BabelTypes from '@babel/types';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport { extractContentSync } from './extractContent/extractContent';\nimport type { PackageName } from './extractContent/utils/constants';\nimport { detectPackageName } from './extractContent/utils/detectPackageName';\n\nexport type ExtractResult = {\n dictionaryKey: string;\n filePath: string;\n content: Record<string, string>;\n locale: Locale;\n};\n\nexport type ExtractPluginOptions = {\n packageName?: PackageName;\n filesList: string[];\n enabled: boolean;\n\n shouldExtract?: (text: string) => boolean;\n configuration: IntlayerConfig;\n /**\n * Callback invoked for each extracted dictionary key/content pair.\n * Used by `getExtractPluginOptions` to write dictionaries to disk.\n * May be async — the plugin will fire-and-forget (Babel transforms are sync).\n */\n onExtract?: (result: ExtractResult) => void | Promise<void>;\n /**\n * Defines the output files path.\n */\n output?: FilePathPattern;\n};\n\ntype State = PluginPass & { opts: ExtractPluginOptions };\n\n/**\n * Babel plugin that extracts translatable content from source files and\n * injects Intlayer hooks (`useIntlayer` / `getIntlayer`) automatically.\n *\n * Designed for use with Babel-based build tools such as Next.js and Webpack.\n *\n * @example babel.config.js\n * ```js\n * const { intlayerExtractBabelPlugin, getExtractPluginOptions } = require('@intlayer/babel');\n * module.exports = {\n * presets: ['next/babel'],\n * plugins: [\n * [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const intlayerExtractBabelPlugin = (_babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n return {\n name: 'babel-plugin-intlayer-extract',\n\n visitor: {\n Program: {\n enter(programPath, state) {\n const opts = state.opts;\n\n // Merge plugin options with the unified compiler config\n const isEnabled = opts.enabled;\n\n if (isEnabled === false) return;\n\n const filename = state.file.opts.filename;\n\n if (!filename) return;\n\n if (opts.filesList
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["normalizePath","detectPackageName","extractContentSync","ANSIColors"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport type { PluginObj, PluginPass } from '@babel/core';\nimport { parse } from '@babel/parser';\nimport type * as BabelTypes from '@babel/types';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport { normalizePath } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport { extractContentSync } from './extractContent/extractContent';\nimport type { PackageName } from './extractContent/utils/constants';\nimport { detectPackageName } from './extractContent/utils/detectPackageName';\n\nexport type ExtractResult = {\n dictionaryKey: string;\n filePath: string;\n content: Record<string, string>;\n locale: Locale;\n};\n\nexport type ExtractPluginOptions = {\n packageName?: PackageName;\n filesList: string[];\n enabled: boolean;\n\n shouldExtract?: (text: string) => boolean;\n configuration: IntlayerConfig;\n /**\n * Callback invoked for each extracted dictionary key/content pair.\n * Used by `getExtractPluginOptions` to write dictionaries to disk.\n * May be async — the plugin will fire-and-forget (Babel transforms are sync).\n */\n onExtract?: (result: ExtractResult) => void | Promise<void>;\n /**\n * Defines the output files path.\n */\n output?: FilePathPattern;\n};\n\ntype State = PluginPass & { opts: ExtractPluginOptions };\n\n/**\n * Babel plugin that extracts translatable content from source files and\n * injects Intlayer hooks (`useIntlayer` / `getIntlayer`) automatically.\n *\n * Designed for use with Babel-based build tools such as Next.js and Webpack.\n *\n * @example babel.config.js\n * ```js\n * const { intlayerExtractBabelPlugin, getExtractPluginOptions } = require('@intlayer/babel');\n * module.exports = {\n * presets: ['next/babel'],\n * plugins: [\n * [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const intlayerExtractBabelPlugin = (_babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n return {\n name: 'babel-plugin-intlayer-extract',\n\n visitor: {\n Program: {\n enter(programPath, state) {\n const opts = state.opts;\n\n // Merge plugin options with the unified compiler config\n const isEnabled = opts.enabled;\n\n if (isEnabled === false) return;\n\n const filename = state.file.opts.filename;\n\n if (!filename) return;\n\n // Compare as POSIX paths (babel filenames use OS separators on Windows).\n if (\n opts.filesList &&\n !opts.filesList.map(normalizePath).includes(normalizePath(filename))\n ) {\n return;\n }\n\n const fileCode: string = state.file.code ?? '';\n if (!fileCode) return;\n\n const appLogger = getAppLogger(opts.configuration);\n const packageName = opts.packageName ?? detectPackageName(filename);\n\n const { saveComponents } = opts.configuration.compiler;\n\n const result = extractContentSync(filename, packageName, {\n configuration: opts.configuration,\n code: fileCode,\n onExtract: (extractResult: {\n key: string;\n content: Record<string, string>;\n }) => {\n if (opts.onExtract) {\n opts.onExtract({\n dictionaryKey: extractResult.key,\n filePath: filename,\n content: extractResult.content,\n locale: opts.configuration.internationalization.defaultLocale,\n });\n }\n },\n declarationOnly: !saveComponents,\n });\n\n if (!result) return;\n\n const { transformedCode: modifiedCode } = result;\n\n if (!modifiedCode) return;\n\n // Replace the Babel AST with the transformed code by re-parsing it.\n // This lets Babel serialise the injected hooks/imports through its\n // own code generator, preserving compatibility with other plugins.\n try {\n const newAst = parse(modifiedCode, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n programPath.node.body = newAst.program.body;\n programPath.node.directives = newAst.program.directives;\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Extracted content from ${colorizePath(relative(opts.configuration.system.baseDir, filename))}`,\n { level: 'debug' }\n );\n } catch (error) {\n appLogger(\n [\n `Failed to parse transformed code for ${colorizePath(relative(opts.configuration.system.baseDir, filename))}:`,\n error,\n ],\n { level: 'error' }\n );\n }\n },\n },\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,MAAa,8BAA8B,WAEnB;AACtB,QAAO;EACL,MAAM;EAEN,SAAS,EACP,SAAS,EACP,MAAM,aAAa,OAAO;GACxB,MAAM,OAAO,MAAM;AAKnB,OAFkB,KAAK,YAEL,MAAO;GAEzB,MAAM,WAAW,MAAM,KAAK,KAAK;AAEjC,OAAI,CAAC,SAAU;AAGf,OACE,KAAK,aACL,CAAC,KAAK,UAAU,IAAIA,qCAAc,CAAC,mDAAuB,SAAS,CAAC,CAEpE;GAGF,MAAM,WAAmB,MAAM,KAAK,QAAQ;AAC5C,OAAI,CAAC,SAAU;GAEf,MAAM,sDAAyB,KAAK,cAAc;GAClD,MAAM,cAAc,KAAK,eAAeC,iEAAkB,SAAS;GAEnE,MAAM,EAAE,mBAAmB,KAAK,cAAc;GAE9C,MAAM,SAASC,yDAAmB,UAAU,aAAa;IACvD,eAAe,KAAK;IACpB,MAAM;IACN,YAAY,kBAGN;AACJ,SAAI,KAAK,UACP,MAAK,UAAU;MACb,eAAe,cAAc;MAC7B,UAAU;MACV,SAAS,cAAc;MACvB,QAAQ,KAAK,cAAc,qBAAqB;MACjD,CAAC;;IAGN,iBAAiB,CAAC;IACnB,CAAC;AAEF,OAAI,CAAC,OAAQ;GAEb,MAAM,EAAE,iBAAiB,iBAAiB;AAE1C,OAAI,CAAC,aAAc;AAKnB,OAAI;IACF,MAAM,kCAAe,cAAc;KACjC,YAAY;KACZ,SAAS,CAAC,OAAO,aAAa;KAC/B,CAAC;AAEF,gBAAY,KAAK,OAAO,OAAO,QAAQ;AACvC,gBAAY,KAAK,aAAa,OAAO,QAAQ;AAE7C,cACE,yCAAY,aAAaC,wBAAW,UAAU,CAAC,4FAAgD,KAAK,cAAc,OAAO,SAAS,SAAS,CAAC,IAC5I,EAAE,OAAO,SAAS,CACnB;YACM,OAAO;AACd,cACE,CACE,0GAA8D,KAAK,cAAc,OAAO,SAAS,SAAS,CAAC,CAAC,IAC5G,MACD,EACD,EAAE,OAAO,SAAS,CACnB;;KAGN,EACF;EACF"}
|
|
@@ -47,6 +47,13 @@ const STATIC_IMPORT_FUNCTION = {
|
|
|
47
47
|
};
|
|
48
48
|
const DYNAMIC_IMPORT_FUNCTION = { useIntlayer: "useDictionaryDynamic" };
|
|
49
49
|
/**
|
|
50
|
+
* Packages whose SSR dynamic helper should render synchronously with a static
|
|
51
|
+
* dictionary. Solid streaming SSR can hydrate static output reliably, while
|
|
52
|
+
* its dynamic resource path either suspends during hydration or serializes the
|
|
53
|
+
* full dictionary into HTML.
|
|
54
|
+
*/
|
|
55
|
+
const PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK = new Set(["solid-intlayer"]);
|
|
56
|
+
/**
|
|
50
57
|
* Replicates the xxHash64 → Base-62 algorithm used by the SWC version
|
|
51
58
|
* and prefixes an underscore so the generated identifiers never collide
|
|
52
59
|
* with user-defined ones.
|
|
@@ -64,6 +71,13 @@ const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchD
|
|
|
64
71
|
if (!rel.startsWith("./") && !rel.startsWith("../")) rel = `./${rel}`;
|
|
65
72
|
return rel;
|
|
66
73
|
};
|
|
74
|
+
const getKeyFromArgument = (arg, t) => {
|
|
75
|
+
if (arg && t.isStringLiteral(arg)) return arg.value;
|
|
76
|
+
if (arg && t.isTemplateLiteral(arg) && arg.expressions.length === 0 && arg.quasis.length === 1) return arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;
|
|
77
|
+
};
|
|
78
|
+
const isCallerName = (name) => CALLER_LIST.includes(name);
|
|
79
|
+
const isDynamicPackage = (packageName) => PACKAGE_LIST_DYNAMIC.includes(packageName);
|
|
80
|
+
const shouldUseStaticSsrDynamicFallback = (callerPackage, importMode, opts) => opts.isServer === true && importMode === "dynamic" && callerPackage !== void 0 && PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK.has(callerPackage);
|
|
67
81
|
/**
|
|
68
82
|
* Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.
|
|
69
83
|
*
|
|
@@ -119,11 +133,11 @@ const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchD
|
|
|
119
133
|
* const content2 = getIntlayer(_dicHash);
|
|
120
134
|
* ```
|
|
121
135
|
*
|
|
122
|
-
* ###
|
|
136
|
+
* ### Fetch Mode (`importMode = "fetch"`)
|
|
123
137
|
*
|
|
124
|
-
* Uses
|
|
138
|
+
* Uses fetch-based dictionary loading for remote dictionaries:
|
|
125
139
|
*
|
|
126
|
-
* **Output if `dictionaryModeMap` includes the key with "
|
|
140
|
+
* **Output if `dictionaryModeMap` includes the key with "fetch" value:**
|
|
127
141
|
* ```ts
|
|
128
142
|
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
129
143
|
* import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';
|
|
@@ -134,7 +148,7 @@ const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchD
|
|
|
134
148
|
* const content2 = getIntlayer(_dicHash);
|
|
135
149
|
* ```
|
|
136
150
|
*
|
|
137
|
-
* > If `dictionaryModeMap` does not include the key with "
|
|
151
|
+
* > If `dictionaryModeMap` does not include the key with "fetch" value, the plugin will fallback to the dynamic import mode.
|
|
138
152
|
*
|
|
139
153
|
* ```ts
|
|
140
154
|
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
@@ -154,6 +168,7 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
154
168
|
this._newStaticImports = /* @__PURE__ */ new Map();
|
|
155
169
|
this._newDynamicImports = /* @__PURE__ */ new Map();
|
|
156
170
|
this._callerMap = /* @__PURE__ */ new Map();
|
|
171
|
+
this._callerPackageMap = /* @__PURE__ */ new Map();
|
|
157
172
|
this._isIncluded = true;
|
|
158
173
|
this._hasValidImport = false;
|
|
159
174
|
this._isDictEntry = false;
|
|
@@ -162,9 +177,9 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
162
177
|
this._isIncluded = false;
|
|
163
178
|
return;
|
|
164
179
|
}
|
|
165
|
-
const filename = this.file.opts.filename;
|
|
180
|
+
const filename = this.file.opts.filename ? (0, _intlayer_config_utils.normalizePath)(this.file.opts.filename) : void 0;
|
|
166
181
|
if (this.opts.filesList && filename) {
|
|
167
|
-
if (!this.opts.filesList.includes(filename)) {
|
|
182
|
+
if (!this.opts.filesList.map(_intlayer_config_utils.normalizePath).includes(filename)) {
|
|
168
183
|
this._isIncluded = false;
|
|
169
184
|
return;
|
|
170
185
|
}
|
|
@@ -172,8 +187,9 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
172
187
|
},
|
|
173
188
|
visitor: { Program: {
|
|
174
189
|
enter(programPath, state) {
|
|
175
|
-
const filename = state.file.opts.filename;
|
|
176
|
-
|
|
190
|
+
const filename = state.file.opts.filename ? (0, _intlayer_config_utils.normalizePath)(state.file.opts.filename) : void 0;
|
|
191
|
+
const dictionariesEntryPath = state.opts.dictionariesEntryPath ? (0, _intlayer_config_utils.normalizePath)(state.opts.dictionariesEntryPath) : void 0;
|
|
192
|
+
if (state.opts.replaceDictionaryEntry && filename === dictionariesEntryPath) {
|
|
177
193
|
state._isDictEntry = true;
|
|
178
194
|
programPath.traverse({
|
|
179
195
|
ImportDeclaration(path) {
|
|
@@ -196,30 +212,46 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
196
212
|
exit(programPath, state) {
|
|
197
213
|
if (state._isDictEntry) return;
|
|
198
214
|
if (!state._isIncluded) return;
|
|
199
|
-
|
|
215
|
+
programPath.traverse({ ImportDeclaration(path) {
|
|
216
|
+
const src = path.node.source.value;
|
|
217
|
+
if (!PACKAGE_LIST.includes(src)) return;
|
|
218
|
+
state._hasValidImport = true;
|
|
219
|
+
for (const spec of path.node.specifiers) {
|
|
220
|
+
if (!t.isImportSpecifier(spec)) continue;
|
|
221
|
+
const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
222
|
+
if (isCallerName(importedName)) {
|
|
223
|
+
state._callerMap?.set(spec.local.name, importedName);
|
|
224
|
+
state._callerPackageMap?.set(spec.local.name, src);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
} });
|
|
228
|
+
const packagesWithDynamicCall = /* @__PURE__ */ new Set();
|
|
229
|
+
const packagesWithFetchCall = /* @__PURE__ */ new Set();
|
|
200
230
|
programPath.traverse({ CallExpression(path) {
|
|
201
231
|
const callee = path.node.callee;
|
|
202
232
|
if (!t.isIdentifier(callee)) return;
|
|
203
233
|
if (state._callerMap?.get(callee.name) !== "useIntlayer") return;
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
else if (arg && t.isTemplateLiteral(arg) && arg.expressions.length === 0 && arg.quasis.length === 1) key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;
|
|
234
|
+
const callerPackage = state._callerPackageMap?.get(callee.name);
|
|
235
|
+
if (!callerPackage) return;
|
|
236
|
+
const key = getKeyFromArgument(path.node.arguments[0], t);
|
|
208
237
|
if (!key) return;
|
|
209
238
|
const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
|
|
210
|
-
if (dictionaryOverrideMode === "dynamic"
|
|
239
|
+
if (dictionaryOverrideMode === "dynamic") packagesWithDynamicCall.add(callerPackage);
|
|
240
|
+
else if (dictionaryOverrideMode === "fetch") packagesWithFetchCall.add(callerPackage);
|
|
211
241
|
} });
|
|
212
242
|
programPath.traverse({
|
|
213
243
|
ImportDeclaration(path) {
|
|
214
244
|
const src = path.node.source.value;
|
|
215
245
|
if (!PACKAGE_LIST.includes(src)) return;
|
|
216
|
-
state._hasValidImport = true;
|
|
217
246
|
for (const spec of path.node.specifiers) {
|
|
218
247
|
if (!t.isImportSpecifier(spec)) continue;
|
|
219
248
|
const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
220
|
-
if (
|
|
249
|
+
if (!isCallerName(importedName)) continue;
|
|
221
250
|
const importMode = state.opts.importMode;
|
|
222
|
-
const
|
|
251
|
+
const packageHasDynamicCall = packagesWithDynamicCall.has(src);
|
|
252
|
+
const packageHasFetchCall = packagesWithFetchCall.has(src);
|
|
253
|
+
const shouldUseStaticFallback = !packageHasFetchCall && shouldUseStaticSsrDynamicFallback(src, importMode === "dynamic" || packageHasDynamicCall ? "dynamic" : importMode, state.opts);
|
|
254
|
+
const shouldUseDynamicHelpers = isDynamicPackage(src) && (importMode === "fetch" || packageHasFetchCall || (importMode === "dynamic" || packageHasDynamicCall) && !shouldUseStaticFallback);
|
|
223
255
|
if (shouldUseDynamicHelpers) state._useDynamicHelpers = true;
|
|
224
256
|
let helperMap;
|
|
225
257
|
if (shouldUseDynamicHelpers) helperMap = {
|
|
@@ -237,21 +269,22 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
237
269
|
const originalImportedName = state._callerMap?.get(callee.name);
|
|
238
270
|
if (!originalImportedName) return;
|
|
239
271
|
state._hasValidImport = true;
|
|
240
|
-
const
|
|
241
|
-
let key;
|
|
242
|
-
if (arg && t.isStringLiteral(arg)) key = arg.value;
|
|
243
|
-
else if (arg && t.isTemplateLiteral(arg) && arg.expressions.length === 0 && arg.quasis.length === 1) key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;
|
|
272
|
+
const key = getKeyFromArgument(path.node.arguments[0], t);
|
|
244
273
|
if (!key) return;
|
|
274
|
+
const callerPackage = state._callerPackageMap?.get(callee.name);
|
|
245
275
|
const importMode = state.opts.importMode;
|
|
246
276
|
const isUseIntlayer = originalImportedName === "useIntlayer";
|
|
247
|
-
const useDynamicHelpers = Boolean(state._useDynamicHelpers);
|
|
248
|
-
let perCallMode = "static";
|
|
249
277
|
const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
|
|
278
|
+
const effectiveImportMode = dictionaryOverrideMode ?? importMode;
|
|
279
|
+
const packageHasFetchCall = callerPackage !== void 0 && packagesWithFetchCall.has(callerPackage);
|
|
280
|
+
const usesStaticSsrDynamicFallback = isUseIntlayer && !packageHasFetchCall && shouldUseStaticSsrDynamicFallback(callerPackage, effectiveImportMode, state.opts);
|
|
281
|
+
const useDynamicHelpers = Boolean(state._useDynamicHelpers) && !usesStaticSsrDynamicFallback;
|
|
282
|
+
let perCallMode = "static";
|
|
250
283
|
if (isUseIntlayer && useDynamicHelpers) {
|
|
251
284
|
if (dictionaryOverrideMode) perCallMode = dictionaryOverrideMode;
|
|
252
285
|
else if (importMode === "dynamic") perCallMode = "dynamic";
|
|
253
286
|
else if (importMode === "fetch") perCallMode = "fetch";
|
|
254
|
-
} else if (isUseIntlayer && !useDynamicHelpers) {
|
|
287
|
+
} else if (isUseIntlayer && !useDynamicHelpers && !usesStaticSsrDynamicFallback) {
|
|
255
288
|
if (dictionaryOverrideMode === "dynamic" || dictionaryOverrideMode === "fetch") perCallMode = dictionaryOverrideMode;
|
|
256
289
|
}
|
|
257
290
|
let ident;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-optimize.cjs","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport { getPathHash } from '@intlayer/chokidar/utils';\nimport { normalizePath } from '@intlayer/config/utils';\n\nconst PACKAGE_LIST = [\n 'intlayer',\n '@intlayer/core',\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'svelte-intlayer',\n 'vue-intlayer',\n 'angular-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n];\n\nconst CALLER_LIST = ['useIntlayer', 'getIntlayer'] as const;\n\n/**\n * Packages that support dynamic import\n */\nconst PACKAGE_LIST_DYNAMIC = [\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'preact-intlayer',\n 'vue-intlayer',\n 'solid-intlayer',\n 'svelte-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n] as const;\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n useIntlayer: 'useDictionary',\n} as const;\n\nconst DYNAMIC_IMPORT_FUNCTION = {\n useIntlayer: 'useDictionaryDynamic',\n} as const;\n\n/**\n * Options for the optimization Babel plugin\n */\nexport type OptimizePluginOptions = {\n /**\n * If false, the plugin will not apply any transformation.\n */\n optimize?: boolean;\n /**\n * The path to the dictionaries directory.\n */\n dictionariesDir: string;\n /**\n * The path to the dictionaries entry file.\n */\n dictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries entry file.\n */\n unmergedDictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries directory.\n */\n unmergedDictionariesDir: string;\n /**\n * The path to the dictionaries directory.\n */\n dynamicDictionariesDir: string;\n /**\n * The path to the dynamic dictionaries entry file.\n */\n dynamicDictionariesEntryPath: string;\n /**\n * The path to the fetch dictionaries directory.\n */\n fetchDictionariesDir: string;\n /**\n * The path to the fetch dictionaries entry file.\n */\n fetchDictionariesEntryPath: string;\n /**\n * If true, the plugin will replace the dictionary entry file with `export default {}`.\n */\n replaceDictionaryEntry: boolean;\n /**\n * If true, the plugin will activate the dynamic import of the dictionaries. It will rely on Suspense to load the dictionaries.\n */\n importMode: 'static' | 'dynamic' | 'fetch' | undefined;\n /**\n * Map of dictionary keys to their specific import mode.\n */\n dictionaryModeMap?: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n >;\n /**\n * Files list to traverse.\n */\n filesList: string[];\n};\n\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** map key → generated ident (per-file) for static imports */\n _newStaticImports?: Map<string, BabelTypes.Identifier>;\n /** map key → generated ident (per-file) for dynamic imports */\n _newDynamicImports?: Map<string, BabelTypes.Identifier>;\n /** whether the current file imported *any* intlayer package */\n _hasValidImport?: boolean;\n /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */\n _callerMap?: Map<string, (typeof CALLER_LIST)[number]>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: boolean;\n /** whether dynamic helpers are active for this file */\n _useDynamicHelpers?: boolean;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n};\n\n/**\n * Replicates the xxHash64 → Base-62 algorithm used by the SWC version\n * and prefixes an underscore so the generated identifiers never collide\n * with user-defined ones.\n */\nconst makeIdent = (\n key: string,\n t: typeof BabelTypes\n): BabelTypes.Identifier => {\n const hash = getPathHash(key);\n return t.identifier(`_${hash}`);\n};\n\nconst computeImport = (\n fromFile: string,\n dictionariesDir: string,\n dynamicDictionariesDir: string,\n fetchDictionariesDir: string,\n key: string,\n importMode: 'static' | 'dynamic' | 'fetch'\n): string => {\n let relativePath = join(dictionariesDir, `${key}.json`);\n\n if (importMode === 'fetch') {\n relativePath = join(fetchDictionariesDir, `${key}.mjs`);\n }\n\n if (importMode === 'dynamic') {\n relativePath = join(dynamicDictionariesDir, `${key}.mjs`);\n }\n\n let rel = relative(dirname(fromFile), relativePath);\n\n // Fix windows path\n rel = normalizePath(rel);\n\n // Fix relative path\n if (!rel.startsWith('./') && !rel.startsWith('../')) {\n rel = `./${rel}`;\n }\n\n return rel;\n};\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()` and `getIntlayer()` from various Intlayer\n * packages into optimized dictionary access patterns, automatically importing the required\n * dictionary files based on the configured import mode.\n *\n * ## Supported Input Patterns\n *\n * The plugin recognizes these function calls:\n *\n * ```ts\n * // useIntlayer\n * import { useIntlayer } from 'react-intlayer';\n * import { useIntlayer } from 'next-intlayer';\n *\n * // getIntlayer\n * import { getIntlayer } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * ```\n *\n * ## Transformation Modes\n *\n * ### Static Mode (default: `importMode = \"static\"`)\n *\n * Imports JSON dictionaries directly and replaces function calls with dictionary access:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import { useDictionary as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash);\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Dynamic Mode (`importMode = \"dynamic\"`)\n *\n * Uses dynamic dictionary loading with Suspense support:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Live Mode (`importMode = \"live\"`)\n *\n * Uses live-based dictionary loading for remote dictionaries:\n *\n * **Output if `dictionaryModeMap` includes the key with \"live\" value:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_fetch, \"app\");\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * > If `dictionaryModeMap` does not include the key with \"live\" value, the plugin will fallback to the dynamic impor\n *\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n */\nexport const intlayerOptimizeBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-transform',\n\n pre() {\n this._newStaticImports = new Map();\n this._newDynamicImports = new Map();\n this._callerMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = false;\n this._useDynamicHelpers = false;\n\n // If optimize is false, skip processing entirely\n if (this.opts.optimize === false) {\n this._isIncluded = false;\n return;\n }\n\n // If filesList is provided, check if current file is included\n const filename = this.file.opts.filename;\n if (this.opts.filesList && filename) {\n const isIncluded = this.opts.filesList.includes(filename);\n\n if (!isIncluded) {\n // Force _isIncluded to false to skip processing\n this._isIncluded = false;\n return;\n }\n }\n },\n\n visitor: {\n /* If this file *is* the dictionaries entry, short-circuit: export {} */\n Program: {\n enter(programPath, state) {\n // Safe access to filename\n const filename = state.file.opts.filename;\n\n // Check if this is the correct file to transform\n\n if (\n state.opts.replaceDictionaryEntry &&\n filename === state.opts.dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n\n // Traverse the program to surgically remove/edit specific parts\n programPath.traverse({\n // Remove all import statements (cleaning up 'sssss.json')\n ImportDeclaration(path) {\n path.remove();\n },\n\n // Find the variable definition and empty the object\n VariableDeclarator(path) {\n // We look for: const x = { ... }\n\n if (t.isObjectExpression(path.node.init)) {\n // Set the object properties to an empty array: {}\n path.node.init.properties = [];\n }\n },\n });\n\n // (Optional) Stop other plugins from processing this file further if needed\n // programPath.stop();\n }\n },\n\n /**\n * After full traversal, process imports and call expressions, then inject the JSON dictionary imports.\n *\n * We do the transformation in Program.exit (via a manual traverse) rather than using\n * top-level ImportDeclaration/CallExpression visitors. This ensures that if another plugin\n * (like babel-plugin-intlayer-extract) adds new useIntlayer calls in its Program.exit,\n * we will see and transform them here because our Program.exit runs after theirs.\n */\n exit(programPath, state) {\n if (state._isDictEntry) return; // nothing else to do – already replaced\n\n if (!state._isIncluded) return; // early-out if file is not included\n\n // Manual traversal to process imports and call expressions\n // This runs AFTER all other plugins' visitors have completed\n\n // Pre-pass to determine if we should use dynamic helpers\n let fileHasDynamicCall = false;\n programPath.traverse({\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (originalImportedName !== 'useIntlayer') return;\n\n const arg = path.node.arguments[0];\n let key: string | undefined;\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;\n }\n if (!key) return;\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n fileHasDynamicCall = true;\n }\n },\n });\n\n programPath.traverse({\n /* Inspect every intlayer import */\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n // Mark that we do import from an intlayer package in this file\n state._hasValidImport = true;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (CALLER_LIST.includes(importedName as any)) {\n state._callerMap?.set(\n spec.local.name,\n importedName as (typeof CALLER_LIST)[number]\n );\n }\n\n const importMode = state.opts.importMode;\n // Determine whether this import should use the dynamic helpers.\n const shouldUseDynamicHelpers =\n (importMode === 'dynamic' ||\n importMode === 'fetch' ||\n fileHasDynamicCall) &&\n PACKAGE_LIST_DYNAMIC.includes(src as any);\n\n // Remember for later (CallExpression) whether we are using the dynamic helpers\n\n if (shouldUseDynamicHelpers) {\n state._useDynamicHelpers = true;\n }\n\n let helperMap: Record<string, string>;\n\n if (shouldUseDynamicHelpers) {\n // Use dynamic helpers for useIntlayer when dynamic mode is enabled\n helperMap = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n } as Record<string, string>;\n } else {\n // Use static helpers by default\n helperMap = STATIC_IMPORT_FUNCTION as Record<string, string>;\n }\n\n const newIdentifier = helperMap[importedName];\n\n // Only rewrite when we actually have a mapping for the imported\n // specifier (ignore unrelated named imports).\n\n if (newIdentifier) {\n // Keep the local alias intact (so calls remain `useIntlayer` /\n // `getIntlayer`), but rewrite the imported identifier so it\n // points to our helper implementation.\n spec.imported = t.identifier(newIdentifier);\n }\n }\n },\n\n /* Replace calls: useIntlayer(\"foo\") → useDictionary(_hash) or useDictionaryDynamic(_hash, \"foo\") */\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (!originalImportedName) return;\n\n // Ensure we ultimately emit helper imports for files that *invoke*\n // the hooks, even if they didn't import them directly (edge cases with\n // re-exports).\n state._hasValidImport = true;\n\n const arg = path.node.arguments[0];\n let key: string | undefined;\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;\n }\n if (!key) return;\n\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const useDynamicHelpers = Boolean(state._useDynamicHelpers);\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'\n let perCallMode: 'static' | 'dynamic' | 'fetch' = 'static';\n\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (isUseIntlayer && useDynamicHelpers) {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic') {\n perCallMode = 'dynamic';\n } else if (importMode === 'fetch') {\n perCallMode = 'fetch';\n }\n } else if (isUseIntlayer && !useDynamicHelpers) {\n // If dynamic helpers are NOT active (global mode is static),\n // we STILL might want to force dynamic/live for this specific call\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n perCallMode = dictionaryOverrideMode;\n }\n }\n\n let ident: BabelTypes.Identifier;\n\n if (perCallMode === 'fetch') {\n // Use fetch dictionaries entry (live mode for selected keys)\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_fetch`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Helper: first argument is the dictionary entry, second is the key\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else if (perCallMode === 'dynamic') {\n // Use dynamic dictionaries entry\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n // Create a unique identifier for dynamic imports by appending a suffix\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_dyn`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Dynamic helper: first argument is the dictionary, second is the key.\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else {\n // Use static imports for getIntlayer or useIntlayer when not using dynamic helpers\n let staticIdent = state._newStaticImports?.get(key);\n\n if (!staticIdent) {\n staticIdent = makeIdent(key, t);\n state._newStaticImports?.set(key, staticIdent);\n }\n ident = staticIdent;\n\n // Static helper (useDictionary / getDictionary): replace key with ident.\n // After the splice above the key is always at index 0.\n path.node.arguments[0] = t.identifier(ident.name);\n }\n },\n });\n\n // Early-out if we touched nothing\n\n if (!state._hasValidImport) return;\n\n const file = state.file.opts.filename!;\n const dictionariesDir = state.opts.dictionariesDir;\n const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;\n const fetchDictionariesDir = state.opts.fetchDictionariesDir;\n const imports: BabelTypes.ImportDeclaration[] = [];\n\n // Generate static JSON imports (getIntlayer always uses JSON dictionaries)\n for (const [key, ident] of state._newStaticImports!) {\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static'\n );\n\n const importDeclarationNode = t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n );\n\n // Add 'type: json' attribute for JSON files\n importDeclarationNode.attributes = [\n t.importAttribute(t.identifier('type'), t.stringLiteral('json')),\n ];\n\n imports.push(importDeclarationNode);\n }\n\n // Generate dynamic/fetch imports (for useIntlayer when using dynamic/live helpers)\n for (const [key, ident] of state._newDynamicImports!) {\n const modeForThisIdent: 'dynamic' | 'fetch' = ident.name.endsWith(\n '_fetch'\n )\n ? 'fetch'\n : 'dynamic';\n\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n modeForThisIdent\n );\n imports.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n )\n );\n }\n\n if (!imports.length) return;\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n const bodyPaths = programPath.get(\n 'body'\n ) as NodePath<BabelTypes.Statement>[];\n let insertPos = 0;\n for (const stmtPath of bodyPaths) {\n const stmt = stmtPath.node;\n\n if (\n t.isExpressionStatement(stmt) &&\n t.isStringLiteral(stmt.expression) &&\n !stmt.expression.value.startsWith('import') &&\n !stmt.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n programPath.node.body.splice(insertPos, 0, ...imports);\n },\n },\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-optimize.cjs","names":["normalizePath"],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport { getPathHash } from '@intlayer/chokidar/utils';\nimport { normalizePath } from '@intlayer/config/utils';\n\nconst PACKAGE_LIST = [\n 'intlayer',\n '@intlayer/core',\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'svelte-intlayer',\n 'vue-intlayer',\n 'angular-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n];\n\nconst CALLER_LIST = ['useIntlayer', 'getIntlayer'] as const;\n\n/**\n * Packages that support dynamic import\n */\nconst PACKAGE_LIST_DYNAMIC = [\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'preact-intlayer',\n 'vue-intlayer',\n 'solid-intlayer',\n 'svelte-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n] as const;\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n useIntlayer: 'useDictionary',\n} as const;\n\nconst DYNAMIC_IMPORT_FUNCTION = {\n useIntlayer: 'useDictionaryDynamic',\n} as const;\n\ntype CallerName = (typeof CALLER_LIST)[number];\ntype ImportMode = 'static' | 'dynamic' | 'fetch';\n\n/**\n * Packages whose SSR dynamic helper should render synchronously with a static\n * dictionary. Solid streaming SSR can hydrate static output reliably, while\n * its dynamic resource path either suspends during hydration or serializes the\n * full dictionary into HTML.\n */\nconst PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK = new Set<string>(['solid-intlayer']);\n\n/**\n * Options for the optimization Babel plugin\n */\nexport type OptimizePluginOptions = {\n /**\n * If false, the plugin will not apply any transformation.\n */\n optimize?: boolean;\n /**\n * The path to the dictionaries directory.\n */\n dictionariesDir: string;\n /**\n * The path to the dictionaries entry file.\n */\n dictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries entry file.\n */\n unmergedDictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries directory.\n */\n unmergedDictionariesDir: string;\n /**\n * The path to the dictionaries directory.\n */\n dynamicDictionariesDir: string;\n /**\n * The path to the dynamic dictionaries entry file.\n */\n dynamicDictionariesEntryPath: string;\n /**\n * The path to the fetch dictionaries directory.\n */\n fetchDictionariesDir: string;\n /**\n * The path to the fetch dictionaries entry file.\n */\n fetchDictionariesEntryPath: string;\n /**\n * If true, the plugin will replace the dictionary entry file with `export default {}`.\n */\n replaceDictionaryEntry: boolean;\n /**\n * If true, the plugin will activate the dynamic import of the dictionaries. It will rely on Suspense to load the dictionaries.\n */\n importMode: 'static' | 'dynamic' | 'fetch' | undefined;\n /**\n * Map of dictionary keys to their specific import mode.\n */\n dictionaryModeMap?: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n >;\n /**\n * Files list to traverse.\n */\n filesList: string[];\n /**\n * Whether the current transform is for an SSR bundle.\n */\n isServer?: boolean;\n};\n\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** map key → generated ident (per-file) for static imports */\n _newStaticImports?: Map<string, BabelTypes.Identifier>;\n /** map key → generated ident (per-file) for dynamic imports */\n _newDynamicImports?: Map<string, BabelTypes.Identifier>;\n /** whether the current file imported *any* intlayer package */\n _hasValidImport?: boolean;\n /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */\n _callerMap?: Map<string, (typeof CALLER_LIST)[number]>;\n /** map from local identifier name to the intlayer package it was imported from */\n _callerPackageMap?: Map<string, string>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: boolean;\n /** whether dynamic helpers are active for this file */\n _useDynamicHelpers?: boolean;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n};\n\n/**\n * Replicates the xxHash64 → Base-62 algorithm used by the SWC version\n * and prefixes an underscore so the generated identifiers never collide\n * with user-defined ones.\n */\nconst makeIdent = (\n key: string,\n t: typeof BabelTypes\n): BabelTypes.Identifier => {\n const hash = getPathHash(key);\n return t.identifier(`_${hash}`);\n};\n\nconst computeImport = (\n fromFile: string,\n dictionariesDir: string,\n dynamicDictionariesDir: string,\n fetchDictionariesDir: string,\n key: string,\n importMode: 'static' | 'dynamic' | 'fetch'\n): string => {\n let relativePath = join(dictionariesDir, `${key}.json`);\n\n if (importMode === 'fetch') {\n relativePath = join(fetchDictionariesDir, `${key}.mjs`);\n }\n\n if (importMode === 'dynamic') {\n relativePath = join(dynamicDictionariesDir, `${key}.mjs`);\n }\n\n let rel = relative(dirname(fromFile), relativePath);\n\n // Fix windows path\n rel = normalizePath(rel);\n\n // Fix relative path\n if (!rel.startsWith('./') && !rel.startsWith('../')) {\n rel = `./${rel}`;\n }\n\n return rel;\n};\n\nconst getKeyFromArgument = (\n arg: BabelTypes.Node | null | undefined,\n t: typeof BabelTypes\n): string | undefined => {\n if (arg && t.isStringLiteral(arg)) {\n return arg.value;\n }\n\n if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n return arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;\n }\n\n return undefined;\n};\n\nconst isCallerName = (name: string): name is CallerName =>\n CALLER_LIST.includes(name as CallerName);\n\nconst isDynamicPackage = (\n packageName: string\n): packageName is (typeof PACKAGE_LIST_DYNAMIC)[number] =>\n PACKAGE_LIST_DYNAMIC.includes(\n packageName as (typeof PACKAGE_LIST_DYNAMIC)[number]\n );\n\nconst shouldUseStaticSsrDynamicFallback = (\n callerPackage: string | undefined,\n importMode: ImportMode | undefined,\n opts: OptimizePluginOptions\n): boolean =>\n opts.isServer === true &&\n importMode === 'dynamic' &&\n callerPackage !== undefined &&\n PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK.has(callerPackage);\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()` and `getIntlayer()` from various Intlayer\n * packages into optimized dictionary access patterns, automatically importing the required\n * dictionary files based on the configured import mode.\n *\n * ## Supported Input Patterns\n *\n * The plugin recognizes these function calls:\n *\n * ```ts\n * // useIntlayer\n * import { useIntlayer } from 'react-intlayer';\n * import { useIntlayer } from 'next-intlayer';\n *\n * // getIntlayer\n * import { getIntlayer } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * ```\n *\n * ## Transformation Modes\n *\n * ### Static Mode (default: `importMode = \"static\"`)\n *\n * Imports JSON dictionaries directly and replaces function calls with dictionary access:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import { useDictionary as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash);\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Dynamic Mode (`importMode = \"dynamic\"`)\n *\n * Uses dynamic dictionary loading with Suspense support:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Fetch Mode (`importMode = \"fetch\"`)\n *\n * Uses fetch-based dictionary loading for remote dictionaries:\n *\n * **Output if `dictionaryModeMap` includes the key with \"fetch\" value:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_fetch, \"app\");\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * > If `dictionaryModeMap` does not include the key with \"fetch\" value, the plugin will fallback to the dynamic import mode.\n *\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n */\nexport const intlayerOptimizeBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-transform',\n\n pre() {\n this._newStaticImports = new Map();\n this._newDynamicImports = new Map();\n this._callerMap = new Map();\n this._callerPackageMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = false;\n this._useDynamicHelpers = false;\n\n // If optimize is false, skip processing entirely\n if (this.opts.optimize === false) {\n this._isIncluded = false;\n return;\n }\n\n // If filesList is provided, check if current file is included\n const filename = this.file.opts.filename\n ? normalizePath(this.file.opts.filename)\n : undefined;\n if (this.opts.filesList && filename) {\n const filesList = this.opts.filesList.map(normalizePath);\n const isIncluded = filesList.includes(filename);\n\n if (!isIncluded) {\n // Force _isIncluded to false to skip processing\n this._isIncluded = false;\n return;\n }\n }\n },\n\n visitor: {\n /* If this file *is* the dictionaries entry, short-circuit: export {} */\n Program: {\n enter(programPath, state) {\n // Safe access to filename\n const filename = state.file.opts.filename\n ? normalizePath(state.file.opts.filename)\n : undefined;\n const dictionariesEntryPath = state.opts.dictionariesEntryPath\n ? normalizePath(state.opts.dictionariesEntryPath)\n : undefined;\n\n // Check if this is the correct file to transform\n\n if (\n state.opts.replaceDictionaryEntry &&\n filename === dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n\n // Traverse the program to surgically remove/edit specific parts\n programPath.traverse({\n // Remove all import statements (cleaning up 'sssss.json')\n ImportDeclaration(path) {\n path.remove();\n },\n\n // Find the variable definition and empty the object\n VariableDeclarator(path) {\n // We look for: const x = { ... }\n\n if (t.isObjectExpression(path.node.init)) {\n // Set the object properties to an empty array: {}\n path.node.init.properties = [];\n }\n },\n });\n\n // (Optional) Stop other plugins from processing this file further if needed\n // programPath.stop();\n }\n },\n\n /**\n * After full traversal, process imports and call expressions, then inject the JSON dictionary imports.\n *\n * We do the transformation in Program.exit (via a manual traverse) rather than using\n * top-level ImportDeclaration/CallExpression visitors. This ensures that if another plugin\n * (like babel-plugin-intlayer-extract) adds new useIntlayer calls in its Program.exit,\n * we will see and transform them here because our Program.exit runs after theirs.\n */\n exit(programPath, state) {\n if (state._isDictEntry) return; // nothing else to do – already replaced\n\n if (!state._isIncluded) return; // early-out if file is not included\n\n // Manual traversal to process imports and call expressions\n // This runs AFTER all other plugins' visitors have completed\n programPath.traverse({\n /* Inspect every intlayer import before deciding helper rewrites. */\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n state._hasValidImport = true;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (isCallerName(importedName)) {\n state._callerMap?.set(spec.local.name, importedName);\n state._callerPackageMap?.set(spec.local.name, src);\n }\n }\n },\n });\n\n // Pre-pass to determine if dictionary-level overrides require the\n // dynamic helper in an otherwise static file.\n const packagesWithDynamicCall = new Set<string>();\n const packagesWithFetchCall = new Set<string>();\n programPath.traverse({\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (originalImportedName !== 'useIntlayer') return;\n\n const callerPackage = state._callerPackageMap?.get(callee.name);\n if (!callerPackage) return;\n\n const key = getKeyFromArgument(path.node.arguments[0], t);\n if (!key) return;\n\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (dictionaryOverrideMode === 'dynamic') {\n packagesWithDynamicCall.add(callerPackage);\n } else if (dictionaryOverrideMode === 'fetch') {\n packagesWithFetchCall.add(callerPackage);\n }\n },\n });\n\n programPath.traverse({\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (!isCallerName(importedName)) continue;\n\n const importMode = state.opts.importMode;\n // Determine whether this import should use the dynamic helpers.\n const packageHasDynamicCall = packagesWithDynamicCall.has(src);\n const packageHasFetchCall = packagesWithFetchCall.has(src);\n // A package import can be rewritten to only one helper. Fetch\n // overrides therefore keep the dynamic helper for every\n // useIntlayer call from that package in this file.\n const shouldUseStaticFallback =\n !packageHasFetchCall &&\n shouldUseStaticSsrDynamicFallback(\n src,\n importMode === 'dynamic' || packageHasDynamicCall\n ? 'dynamic'\n : importMode,\n state.opts\n );\n const shouldUseDynamicHelpers =\n isDynamicPackage(src) &&\n (importMode === 'fetch' ||\n packageHasFetchCall ||\n ((importMode === 'dynamic' || packageHasDynamicCall) &&\n !shouldUseStaticFallback));\n\n // Remember for later (CallExpression) whether we are using the dynamic helpers\n\n if (shouldUseDynamicHelpers) {\n state._useDynamicHelpers = true;\n }\n\n let helperMap: Record<string, string>;\n\n if (shouldUseDynamicHelpers) {\n // Use dynamic helpers for useIntlayer when dynamic mode is enabled\n helperMap = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n } as Record<string, string>;\n } else {\n // Use static helpers by default\n helperMap = STATIC_IMPORT_FUNCTION as Record<string, string>;\n }\n\n const newIdentifier = helperMap[importedName];\n\n if (newIdentifier) {\n // Keep the local alias intact (so calls remain `useIntlayer` /\n // `getIntlayer`), but rewrite the imported identifier so it\n // points to our helper implementation.\n spec.imported = t.identifier(newIdentifier);\n }\n }\n },\n\n /* Replace calls: useIntlayer(\"foo\") → useDictionary(_hash) or useDictionaryDynamic(_hash, \"foo\") */\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (!originalImportedName) return;\n\n // Ensure we ultimately emit helper imports for files that *invoke*\n // the hooks, even if they didn't import them directly (edge cases with\n // re-exports).\n state._hasValidImport = true;\n\n const key = getKeyFromArgument(path.node.arguments[0], t);\n if (!key) return;\n\n const callerPackage = state._callerPackageMap?.get(callee.name);\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n const effectiveImportMode = dictionaryOverrideMode ?? importMode;\n const packageHasFetchCall =\n callerPackage !== undefined &&\n packagesWithFetchCall.has(callerPackage);\n const usesStaticSsrDynamicFallback =\n isUseIntlayer &&\n !packageHasFetchCall &&\n shouldUseStaticSsrDynamicFallback(\n callerPackage,\n effectiveImportMode,\n state.opts\n );\n const useDynamicHelpers =\n Boolean(state._useDynamicHelpers) &&\n !usesStaticSsrDynamicFallback;\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'\n let perCallMode: ImportMode = 'static';\n\n if (isUseIntlayer && useDynamicHelpers) {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic') {\n perCallMode = 'dynamic';\n } else if (importMode === 'fetch') {\n perCallMode = 'fetch';\n }\n } else if (\n isUseIntlayer &&\n !useDynamicHelpers &&\n !usesStaticSsrDynamicFallback\n ) {\n // If dynamic helpers are NOT active (global mode is static),\n // we STILL might want to force dynamic/fetch for this specific call\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n perCallMode = dictionaryOverrideMode;\n }\n }\n\n let ident: BabelTypes.Identifier;\n\n if (perCallMode === 'fetch') {\n // Use fetch dictionaries entry for selected keys\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_fetch`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Helper: first argument is the dictionary entry, second is the key\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else if (perCallMode === 'dynamic') {\n // Use dynamic dictionaries entry\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n // Create a unique identifier for dynamic imports by appending a suffix\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_dyn`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Dynamic helper: first argument is the dictionary, second is the key.\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else {\n // Use static imports for getIntlayer or useIntlayer when not using dynamic helpers\n let staticIdent = state._newStaticImports?.get(key);\n\n if (!staticIdent) {\n staticIdent = makeIdent(key, t);\n state._newStaticImports?.set(key, staticIdent);\n }\n ident = staticIdent;\n\n // Static helper (useDictionary / getDictionary): replace key with ident.\n // After the splice above the key is always at index 0.\n path.node.arguments[0] = t.identifier(ident.name);\n }\n },\n });\n\n // Early-out if we touched nothing\n\n if (!state._hasValidImport) return;\n\n const file = state.file.opts.filename!;\n const dictionariesDir = state.opts.dictionariesDir;\n const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;\n const fetchDictionariesDir = state.opts.fetchDictionariesDir;\n const imports: BabelTypes.ImportDeclaration[] = [];\n\n // Generate static JSON imports (getIntlayer always uses JSON dictionaries)\n for (const [key, ident] of state._newStaticImports!) {\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static'\n );\n\n const importDeclarationNode = t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n );\n\n // Add 'type: json' attribute for JSON files\n importDeclarationNode.attributes = [\n t.importAttribute(t.identifier('type'), t.stringLiteral('json')),\n ];\n\n imports.push(importDeclarationNode);\n }\n\n // Generate dynamic/fetch imports (for useIntlayer when using dynamic/fetch helpers)\n for (const [key, ident] of state._newDynamicImports!) {\n const modeForThisIdent: 'dynamic' | 'fetch' = ident.name.endsWith(\n '_fetch'\n )\n ? 'fetch'\n : 'dynamic';\n\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n modeForThisIdent\n );\n imports.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n )\n );\n }\n\n if (!imports.length) return;\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n const bodyPaths = programPath.get(\n 'body'\n ) as NodePath<BabelTypes.Statement>[];\n let insertPos = 0;\n for (const stmtPath of bodyPaths) {\n const stmt = stmtPath.node;\n\n if (\n t.isExpressionStatement(stmt) &&\n t.isStringLiteral(stmt.expression) &&\n !stmt.expression.value.startsWith('import') &&\n !stmt.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n programPath.node.body.splice(insertPos, 0, ...imports);\n },\n },\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { extractContentSync } from "./extractContent/extractContent.mjs";
|
|
|
3
3
|
import { relative } from "node:path";
|
|
4
4
|
import * as ANSIColors from "@intlayer/config/colors";
|
|
5
5
|
import { colorize, colorizePath, getAppLogger } from "@intlayer/config/logger";
|
|
6
|
+
import { normalizePath } from "@intlayer/config/utils";
|
|
6
7
|
import { parse } from "@babel/parser";
|
|
7
8
|
|
|
8
9
|
//#region src/babel-plugin-intlayer-extract.ts
|
|
@@ -31,7 +32,7 @@ const intlayerExtractBabelPlugin = (_babel) => {
|
|
|
31
32
|
if (opts.enabled === false) return;
|
|
32
33
|
const filename = state.file.opts.filename;
|
|
33
34
|
if (!filename) return;
|
|
34
|
-
if (opts.filesList && !opts.filesList.includes(filename)) return;
|
|
35
|
+
if (opts.filesList && !opts.filesList.map(normalizePath).includes(normalizePath(filename))) return;
|
|
35
36
|
const fileCode = state.file.code ?? "";
|
|
36
37
|
if (!fileCode) return;
|
|
37
38
|
const appLogger = getAppLogger(opts.configuration);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport type { PluginObj, PluginPass } from '@babel/core';\nimport { parse } from '@babel/parser';\nimport type * as BabelTypes from '@babel/types';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport { extractContentSync } from './extractContent/extractContent';\nimport type { PackageName } from './extractContent/utils/constants';\nimport { detectPackageName } from './extractContent/utils/detectPackageName';\n\nexport type ExtractResult = {\n dictionaryKey: string;\n filePath: string;\n content: Record<string, string>;\n locale: Locale;\n};\n\nexport type ExtractPluginOptions = {\n packageName?: PackageName;\n filesList: string[];\n enabled: boolean;\n\n shouldExtract?: (text: string) => boolean;\n configuration: IntlayerConfig;\n /**\n * Callback invoked for each extracted dictionary key/content pair.\n * Used by `getExtractPluginOptions` to write dictionaries to disk.\n * May be async — the plugin will fire-and-forget (Babel transforms are sync).\n */\n onExtract?: (result: ExtractResult) => void | Promise<void>;\n /**\n * Defines the output files path.\n */\n output?: FilePathPattern;\n};\n\ntype State = PluginPass & { opts: ExtractPluginOptions };\n\n/**\n * Babel plugin that extracts translatable content from source files and\n * injects Intlayer hooks (`useIntlayer` / `getIntlayer`) automatically.\n *\n * Designed for use with Babel-based build tools such as Next.js and Webpack.\n *\n * @example babel.config.js\n * ```js\n * const { intlayerExtractBabelPlugin, getExtractPluginOptions } = require('@intlayer/babel');\n * module.exports = {\n * presets: ['next/babel'],\n * plugins: [\n * [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const intlayerExtractBabelPlugin = (_babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n return {\n name: 'babel-plugin-intlayer-extract',\n\n visitor: {\n Program: {\n enter(programPath, state) {\n const opts = state.opts;\n\n // Merge plugin options with the unified compiler config\n const isEnabled = opts.enabled;\n\n if (isEnabled === false) return;\n\n const filename = state.file.opts.filename;\n\n if (!filename) return;\n\n if (opts.filesList
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport type { PluginObj, PluginPass } from '@babel/core';\nimport { parse } from '@babel/parser';\nimport type * as BabelTypes from '@babel/types';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport { normalizePath } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport { extractContentSync } from './extractContent/extractContent';\nimport type { PackageName } from './extractContent/utils/constants';\nimport { detectPackageName } from './extractContent/utils/detectPackageName';\n\nexport type ExtractResult = {\n dictionaryKey: string;\n filePath: string;\n content: Record<string, string>;\n locale: Locale;\n};\n\nexport type ExtractPluginOptions = {\n packageName?: PackageName;\n filesList: string[];\n enabled: boolean;\n\n shouldExtract?: (text: string) => boolean;\n configuration: IntlayerConfig;\n /**\n * Callback invoked for each extracted dictionary key/content pair.\n * Used by `getExtractPluginOptions` to write dictionaries to disk.\n * May be async — the plugin will fire-and-forget (Babel transforms are sync).\n */\n onExtract?: (result: ExtractResult) => void | Promise<void>;\n /**\n * Defines the output files path.\n */\n output?: FilePathPattern;\n};\n\ntype State = PluginPass & { opts: ExtractPluginOptions };\n\n/**\n * Babel plugin that extracts translatable content from source files and\n * injects Intlayer hooks (`useIntlayer` / `getIntlayer`) automatically.\n *\n * Designed for use with Babel-based build tools such as Next.js and Webpack.\n *\n * @example babel.config.js\n * ```js\n * const { intlayerExtractBabelPlugin, getExtractPluginOptions } = require('@intlayer/babel');\n * module.exports = {\n * presets: ['next/babel'],\n * plugins: [\n * [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const intlayerExtractBabelPlugin = (_babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n return {\n name: 'babel-plugin-intlayer-extract',\n\n visitor: {\n Program: {\n enter(programPath, state) {\n const opts = state.opts;\n\n // Merge plugin options with the unified compiler config\n const isEnabled = opts.enabled;\n\n if (isEnabled === false) return;\n\n const filename = state.file.opts.filename;\n\n if (!filename) return;\n\n // Compare as POSIX paths (babel filenames use OS separators on Windows).\n if (\n opts.filesList &&\n !opts.filesList.map(normalizePath).includes(normalizePath(filename))\n ) {\n return;\n }\n\n const fileCode: string = state.file.code ?? '';\n if (!fileCode) return;\n\n const appLogger = getAppLogger(opts.configuration);\n const packageName = opts.packageName ?? detectPackageName(filename);\n\n const { saveComponents } = opts.configuration.compiler;\n\n const result = extractContentSync(filename, packageName, {\n configuration: opts.configuration,\n code: fileCode,\n onExtract: (extractResult: {\n key: string;\n content: Record<string, string>;\n }) => {\n if (opts.onExtract) {\n opts.onExtract({\n dictionaryKey: extractResult.key,\n filePath: filename,\n content: extractResult.content,\n locale: opts.configuration.internationalization.defaultLocale,\n });\n }\n },\n declarationOnly: !saveComponents,\n });\n\n if (!result) return;\n\n const { transformedCode: modifiedCode } = result;\n\n if (!modifiedCode) return;\n\n // Replace the Babel AST with the transformed code by re-parsing it.\n // This lets Babel serialise the injected hooks/imports through its\n // own code generator, preserving compatibility with other plugins.\n try {\n const newAst = parse(modifiedCode, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n programPath.node.body = newAst.program.body;\n programPath.node.directives = newAst.program.directives;\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Extracted content from ${colorizePath(relative(opts.configuration.system.baseDir, filename))}`,\n { level: 'debug' }\n );\n } catch (error) {\n appLogger(\n [\n `Failed to parse transformed code for ${colorizePath(relative(opts.configuration.system.baseDir, filename))}:`,\n error,\n ],\n { level: 'error' }\n );\n }\n },\n },\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,MAAa,8BAA8B,WAEnB;AACtB,QAAO;EACL,MAAM;EAEN,SAAS,EACP,SAAS,EACP,MAAM,aAAa,OAAO;GACxB,MAAM,OAAO,MAAM;AAKnB,OAFkB,KAAK,YAEL,MAAO;GAEzB,MAAM,WAAW,MAAM,KAAK,KAAK;AAEjC,OAAI,CAAC,SAAU;AAGf,OACE,KAAK,aACL,CAAC,KAAK,UAAU,IAAI,cAAc,CAAC,SAAS,cAAc,SAAS,CAAC,CAEpE;GAGF,MAAM,WAAmB,MAAM,KAAK,QAAQ;AAC5C,OAAI,CAAC,SAAU;GAEf,MAAM,YAAY,aAAa,KAAK,cAAc;GAClD,MAAM,cAAc,KAAK,eAAe,kBAAkB,SAAS;GAEnE,MAAM,EAAE,mBAAmB,KAAK,cAAc;GAE9C,MAAM,SAAS,mBAAmB,UAAU,aAAa;IACvD,eAAe,KAAK;IACpB,MAAM;IACN,YAAY,kBAGN;AACJ,SAAI,KAAK,UACP,MAAK,UAAU;MACb,eAAe,cAAc;MAC7B,UAAU;MACV,SAAS,cAAc;MACvB,QAAQ,KAAK,cAAc,qBAAqB;MACjD,CAAC;;IAGN,iBAAiB,CAAC;IACnB,CAAC;AAEF,OAAI,CAAC,OAAQ;GAEb,MAAM,EAAE,iBAAiB,iBAAiB;AAE1C,OAAI,CAAC,aAAc;AAKnB,OAAI;IACF,MAAM,SAAS,MAAM,cAAc;KACjC,YAAY;KACZ,SAAS,CAAC,OAAO,aAAa;KAC/B,CAAC;AAEF,gBAAY,KAAK,OAAO,OAAO,QAAQ;AACvC,gBAAY,KAAK,aAAa,OAAO,QAAQ;AAE7C,cACE,GAAG,SAAS,aAAa,WAAW,UAAU,CAAC,0BAA0B,aAAa,SAAS,KAAK,cAAc,OAAO,SAAS,SAAS,CAAC,IAC5I,EAAE,OAAO,SAAS,CACnB;YACM,OAAO;AACd,cACE,CACE,wCAAwC,aAAa,SAAS,KAAK,cAAc,OAAO,SAAS,SAAS,CAAC,CAAC,IAC5G,MACD,EACD,EAAE,OAAO,SAAS,CACnB;;KAGN,EACF;EACF"}
|
|
@@ -45,6 +45,13 @@ const STATIC_IMPORT_FUNCTION = {
|
|
|
45
45
|
};
|
|
46
46
|
const DYNAMIC_IMPORT_FUNCTION = { useIntlayer: "useDictionaryDynamic" };
|
|
47
47
|
/**
|
|
48
|
+
* Packages whose SSR dynamic helper should render synchronously with a static
|
|
49
|
+
* dictionary. Solid streaming SSR can hydrate static output reliably, while
|
|
50
|
+
* its dynamic resource path either suspends during hydration or serializes the
|
|
51
|
+
* full dictionary into HTML.
|
|
52
|
+
*/
|
|
53
|
+
const PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK = new Set(["solid-intlayer"]);
|
|
54
|
+
/**
|
|
48
55
|
* Replicates the xxHash64 → Base-62 algorithm used by the SWC version
|
|
49
56
|
* and prefixes an underscore so the generated identifiers never collide
|
|
50
57
|
* with user-defined ones.
|
|
@@ -62,6 +69,13 @@ const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchD
|
|
|
62
69
|
if (!rel.startsWith("./") && !rel.startsWith("../")) rel = `./${rel}`;
|
|
63
70
|
return rel;
|
|
64
71
|
};
|
|
72
|
+
const getKeyFromArgument = (arg, t) => {
|
|
73
|
+
if (arg && t.isStringLiteral(arg)) return arg.value;
|
|
74
|
+
if (arg && t.isTemplateLiteral(arg) && arg.expressions.length === 0 && arg.quasis.length === 1) return arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;
|
|
75
|
+
};
|
|
76
|
+
const isCallerName = (name) => CALLER_LIST.includes(name);
|
|
77
|
+
const isDynamicPackage = (packageName) => PACKAGE_LIST_DYNAMIC.includes(packageName);
|
|
78
|
+
const shouldUseStaticSsrDynamicFallback = (callerPackage, importMode, opts) => opts.isServer === true && importMode === "dynamic" && callerPackage !== void 0 && PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK.has(callerPackage);
|
|
65
79
|
/**
|
|
66
80
|
* Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.
|
|
67
81
|
*
|
|
@@ -117,11 +131,11 @@ const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchD
|
|
|
117
131
|
* const content2 = getIntlayer(_dicHash);
|
|
118
132
|
* ```
|
|
119
133
|
*
|
|
120
|
-
* ###
|
|
134
|
+
* ### Fetch Mode (`importMode = "fetch"`)
|
|
121
135
|
*
|
|
122
|
-
* Uses
|
|
136
|
+
* Uses fetch-based dictionary loading for remote dictionaries:
|
|
123
137
|
*
|
|
124
|
-
* **Output if `dictionaryModeMap` includes the key with "
|
|
138
|
+
* **Output if `dictionaryModeMap` includes the key with "fetch" value:**
|
|
125
139
|
* ```ts
|
|
126
140
|
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
127
141
|
* import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';
|
|
@@ -132,7 +146,7 @@ const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchD
|
|
|
132
146
|
* const content2 = getIntlayer(_dicHash);
|
|
133
147
|
* ```
|
|
134
148
|
*
|
|
135
|
-
* > If `dictionaryModeMap` does not include the key with "
|
|
149
|
+
* > If `dictionaryModeMap` does not include the key with "fetch" value, the plugin will fallback to the dynamic import mode.
|
|
136
150
|
*
|
|
137
151
|
* ```ts
|
|
138
152
|
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
@@ -152,6 +166,7 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
152
166
|
this._newStaticImports = /* @__PURE__ */ new Map();
|
|
153
167
|
this._newDynamicImports = /* @__PURE__ */ new Map();
|
|
154
168
|
this._callerMap = /* @__PURE__ */ new Map();
|
|
169
|
+
this._callerPackageMap = /* @__PURE__ */ new Map();
|
|
155
170
|
this._isIncluded = true;
|
|
156
171
|
this._hasValidImport = false;
|
|
157
172
|
this._isDictEntry = false;
|
|
@@ -160,9 +175,9 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
160
175
|
this._isIncluded = false;
|
|
161
176
|
return;
|
|
162
177
|
}
|
|
163
|
-
const filename = this.file.opts.filename;
|
|
178
|
+
const filename = this.file.opts.filename ? normalizePath(this.file.opts.filename) : void 0;
|
|
164
179
|
if (this.opts.filesList && filename) {
|
|
165
|
-
if (!this.opts.filesList.includes(filename)) {
|
|
180
|
+
if (!this.opts.filesList.map(normalizePath).includes(filename)) {
|
|
166
181
|
this._isIncluded = false;
|
|
167
182
|
return;
|
|
168
183
|
}
|
|
@@ -170,8 +185,9 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
170
185
|
},
|
|
171
186
|
visitor: { Program: {
|
|
172
187
|
enter(programPath, state) {
|
|
173
|
-
const filename = state.file.opts.filename;
|
|
174
|
-
|
|
188
|
+
const filename = state.file.opts.filename ? normalizePath(state.file.opts.filename) : void 0;
|
|
189
|
+
const dictionariesEntryPath = state.opts.dictionariesEntryPath ? normalizePath(state.opts.dictionariesEntryPath) : void 0;
|
|
190
|
+
if (state.opts.replaceDictionaryEntry && filename === dictionariesEntryPath) {
|
|
175
191
|
state._isDictEntry = true;
|
|
176
192
|
programPath.traverse({
|
|
177
193
|
ImportDeclaration(path) {
|
|
@@ -194,30 +210,46 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
194
210
|
exit(programPath, state) {
|
|
195
211
|
if (state._isDictEntry) return;
|
|
196
212
|
if (!state._isIncluded) return;
|
|
197
|
-
|
|
213
|
+
programPath.traverse({ ImportDeclaration(path) {
|
|
214
|
+
const src = path.node.source.value;
|
|
215
|
+
if (!PACKAGE_LIST.includes(src)) return;
|
|
216
|
+
state._hasValidImport = true;
|
|
217
|
+
for (const spec of path.node.specifiers) {
|
|
218
|
+
if (!t.isImportSpecifier(spec)) continue;
|
|
219
|
+
const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
220
|
+
if (isCallerName(importedName)) {
|
|
221
|
+
state._callerMap?.set(spec.local.name, importedName);
|
|
222
|
+
state._callerPackageMap?.set(spec.local.name, src);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} });
|
|
226
|
+
const packagesWithDynamicCall = /* @__PURE__ */ new Set();
|
|
227
|
+
const packagesWithFetchCall = /* @__PURE__ */ new Set();
|
|
198
228
|
programPath.traverse({ CallExpression(path) {
|
|
199
229
|
const callee = path.node.callee;
|
|
200
230
|
if (!t.isIdentifier(callee)) return;
|
|
201
231
|
if (state._callerMap?.get(callee.name) !== "useIntlayer") return;
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
else if (arg && t.isTemplateLiteral(arg) && arg.expressions.length === 0 && arg.quasis.length === 1) key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;
|
|
232
|
+
const callerPackage = state._callerPackageMap?.get(callee.name);
|
|
233
|
+
if (!callerPackage) return;
|
|
234
|
+
const key = getKeyFromArgument(path.node.arguments[0], t);
|
|
206
235
|
if (!key) return;
|
|
207
236
|
const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
|
|
208
|
-
if (dictionaryOverrideMode === "dynamic"
|
|
237
|
+
if (dictionaryOverrideMode === "dynamic") packagesWithDynamicCall.add(callerPackage);
|
|
238
|
+
else if (dictionaryOverrideMode === "fetch") packagesWithFetchCall.add(callerPackage);
|
|
209
239
|
} });
|
|
210
240
|
programPath.traverse({
|
|
211
241
|
ImportDeclaration(path) {
|
|
212
242
|
const src = path.node.source.value;
|
|
213
243
|
if (!PACKAGE_LIST.includes(src)) return;
|
|
214
|
-
state._hasValidImport = true;
|
|
215
244
|
for (const spec of path.node.specifiers) {
|
|
216
245
|
if (!t.isImportSpecifier(spec)) continue;
|
|
217
246
|
const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
218
|
-
if (
|
|
247
|
+
if (!isCallerName(importedName)) continue;
|
|
219
248
|
const importMode = state.opts.importMode;
|
|
220
|
-
const
|
|
249
|
+
const packageHasDynamicCall = packagesWithDynamicCall.has(src);
|
|
250
|
+
const packageHasFetchCall = packagesWithFetchCall.has(src);
|
|
251
|
+
const shouldUseStaticFallback = !packageHasFetchCall && shouldUseStaticSsrDynamicFallback(src, importMode === "dynamic" || packageHasDynamicCall ? "dynamic" : importMode, state.opts);
|
|
252
|
+
const shouldUseDynamicHelpers = isDynamicPackage(src) && (importMode === "fetch" || packageHasFetchCall || (importMode === "dynamic" || packageHasDynamicCall) && !shouldUseStaticFallback);
|
|
221
253
|
if (shouldUseDynamicHelpers) state._useDynamicHelpers = true;
|
|
222
254
|
let helperMap;
|
|
223
255
|
if (shouldUseDynamicHelpers) helperMap = {
|
|
@@ -235,21 +267,22 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
235
267
|
const originalImportedName = state._callerMap?.get(callee.name);
|
|
236
268
|
if (!originalImportedName) return;
|
|
237
269
|
state._hasValidImport = true;
|
|
238
|
-
const
|
|
239
|
-
let key;
|
|
240
|
-
if (arg && t.isStringLiteral(arg)) key = arg.value;
|
|
241
|
-
else if (arg && t.isTemplateLiteral(arg) && arg.expressions.length === 0 && arg.quasis.length === 1) key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;
|
|
270
|
+
const key = getKeyFromArgument(path.node.arguments[0], t);
|
|
242
271
|
if (!key) return;
|
|
272
|
+
const callerPackage = state._callerPackageMap?.get(callee.name);
|
|
243
273
|
const importMode = state.opts.importMode;
|
|
244
274
|
const isUseIntlayer = originalImportedName === "useIntlayer";
|
|
245
|
-
const useDynamicHelpers = Boolean(state._useDynamicHelpers);
|
|
246
|
-
let perCallMode = "static";
|
|
247
275
|
const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
|
|
276
|
+
const effectiveImportMode = dictionaryOverrideMode ?? importMode;
|
|
277
|
+
const packageHasFetchCall = callerPackage !== void 0 && packagesWithFetchCall.has(callerPackage);
|
|
278
|
+
const usesStaticSsrDynamicFallback = isUseIntlayer && !packageHasFetchCall && shouldUseStaticSsrDynamicFallback(callerPackage, effectiveImportMode, state.opts);
|
|
279
|
+
const useDynamicHelpers = Boolean(state._useDynamicHelpers) && !usesStaticSsrDynamicFallback;
|
|
280
|
+
let perCallMode = "static";
|
|
248
281
|
if (isUseIntlayer && useDynamicHelpers) {
|
|
249
282
|
if (dictionaryOverrideMode) perCallMode = dictionaryOverrideMode;
|
|
250
283
|
else if (importMode === "dynamic") perCallMode = "dynamic";
|
|
251
284
|
else if (importMode === "fetch") perCallMode = "fetch";
|
|
252
|
-
} else if (isUseIntlayer && !useDynamicHelpers) {
|
|
285
|
+
} else if (isUseIntlayer && !useDynamicHelpers && !usesStaticSsrDynamicFallback) {
|
|
253
286
|
if (dictionaryOverrideMode === "dynamic" || dictionaryOverrideMode === "fetch") perCallMode = dictionaryOverrideMode;
|
|
254
287
|
}
|
|
255
288
|
let ident;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-optimize.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport { getPathHash } from '@intlayer/chokidar/utils';\nimport { normalizePath } from '@intlayer/config/utils';\n\nconst PACKAGE_LIST = [\n 'intlayer',\n '@intlayer/core',\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'svelte-intlayer',\n 'vue-intlayer',\n 'angular-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n];\n\nconst CALLER_LIST = ['useIntlayer', 'getIntlayer'] as const;\n\n/**\n * Packages that support dynamic import\n */\nconst PACKAGE_LIST_DYNAMIC = [\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'preact-intlayer',\n 'vue-intlayer',\n 'solid-intlayer',\n 'svelte-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n] as const;\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n useIntlayer: 'useDictionary',\n} as const;\n\nconst DYNAMIC_IMPORT_FUNCTION = {\n useIntlayer: 'useDictionaryDynamic',\n} as const;\n\n/**\n * Options for the optimization Babel plugin\n */\nexport type OptimizePluginOptions = {\n /**\n * If false, the plugin will not apply any transformation.\n */\n optimize?: boolean;\n /**\n * The path to the dictionaries directory.\n */\n dictionariesDir: string;\n /**\n * The path to the dictionaries entry file.\n */\n dictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries entry file.\n */\n unmergedDictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries directory.\n */\n unmergedDictionariesDir: string;\n /**\n * The path to the dictionaries directory.\n */\n dynamicDictionariesDir: string;\n /**\n * The path to the dynamic dictionaries entry file.\n */\n dynamicDictionariesEntryPath: string;\n /**\n * The path to the fetch dictionaries directory.\n */\n fetchDictionariesDir: string;\n /**\n * The path to the fetch dictionaries entry file.\n */\n fetchDictionariesEntryPath: string;\n /**\n * If true, the plugin will replace the dictionary entry file with `export default {}`.\n */\n replaceDictionaryEntry: boolean;\n /**\n * If true, the plugin will activate the dynamic import of the dictionaries. It will rely on Suspense to load the dictionaries.\n */\n importMode: 'static' | 'dynamic' | 'fetch' | undefined;\n /**\n * Map of dictionary keys to their specific import mode.\n */\n dictionaryModeMap?: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n >;\n /**\n * Files list to traverse.\n */\n filesList: string[];\n};\n\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** map key → generated ident (per-file) for static imports */\n _newStaticImports?: Map<string, BabelTypes.Identifier>;\n /** map key → generated ident (per-file) for dynamic imports */\n _newDynamicImports?: Map<string, BabelTypes.Identifier>;\n /** whether the current file imported *any* intlayer package */\n _hasValidImport?: boolean;\n /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */\n _callerMap?: Map<string, (typeof CALLER_LIST)[number]>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: boolean;\n /** whether dynamic helpers are active for this file */\n _useDynamicHelpers?: boolean;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n};\n\n/**\n * Replicates the xxHash64 → Base-62 algorithm used by the SWC version\n * and prefixes an underscore so the generated identifiers never collide\n * with user-defined ones.\n */\nconst makeIdent = (\n key: string,\n t: typeof BabelTypes\n): BabelTypes.Identifier => {\n const hash = getPathHash(key);\n return t.identifier(`_${hash}`);\n};\n\nconst computeImport = (\n fromFile: string,\n dictionariesDir: string,\n dynamicDictionariesDir: string,\n fetchDictionariesDir: string,\n key: string,\n importMode: 'static' | 'dynamic' | 'fetch'\n): string => {\n let relativePath = join(dictionariesDir, `${key}.json`);\n\n if (importMode === 'fetch') {\n relativePath = join(fetchDictionariesDir, `${key}.mjs`);\n }\n\n if (importMode === 'dynamic') {\n relativePath = join(dynamicDictionariesDir, `${key}.mjs`);\n }\n\n let rel = relative(dirname(fromFile), relativePath);\n\n // Fix windows path\n rel = normalizePath(rel);\n\n // Fix relative path\n if (!rel.startsWith('./') && !rel.startsWith('../')) {\n rel = `./${rel}`;\n }\n\n return rel;\n};\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()` and `getIntlayer()` from various Intlayer\n * packages into optimized dictionary access patterns, automatically importing the required\n * dictionary files based on the configured import mode.\n *\n * ## Supported Input Patterns\n *\n * The plugin recognizes these function calls:\n *\n * ```ts\n * // useIntlayer\n * import { useIntlayer } from 'react-intlayer';\n * import { useIntlayer } from 'next-intlayer';\n *\n * // getIntlayer\n * import { getIntlayer } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * ```\n *\n * ## Transformation Modes\n *\n * ### Static Mode (default: `importMode = \"static\"`)\n *\n * Imports JSON dictionaries directly and replaces function calls with dictionary access:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import { useDictionary as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash);\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Dynamic Mode (`importMode = \"dynamic\"`)\n *\n * Uses dynamic dictionary loading with Suspense support:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Live Mode (`importMode = \"live\"`)\n *\n * Uses live-based dictionary loading for remote dictionaries:\n *\n * **Output if `dictionaryModeMap` includes the key with \"live\" value:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_fetch, \"app\");\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * > If `dictionaryModeMap` does not include the key with \"live\" value, the plugin will fallback to the dynamic impor\n *\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n */\nexport const intlayerOptimizeBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-transform',\n\n pre() {\n this._newStaticImports = new Map();\n this._newDynamicImports = new Map();\n this._callerMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = false;\n this._useDynamicHelpers = false;\n\n // If optimize is false, skip processing entirely\n if (this.opts.optimize === false) {\n this._isIncluded = false;\n return;\n }\n\n // If filesList is provided, check if current file is included\n const filename = this.file.opts.filename;\n if (this.opts.filesList && filename) {\n const isIncluded = this.opts.filesList.includes(filename);\n\n if (!isIncluded) {\n // Force _isIncluded to false to skip processing\n this._isIncluded = false;\n return;\n }\n }\n },\n\n visitor: {\n /* If this file *is* the dictionaries entry, short-circuit: export {} */\n Program: {\n enter(programPath, state) {\n // Safe access to filename\n const filename = state.file.opts.filename;\n\n // Check if this is the correct file to transform\n\n if (\n state.opts.replaceDictionaryEntry &&\n filename === state.opts.dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n\n // Traverse the program to surgically remove/edit specific parts\n programPath.traverse({\n // Remove all import statements (cleaning up 'sssss.json')\n ImportDeclaration(path) {\n path.remove();\n },\n\n // Find the variable definition and empty the object\n VariableDeclarator(path) {\n // We look for: const x = { ... }\n\n if (t.isObjectExpression(path.node.init)) {\n // Set the object properties to an empty array: {}\n path.node.init.properties = [];\n }\n },\n });\n\n // (Optional) Stop other plugins from processing this file further if needed\n // programPath.stop();\n }\n },\n\n /**\n * After full traversal, process imports and call expressions, then inject the JSON dictionary imports.\n *\n * We do the transformation in Program.exit (via a manual traverse) rather than using\n * top-level ImportDeclaration/CallExpression visitors. This ensures that if another plugin\n * (like babel-plugin-intlayer-extract) adds new useIntlayer calls in its Program.exit,\n * we will see and transform them here because our Program.exit runs after theirs.\n */\n exit(programPath, state) {\n if (state._isDictEntry) return; // nothing else to do – already replaced\n\n if (!state._isIncluded) return; // early-out if file is not included\n\n // Manual traversal to process imports and call expressions\n // This runs AFTER all other plugins' visitors have completed\n\n // Pre-pass to determine if we should use dynamic helpers\n let fileHasDynamicCall = false;\n programPath.traverse({\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (originalImportedName !== 'useIntlayer') return;\n\n const arg = path.node.arguments[0];\n let key: string | undefined;\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;\n }\n if (!key) return;\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n fileHasDynamicCall = true;\n }\n },\n });\n\n programPath.traverse({\n /* Inspect every intlayer import */\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n // Mark that we do import from an intlayer package in this file\n state._hasValidImport = true;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (CALLER_LIST.includes(importedName as any)) {\n state._callerMap?.set(\n spec.local.name,\n importedName as (typeof CALLER_LIST)[number]\n );\n }\n\n const importMode = state.opts.importMode;\n // Determine whether this import should use the dynamic helpers.\n const shouldUseDynamicHelpers =\n (importMode === 'dynamic' ||\n importMode === 'fetch' ||\n fileHasDynamicCall) &&\n PACKAGE_LIST_DYNAMIC.includes(src as any);\n\n // Remember for later (CallExpression) whether we are using the dynamic helpers\n\n if (shouldUseDynamicHelpers) {\n state._useDynamicHelpers = true;\n }\n\n let helperMap: Record<string, string>;\n\n if (shouldUseDynamicHelpers) {\n // Use dynamic helpers for useIntlayer when dynamic mode is enabled\n helperMap = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n } as Record<string, string>;\n } else {\n // Use static helpers by default\n helperMap = STATIC_IMPORT_FUNCTION as Record<string, string>;\n }\n\n const newIdentifier = helperMap[importedName];\n\n // Only rewrite when we actually have a mapping for the imported\n // specifier (ignore unrelated named imports).\n\n if (newIdentifier) {\n // Keep the local alias intact (so calls remain `useIntlayer` /\n // `getIntlayer`), but rewrite the imported identifier so it\n // points to our helper implementation.\n spec.imported = t.identifier(newIdentifier);\n }\n }\n },\n\n /* Replace calls: useIntlayer(\"foo\") → useDictionary(_hash) or useDictionaryDynamic(_hash, \"foo\") */\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (!originalImportedName) return;\n\n // Ensure we ultimately emit helper imports for files that *invoke*\n // the hooks, even if they didn't import them directly (edge cases with\n // re-exports).\n state._hasValidImport = true;\n\n const arg = path.node.arguments[0];\n let key: string | undefined;\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n key = arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;\n }\n if (!key) return;\n\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const useDynamicHelpers = Boolean(state._useDynamicHelpers);\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'\n let perCallMode: 'static' | 'dynamic' | 'fetch' = 'static';\n\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (isUseIntlayer && useDynamicHelpers) {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic') {\n perCallMode = 'dynamic';\n } else if (importMode === 'fetch') {\n perCallMode = 'fetch';\n }\n } else if (isUseIntlayer && !useDynamicHelpers) {\n // If dynamic helpers are NOT active (global mode is static),\n // we STILL might want to force dynamic/live for this specific call\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n perCallMode = dictionaryOverrideMode;\n }\n }\n\n let ident: BabelTypes.Identifier;\n\n if (perCallMode === 'fetch') {\n // Use fetch dictionaries entry (live mode for selected keys)\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_fetch`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Helper: first argument is the dictionary entry, second is the key\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else if (perCallMode === 'dynamic') {\n // Use dynamic dictionaries entry\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n // Create a unique identifier for dynamic imports by appending a suffix\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_dyn`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Dynamic helper: first argument is the dictionary, second is the key.\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else {\n // Use static imports for getIntlayer or useIntlayer when not using dynamic helpers\n let staticIdent = state._newStaticImports?.get(key);\n\n if (!staticIdent) {\n staticIdent = makeIdent(key, t);\n state._newStaticImports?.set(key, staticIdent);\n }\n ident = staticIdent;\n\n // Static helper (useDictionary / getDictionary): replace key with ident.\n // After the splice above the key is always at index 0.\n path.node.arguments[0] = t.identifier(ident.name);\n }\n },\n });\n\n // Early-out if we touched nothing\n\n if (!state._hasValidImport) return;\n\n const file = state.file.opts.filename!;\n const dictionariesDir = state.opts.dictionariesDir;\n const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;\n const fetchDictionariesDir = state.opts.fetchDictionariesDir;\n const imports: BabelTypes.ImportDeclaration[] = [];\n\n // Generate static JSON imports (getIntlayer always uses JSON dictionaries)\n for (const [key, ident] of state._newStaticImports!) {\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static'\n );\n\n const importDeclarationNode = t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n );\n\n // Add 'type: json' attribute for JSON files\n importDeclarationNode.attributes = [\n t.importAttribute(t.identifier('type'), t.stringLiteral('json')),\n ];\n\n imports.push(importDeclarationNode);\n }\n\n // Generate dynamic/fetch imports (for useIntlayer when using dynamic/live helpers)\n for (const [key, ident] of state._newDynamicImports!) {\n const modeForThisIdent: 'dynamic' | 'fetch' = ident.name.endsWith(\n '_fetch'\n )\n ? 'fetch'\n : 'dynamic';\n\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n modeForThisIdent\n );\n imports.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n )\n );\n }\n\n if (!imports.length) return;\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n const bodyPaths = programPath.get(\n 'body'\n ) as NodePath<BabelTypes.Statement>[];\n let insertPos = 0;\n for (const stmtPath of bodyPaths) {\n const stmt = stmtPath.node;\n\n if (\n t.isExpressionStatement(stmt) &&\n t.isStringLiteral(stmt.expression) &&\n !stmt.expression.value.startsWith('import') &&\n !stmt.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n programPath.node.body.splice(insertPos, 0, ...imports);\n },\n },\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-optimize.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport { getPathHash } from '@intlayer/chokidar/utils';\nimport { normalizePath } from '@intlayer/config/utils';\n\nconst PACKAGE_LIST = [\n 'intlayer',\n '@intlayer/core',\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'svelte-intlayer',\n 'vue-intlayer',\n 'angular-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n];\n\nconst CALLER_LIST = ['useIntlayer', 'getIntlayer'] as const;\n\n/**\n * Packages that support dynamic import\n */\nconst PACKAGE_LIST_DYNAMIC = [\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'preact-intlayer',\n 'vue-intlayer',\n 'solid-intlayer',\n 'svelte-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'vanilla-intlayer',\n] as const;\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n useIntlayer: 'useDictionary',\n} as const;\n\nconst DYNAMIC_IMPORT_FUNCTION = {\n useIntlayer: 'useDictionaryDynamic',\n} as const;\n\ntype CallerName = (typeof CALLER_LIST)[number];\ntype ImportMode = 'static' | 'dynamic' | 'fetch';\n\n/**\n * Packages whose SSR dynamic helper should render synchronously with a static\n * dictionary. Solid streaming SSR can hydrate static output reliably, while\n * its dynamic resource path either suspends during hydration or serializes the\n * full dictionary into HTML.\n */\nconst PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK = new Set<string>(['solid-intlayer']);\n\n/**\n * Options for the optimization Babel plugin\n */\nexport type OptimizePluginOptions = {\n /**\n * If false, the plugin will not apply any transformation.\n */\n optimize?: boolean;\n /**\n * The path to the dictionaries directory.\n */\n dictionariesDir: string;\n /**\n * The path to the dictionaries entry file.\n */\n dictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries entry file.\n */\n unmergedDictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries directory.\n */\n unmergedDictionariesDir: string;\n /**\n * The path to the dictionaries directory.\n */\n dynamicDictionariesDir: string;\n /**\n * The path to the dynamic dictionaries entry file.\n */\n dynamicDictionariesEntryPath: string;\n /**\n * The path to the fetch dictionaries directory.\n */\n fetchDictionariesDir: string;\n /**\n * The path to the fetch dictionaries entry file.\n */\n fetchDictionariesEntryPath: string;\n /**\n * If true, the plugin will replace the dictionary entry file with `export default {}`.\n */\n replaceDictionaryEntry: boolean;\n /**\n * If true, the plugin will activate the dynamic import of the dictionaries. It will rely on Suspense to load the dictionaries.\n */\n importMode: 'static' | 'dynamic' | 'fetch' | undefined;\n /**\n * Map of dictionary keys to their specific import mode.\n */\n dictionaryModeMap?: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n >;\n /**\n * Files list to traverse.\n */\n filesList: string[];\n /**\n * Whether the current transform is for an SSR bundle.\n */\n isServer?: boolean;\n};\n\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** map key → generated ident (per-file) for static imports */\n _newStaticImports?: Map<string, BabelTypes.Identifier>;\n /** map key → generated ident (per-file) for dynamic imports */\n _newDynamicImports?: Map<string, BabelTypes.Identifier>;\n /** whether the current file imported *any* intlayer package */\n _hasValidImport?: boolean;\n /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */\n _callerMap?: Map<string, (typeof CALLER_LIST)[number]>;\n /** map from local identifier name to the intlayer package it was imported from */\n _callerPackageMap?: Map<string, string>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: boolean;\n /** whether dynamic helpers are active for this file */\n _useDynamicHelpers?: boolean;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n};\n\n/**\n * Replicates the xxHash64 → Base-62 algorithm used by the SWC version\n * and prefixes an underscore so the generated identifiers never collide\n * with user-defined ones.\n */\nconst makeIdent = (\n key: string,\n t: typeof BabelTypes\n): BabelTypes.Identifier => {\n const hash = getPathHash(key);\n return t.identifier(`_${hash}`);\n};\n\nconst computeImport = (\n fromFile: string,\n dictionariesDir: string,\n dynamicDictionariesDir: string,\n fetchDictionariesDir: string,\n key: string,\n importMode: 'static' | 'dynamic' | 'fetch'\n): string => {\n let relativePath = join(dictionariesDir, `${key}.json`);\n\n if (importMode === 'fetch') {\n relativePath = join(fetchDictionariesDir, `${key}.mjs`);\n }\n\n if (importMode === 'dynamic') {\n relativePath = join(dynamicDictionariesDir, `${key}.mjs`);\n }\n\n let rel = relative(dirname(fromFile), relativePath);\n\n // Fix windows path\n rel = normalizePath(rel);\n\n // Fix relative path\n if (!rel.startsWith('./') && !rel.startsWith('../')) {\n rel = `./${rel}`;\n }\n\n return rel;\n};\n\nconst getKeyFromArgument = (\n arg: BabelTypes.Node | null | undefined,\n t: typeof BabelTypes\n): string | undefined => {\n if (arg && t.isStringLiteral(arg)) {\n return arg.value;\n }\n\n if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n return arg.quasis[0]?.value.cooked ?? arg.quasis[0]?.value.raw;\n }\n\n return undefined;\n};\n\nconst isCallerName = (name: string): name is CallerName =>\n CALLER_LIST.includes(name as CallerName);\n\nconst isDynamicPackage = (\n packageName: string\n): packageName is (typeof PACKAGE_LIST_DYNAMIC)[number] =>\n PACKAGE_LIST_DYNAMIC.includes(\n packageName as (typeof PACKAGE_LIST_DYNAMIC)[number]\n );\n\nconst shouldUseStaticSsrDynamicFallback = (\n callerPackage: string | undefined,\n importMode: ImportMode | undefined,\n opts: OptimizePluginOptions\n): boolean =>\n opts.isServer === true &&\n importMode === 'dynamic' &&\n callerPackage !== undefined &&\n PACKAGE_SSR_DYNAMIC_STATIC_FALLBACK.has(callerPackage);\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()` and `getIntlayer()` from various Intlayer\n * packages into optimized dictionary access patterns, automatically importing the required\n * dictionary files based on the configured import mode.\n *\n * ## Supported Input Patterns\n *\n * The plugin recognizes these function calls:\n *\n * ```ts\n * // useIntlayer\n * import { useIntlayer } from 'react-intlayer';\n * import { useIntlayer } from 'next-intlayer';\n *\n * // getIntlayer\n * import { getIntlayer } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * ```\n *\n * ## Transformation Modes\n *\n * ### Static Mode (default: `importMode = \"static\"`)\n *\n * Imports JSON dictionaries directly and replaces function calls with dictionary access:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import { useDictionary as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash);\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Dynamic Mode (`importMode = \"dynamic\"`)\n *\n * Uses dynamic dictionary loading with Suspense support:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Fetch Mode (`importMode = \"fetch\"`)\n *\n * Uses fetch-based dictionary loading for remote dictionaries:\n *\n * **Output if `dictionaryModeMap` includes the key with \"fetch\" value:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_fetch, \"app\");\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * > If `dictionaryModeMap` does not include the key with \"fetch\" value, the plugin will fallback to the dynamic import mode.\n *\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n */\nexport const intlayerOptimizeBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-transform',\n\n pre() {\n this._newStaticImports = new Map();\n this._newDynamicImports = new Map();\n this._callerMap = new Map();\n this._callerPackageMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = false;\n this._useDynamicHelpers = false;\n\n // If optimize is false, skip processing entirely\n if (this.opts.optimize === false) {\n this._isIncluded = false;\n return;\n }\n\n // If filesList is provided, check if current file is included\n const filename = this.file.opts.filename\n ? normalizePath(this.file.opts.filename)\n : undefined;\n if (this.opts.filesList && filename) {\n const filesList = this.opts.filesList.map(normalizePath);\n const isIncluded = filesList.includes(filename);\n\n if (!isIncluded) {\n // Force _isIncluded to false to skip processing\n this._isIncluded = false;\n return;\n }\n }\n },\n\n visitor: {\n /* If this file *is* the dictionaries entry, short-circuit: export {} */\n Program: {\n enter(programPath, state) {\n // Safe access to filename\n const filename = state.file.opts.filename\n ? normalizePath(state.file.opts.filename)\n : undefined;\n const dictionariesEntryPath = state.opts.dictionariesEntryPath\n ? normalizePath(state.opts.dictionariesEntryPath)\n : undefined;\n\n // Check if this is the correct file to transform\n\n if (\n state.opts.replaceDictionaryEntry &&\n filename === dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n\n // Traverse the program to surgically remove/edit specific parts\n programPath.traverse({\n // Remove all import statements (cleaning up 'sssss.json')\n ImportDeclaration(path) {\n path.remove();\n },\n\n // Find the variable definition and empty the object\n VariableDeclarator(path) {\n // We look for: const x = { ... }\n\n if (t.isObjectExpression(path.node.init)) {\n // Set the object properties to an empty array: {}\n path.node.init.properties = [];\n }\n },\n });\n\n // (Optional) Stop other plugins from processing this file further if needed\n // programPath.stop();\n }\n },\n\n /**\n * After full traversal, process imports and call expressions, then inject the JSON dictionary imports.\n *\n * We do the transformation in Program.exit (via a manual traverse) rather than using\n * top-level ImportDeclaration/CallExpression visitors. This ensures that if another plugin\n * (like babel-plugin-intlayer-extract) adds new useIntlayer calls in its Program.exit,\n * we will see and transform them here because our Program.exit runs after theirs.\n */\n exit(programPath, state) {\n if (state._isDictEntry) return; // nothing else to do – already replaced\n\n if (!state._isIncluded) return; // early-out if file is not included\n\n // Manual traversal to process imports and call expressions\n // This runs AFTER all other plugins' visitors have completed\n programPath.traverse({\n /* Inspect every intlayer import before deciding helper rewrites. */\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n state._hasValidImport = true;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (isCallerName(importedName)) {\n state._callerMap?.set(spec.local.name, importedName);\n state._callerPackageMap?.set(spec.local.name, src);\n }\n }\n },\n });\n\n // Pre-pass to determine if dictionary-level overrides require the\n // dynamic helper in an otherwise static file.\n const packagesWithDynamicCall = new Set<string>();\n const packagesWithFetchCall = new Set<string>();\n programPath.traverse({\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (originalImportedName !== 'useIntlayer') return;\n\n const callerPackage = state._callerPackageMap?.get(callee.name);\n if (!callerPackage) return;\n\n const key = getKeyFromArgument(path.node.arguments[0], t);\n if (!key) return;\n\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (dictionaryOverrideMode === 'dynamic') {\n packagesWithDynamicCall.add(callerPackage);\n } else if (dictionaryOverrideMode === 'fetch') {\n packagesWithFetchCall.add(callerPackage);\n }\n },\n });\n\n programPath.traverse({\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (!isCallerName(importedName)) continue;\n\n const importMode = state.opts.importMode;\n // Determine whether this import should use the dynamic helpers.\n const packageHasDynamicCall = packagesWithDynamicCall.has(src);\n const packageHasFetchCall = packagesWithFetchCall.has(src);\n // A package import can be rewritten to only one helper. Fetch\n // overrides therefore keep the dynamic helper for every\n // useIntlayer call from that package in this file.\n const shouldUseStaticFallback =\n !packageHasFetchCall &&\n shouldUseStaticSsrDynamicFallback(\n src,\n importMode === 'dynamic' || packageHasDynamicCall\n ? 'dynamic'\n : importMode,\n state.opts\n );\n const shouldUseDynamicHelpers =\n isDynamicPackage(src) &&\n (importMode === 'fetch' ||\n packageHasFetchCall ||\n ((importMode === 'dynamic' || packageHasDynamicCall) &&\n !shouldUseStaticFallback));\n\n // Remember for later (CallExpression) whether we are using the dynamic helpers\n\n if (shouldUseDynamicHelpers) {\n state._useDynamicHelpers = true;\n }\n\n let helperMap: Record<string, string>;\n\n if (shouldUseDynamicHelpers) {\n // Use dynamic helpers for useIntlayer when dynamic mode is enabled\n helperMap = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n } as Record<string, string>;\n } else {\n // Use static helpers by default\n helperMap = STATIC_IMPORT_FUNCTION as Record<string, string>;\n }\n\n const newIdentifier = helperMap[importedName];\n\n if (newIdentifier) {\n // Keep the local alias intact (so calls remain `useIntlayer` /\n // `getIntlayer`), but rewrite the imported identifier so it\n // points to our helper implementation.\n spec.imported = t.identifier(newIdentifier);\n }\n }\n },\n\n /* Replace calls: useIntlayer(\"foo\") → useDictionary(_hash) or useDictionaryDynamic(_hash, \"foo\") */\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (!originalImportedName) return;\n\n // Ensure we ultimately emit helper imports for files that *invoke*\n // the hooks, even if they didn't import them directly (edge cases with\n // re-exports).\n state._hasValidImport = true;\n\n const key = getKeyFromArgument(path.node.arguments[0], t);\n if (!key) return;\n\n const callerPackage = state._callerPackageMap?.get(callee.name);\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n const effectiveImportMode = dictionaryOverrideMode ?? importMode;\n const packageHasFetchCall =\n callerPackage !== undefined &&\n packagesWithFetchCall.has(callerPackage);\n const usesStaticSsrDynamicFallback =\n isUseIntlayer &&\n !packageHasFetchCall &&\n shouldUseStaticSsrDynamicFallback(\n callerPackage,\n effectiveImportMode,\n state.opts\n );\n const useDynamicHelpers =\n Boolean(state._useDynamicHelpers) &&\n !usesStaticSsrDynamicFallback;\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'\n let perCallMode: ImportMode = 'static';\n\n if (isUseIntlayer && useDynamicHelpers) {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic') {\n perCallMode = 'dynamic';\n } else if (importMode === 'fetch') {\n perCallMode = 'fetch';\n }\n } else if (\n isUseIntlayer &&\n !useDynamicHelpers &&\n !usesStaticSsrDynamicFallback\n ) {\n // If dynamic helpers are NOT active (global mode is static),\n // we STILL might want to force dynamic/fetch for this specific call\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n perCallMode = dictionaryOverrideMode;\n }\n }\n\n let ident: BabelTypes.Identifier;\n\n if (perCallMode === 'fetch') {\n // Use fetch dictionaries entry for selected keys\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_fetch`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Helper: first argument is the dictionary entry, second is the key\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else if (perCallMode === 'dynamic') {\n // Use dynamic dictionaries entry\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n // Create a unique identifier for dynamic imports by appending a suffix\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_dyn`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Dynamic helper: first argument is the dictionary, second is the key.\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else {\n // Use static imports for getIntlayer or useIntlayer when not using dynamic helpers\n let staticIdent = state._newStaticImports?.get(key);\n\n if (!staticIdent) {\n staticIdent = makeIdent(key, t);\n state._newStaticImports?.set(key, staticIdent);\n }\n ident = staticIdent;\n\n // Static helper (useDictionary / getDictionary): replace key with ident.\n // After the splice above the key is always at index 0.\n path.node.arguments[0] = t.identifier(ident.name);\n }\n },\n });\n\n // Early-out if we touched nothing\n\n if (!state._hasValidImport) return;\n\n const file = state.file.opts.filename!;\n const dictionariesDir = state.opts.dictionariesDir;\n const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;\n const fetchDictionariesDir = state.opts.fetchDictionariesDir;\n const imports: BabelTypes.ImportDeclaration[] = [];\n\n // Generate static JSON imports (getIntlayer always uses JSON dictionaries)\n for (const [key, ident] of state._newStaticImports!) {\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static'\n );\n\n const importDeclarationNode = t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n );\n\n // Add 'type: json' attribute for JSON files\n importDeclarationNode.attributes = [\n t.importAttribute(t.identifier('type'), t.stringLiteral('json')),\n ];\n\n imports.push(importDeclarationNode);\n }\n\n // Generate dynamic/fetch imports (for useIntlayer when using dynamic/fetch helpers)\n for (const [key, ident] of state._newDynamicImports!) {\n const modeForThisIdent: 'dynamic' | 'fetch' = ident.name.endsWith(\n '_fetch'\n )\n ? 'fetch'\n : 'dynamic';\n\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n modeForThisIdent\n );\n imports.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n )\n );\n }\n\n if (!imports.length) return;\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n const bodyPaths = programPath.get(\n 'body'\n ) as NodePath<BabelTypes.Statement>[];\n let insertPos = 0;\n for (const stmtPath of bodyPaths) {\n const stmt = stmtPath.node;\n\n if (\n t.isExpressionStatement(stmt) &&\n t.isStringLiteral(stmt.expression) &&\n !stmt.expression.value.startsWith('import') &&\n !stmt.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n programPath.node.body.splice(insertPos, 0, ...imports);\n },\n },\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"mappings":";;;;;;;;KAcY,aAAA;EACV,aAAA;EACA,QAAA;EACA,OAAA,EAAS,MAAA;EACT,MAAA,EAAQ,MAAA;AAAA;AAAA,KAGE,oBAAA;EACV,WAAA,GAAc,WAAA;EACd,SAAA;EACA,OAAA;EAEA,aAAA,IAAiB,IAAA;EACjB,aAAA,EAAe,cAAA;EATD;;AAGhB;;;EAYE,SAAA,IAAa,MAAA,EAAQ,aAAA,YAAyB,OAAA;EAN/B;;;EAUf,MAAA,GAAS,eAAA;AAAA;AAAA,KAGN,KAAA,GAAQ,UAAA;EAAe,IAAA,EAAM,oBAAA;AAAA;;;;;;;;;;;;;;;AAFhC;;;cAqBW,0BAAA,GAA8B,MAAA;EACzC,KAAA,SAAc,UAAA;AAAA,MACZ,SAAA,CAAU,KAAA"}
|
|
@@ -59,13 +59,18 @@ type OptimizePluginOptions = {
|
|
|
59
59
|
* Files list to traverse.
|
|
60
60
|
*/
|
|
61
61
|
filesList: string[];
|
|
62
|
+
/**
|
|
63
|
+
* Whether the current transform is for an SSR bundle.
|
|
64
|
+
*/
|
|
65
|
+
isServer?: boolean;
|
|
62
66
|
};
|
|
63
67
|
type State = PluginPass & {
|
|
64
68
|
opts: OptimizePluginOptions; /** map key → generated ident (per-file) for static imports */
|
|
65
69
|
_newStaticImports?: Map<string, BabelTypes.Identifier>; /** map key → generated ident (per-file) for dynamic imports */
|
|
66
70
|
_newDynamicImports?: Map<string, BabelTypes.Identifier>; /** whether the current file imported *any* intlayer package */
|
|
67
71
|
_hasValidImport?: boolean; /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */
|
|
68
|
-
_callerMap?: Map<string, (typeof CALLER_LIST)[number]>; /**
|
|
72
|
+
_callerMap?: Map<string, (typeof CALLER_LIST)[number]>; /** map from local identifier name to the intlayer package it was imported from */
|
|
73
|
+
_callerPackageMap?: Map<string, string>; /** whether the current file *is* the dictionaries entry file */
|
|
69
74
|
_isDictEntry?: boolean; /** whether dynamic helpers are active for this file */
|
|
70
75
|
_useDynamicHelpers?: boolean; /** whether the current file is included in the filesList */
|
|
71
76
|
_isIncluded?: boolean;
|
|
@@ -125,11 +130,11 @@ type State = PluginPass & {
|
|
|
125
130
|
* const content2 = getIntlayer(_dicHash);
|
|
126
131
|
* ```
|
|
127
132
|
*
|
|
128
|
-
* ###
|
|
133
|
+
* ### Fetch Mode (`importMode = "fetch"`)
|
|
129
134
|
*
|
|
130
|
-
* Uses
|
|
135
|
+
* Uses fetch-based dictionary loading for remote dictionaries:
|
|
131
136
|
*
|
|
132
|
-
* **Output if `dictionaryModeMap` includes the key with "
|
|
137
|
+
* **Output if `dictionaryModeMap` includes the key with "fetch" value:**
|
|
133
138
|
* ```ts
|
|
134
139
|
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
135
140
|
* import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';
|
|
@@ -140,7 +145,7 @@ type State = PluginPass & {
|
|
|
140
145
|
* const content2 = getIntlayer(_dicHash);
|
|
141
146
|
* ```
|
|
142
147
|
*
|
|
143
|
-
* > If `dictionaryModeMap` does not include the key with "
|
|
148
|
+
* > If `dictionaryModeMap` does not include the key with "fetch" value, the plugin will fallback to the dynamic import mode.
|
|
144
149
|
*
|
|
145
150
|
* ```ts
|
|
146
151
|
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-optimize.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"mappings":";;;;cAwBM,WAAA;;AAtB0C;;
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-optimize.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"mappings":";;;;cAwBM,WAAA;;AAtB0C;;KAkEpC,qBAAA;EA5C+C;;AA4C3D;EAIE,QAAA;;;;EAIA,eAAA;EAIA;;;EAAA,qBAAA;EAgBA;;;EAZA,6BAAA;EA4BA;;;EAxBA,uBAAA;EAuCA;;;EAnCA,sBAAA;EAsCQ;;;EAlCR,4BAAA;EAqCgC;;;EAjChC,oBAAA;EAuCiC;;;EAnCjC,0BAAA;EAqCuB;;;EAjCvB,sBAAA;EAyBA;;;EArBA,UAAA;EAuBA;;;EAnBA,iBAAA,GAAoB,MAAA;EAqBpB;;;EAdA,SAAA;EAkBA;;;EAdA,QAAA;AAAA;AAAA,KAGG,KAAA,GAAQ,UAAA;EACX,IAAA,EAAM,qBAAA,EAyLK;EAvLX,iBAAA,GAAoB,GAAA,SAAY,UAAA,CAAW,UAAA;EAE3C,kBAAA,GAAqB,GAAA,SAAY,UAAA,CAAW,UAAA,GAuLhC;EArLZ,eAAA,YAqLW;EAnLX,UAAA,GAAa,GAAA,iBAAoB,WAAA,YAkLjC;EAhLA,iBAAA,GAAoB,GAAA,kBA+KsB;EA7K1C,YAAA,YA+KY;EA7KZ,kBAAA,YA6KiB;EA3KjB,WAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyKW,2BAAA,GAA+B,KAAA;EAC1C,KAAA,SAAc,UAAA;AAAA,MACZ,SAAA,CAAU,KAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/babel",
|
|
3
|
-
"version": "8.12.
|
|
3
|
+
"version": "8.12.4-canary.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A Babel plugin for Intlayer that transforms declaration files and provides internationalization features during the build process according to the Intlayer configuration.",
|
|
6
6
|
"keywords": [
|
|
@@ -81,12 +81,12 @@
|
|
|
81
81
|
"@babel/plugin-syntax-jsx": "7.29.7",
|
|
82
82
|
"@babel/traverse": "7.29.7",
|
|
83
83
|
"@babel/types": "7.29.7",
|
|
84
|
-
"@intlayer/chokidar": "8.12.
|
|
85
|
-
"@intlayer/config": "8.12.
|
|
86
|
-
"@intlayer/core": "8.12.
|
|
87
|
-
"@intlayer/dictionaries-entry": "8.12.
|
|
88
|
-
"@intlayer/types": "8.12.
|
|
89
|
-
"@intlayer/unmerged-dictionaries-entry": "8.12.
|
|
84
|
+
"@intlayer/chokidar": "8.12.4-canary.0",
|
|
85
|
+
"@intlayer/config": "8.12.4-canary.0",
|
|
86
|
+
"@intlayer/core": "8.12.4-canary.0",
|
|
87
|
+
"@intlayer/dictionaries-entry": "8.12.4-canary.0",
|
|
88
|
+
"@intlayer/types": "8.12.4-canary.0",
|
|
89
|
+
"@intlayer/unmerged-dictionaries-entry": "8.12.4-canary.0",
|
|
90
90
|
"@types/babel__core": "7.20.5",
|
|
91
91
|
"@types/babel__generator": "7.27.0",
|
|
92
92
|
"@types/babel__traverse": "7.28.0"
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"vitest": "4.1.8"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@intlayer/svelte-compiler": "8.12.
|
|
108
|
-
"@intlayer/vue-compiler": "8.12.
|
|
107
|
+
"@intlayer/svelte-compiler": "8.12.4-canary.0",
|
|
108
|
+
"@intlayer/vue-compiler": "8.12.4-canary.0"
|
|
109
109
|
},
|
|
110
110
|
"peerDependenciesMeta": {
|
|
111
111
|
"@intlayer/svelte-compiler": {
|