@intlayer/babel 9.2.0 → 9.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -24
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +32 -0
- package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs +35 -15
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-purge.cjs +161 -16
- package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs +45 -1
- package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
- package/dist/cjs/babelParser.cjs.map +1 -1
- package/dist/cjs/extractContent/babelProcessor.cjs +50 -49
- package/dist/cjs/extractContent/babelProcessor.cjs.map +1 -1
- package/dist/cjs/extractContent/contentWriter.cjs +3 -2
- package/dist/cjs/extractContent/contentWriter.cjs.map +1 -1
- package/dist/cjs/extractContent/extractContent.cjs +4 -2
- package/dist/cjs/extractContent/extractContent.cjs.map +1 -1
- package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/constants.cjs +0 -1
- package/dist/cjs/extractContent/utils/constants.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/detectPackageName.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs +5 -3
- package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/generateKey.cjs +0 -1
- package/dist/cjs/extractContent/utils/generateKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/shouldExtract.cjs +0 -1
- package/dist/cjs/extractContent/utils/shouldExtract.cjs.map +1 -1
- package/dist/cjs/extractScriptBlocks.cjs.map +1 -1
- package/dist/cjs/getExtractPluginOptions.cjs +4 -2
- package/dist/cjs/getExtractPluginOptions.cjs.map +1 -1
- package/dist/cjs/getOptimizePluginOptions.cjs +2 -0
- package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
- package/dist/cjs/getPurgePluginOptions.cjs +3 -0
- package/dist/cjs/getPurgePluginOptions.cjs.map +1 -1
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/transformers.cjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-field-rename.mjs +32 -1
- package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +35 -15
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-purge.mjs +160 -18
- package/dist/esm/babel-plugin-intlayer-purge.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs +45 -1
- package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
- package/dist/esm/extractContent/babelProcessor.mjs +50 -49
- package/dist/esm/extractContent/babelProcessor.mjs.map +1 -1
- package/dist/esm/extractContent/contentWriter.mjs +3 -2
- package/dist/esm/extractContent/contentWriter.mjs.map +1 -1
- package/dist/esm/extractContent/extractContent.mjs +4 -2
- package/dist/esm/extractContent/extractContent.mjs.map +1 -1
- package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs +5 -3
- package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs.map +1 -1
- package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs.map +1 -1
- package/dist/esm/getExtractPluginOptions.mjs +4 -2
- package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
- package/dist/esm/getOptimizePluginOptions.mjs +2 -0
- package/dist/esm/getOptimizePluginOptions.mjs.map +1 -1
- package/dist/esm/getPurgePluginOptions.mjs +3 -0
- package/dist/esm/getPurgePluginOptions.mjs.map +1 -1
- package/dist/esm/index.mjs +4 -4
- package/dist/esm/transformers.mjs.map +1 -1
- package/dist/types/babel-plugin-intlayer-field-rename.d.ts +29 -1
- package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts +15 -0
- package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-purge.d.ts +36 -1
- package/dist/types/babel-plugin-intlayer-purge.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts +30 -1
- package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
- package/dist/types/getOptimizePluginOptions.d.ts.map +1 -1
- package/dist/types/getPurgePluginOptions.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/transformers.d.ts +2 -2
- package/dist/types/transformers.d.ts.map +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-optimize.cjs","names":["getNormalizedFilesListSet"],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObject, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n type CallerDescriptor,\n getRewritableCallers,\n} from '@intlayer/config/callers';\nimport { normalizePath } from '@intlayer/config/utils';\nimport { getPathHash } from '@intlayer/engine/utils';\nimport { getNormalizedFilesListSet } from './normalizedFilesList';\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/** Import rename table applied when the helper plan for a package is `dynamic`. */\nconst DYNAMIC_HELPER_MAP: Record<string, string> = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n};\n\n/**\n * Packages whose SSR-static `useDictionary` lives in a `/server` subpath\n * because it differs from the root one. Solid's reserves one hydration\n * resource slot so hydration ids stay aligned with the client's\n * `useDictionaryDynamic`; for other frameworks the root `useDictionary` is\n * already the correct SSR-static implementation.\n */\nconst SSR_STATIC_IMPORT_SOURCE: Partial<Record<string, string>> = {\n 'solid-intlayer': 'solid-intlayer/server',\n};\n\ntype CallerName = (typeof CALLER_LIST)[number];\ntype ImportMode = 'static' | 'dynamic' | 'fetch';\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 * Compat-adapter caller descriptors injected by the compat packages'\n * bundler plugins (e.g. `@intlayer/react-i18next/plugin`).\n *\n * Callers carrying `staticReplacement` / `dynamicReplacement` are rewritten\n * the same way as native `useIntlayer` calls: the namespace string argument\n * is replaced by a pre-imported dictionary object and the import specifier\n * is re-pointed to the dictionary-accepting variant, e.g.\n * `useTranslation('about')` → `useDictionary(_dictHash)`.\n *\n * No compat-specific name is hard-coded in this plugin — the whole rewrite\n * is driven by these descriptors.\n */\n compatCallers?: CallerDescriptor[];\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 /** map from local identifier name to the compat caller descriptor it was imported as */\n _compatCallerMap?: Map<string, CallerDescriptor>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: 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\n/**\n * Splits a namespace string at the first `.` to separate the dictionary key\n * from an optional key prefix for nested namespaces, mirroring the SWC\n * plugin's `split_namespace`.\n *\n * `'about'` → `{ dictionaryKey: 'about', keyPrefix: '' }`\n * `'about.counter'` → `{ dictionaryKey: 'about', keyPrefix: 'counter' }`\n */\nconst splitNamespace = (\n namespace: string\n): { dictionaryKey: string; keyPrefix: string } => {\n const dotPosition = namespace.indexOf('.');\n if (dotPosition === -1) return { dictionaryKey: namespace, keyPrefix: '' };\n return {\n dictionaryKey: namespace.slice(0, dotPosition),\n keyPrefix: namespace.slice(dotPosition + 1),\n };\n};\n\n/**\n * Result of statically resolving the namespace of a compat caller call-site.\n */\ntype CompatNamespaceMatch = {\n /** The full namespace string, e.g. `'about.counter'`. */\n fullNamespace: string;\n /** Index of the positional namespace argument, when read from an argument. */\n argumentIndex?: number;\n /**\n * The options-object property holding the namespace, when read from an\n * option. The rewrite mutates it in place (key-prefix remainder) or removes\n * it from `optionsObject`.\n */\n optionProperty?: BabelTypes.ObjectProperty;\n /** The options object owning `optionProperty`. */\n optionsObject?: BabelTypes.ObjectExpression;\n};\n\n/**\n * Statically resolves the namespace of a compat caller call-site from its\n * descriptor's `namespaceSources` (argument / option / fixed — the\n * per-message-id `path-first-segment` form cannot bind one dictionary to the\n * call site and is skipped). Returns `undefined` when the namespace is absent\n * or dynamic, in which case the call is left untouched and resolves through\n * the runtime dictionary registry.\n */\nconst resolveCompatNamespaceMatch = (\n t: typeof BabelTypes,\n callArguments: BabelTypes.CallExpression['arguments'],\n descriptor: CallerDescriptor\n): CompatNamespaceMatch | undefined => {\n for (const source of descriptor.namespaceSources) {\n if (source.from === 'fixed') {\n return { fullNamespace: source.value };\n }\n\n if (source.from === 'argument') {\n const namespace = getKeyFromArgument(callArguments[source.index], t);\n if (namespace !== undefined) {\n return { fullNamespace: namespace, argumentIndex: source.index };\n }\n continue;\n }\n\n if (source.from === 'option') {\n const optionsArgument = callArguments[source.argumentIndex];\n if (!optionsArgument || !t.isObjectExpression(optionsArgument)) continue;\n\n for (const property of optionsArgument.properties) {\n if (!t.isObjectProperty(property)) continue;\n const keyMatches =\n (t.isIdentifier(property.key) &&\n property.key.name === source.property) ||\n (t.isStringLiteral(property.key) &&\n property.key.value === source.property);\n if (!keyMatches) continue;\n\n const namespace = getKeyFromArgument(property.value, t);\n if (namespace !== undefined) {\n return {\n fullNamespace: namespace,\n optionProperty: property,\n optionsObject: optionsArgument,\n };\n }\n }\n }\n }\n\n return undefined;\n};\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\n/**\n * Helper family every `useIntlayer`/`getIntlayer` call from one package import\n * resolves to in the current file. `ssrStatic` is the SSR bundle of a\n * dynamic-mode file: rewritten to the static `useDictionary` (from the\n * package's `/server` entry when it has one — see\n * `SSR_STATIC_IMPORT_SOURCE`) so the server renders static JSON while the\n * client keeps the dynamic loader.\n */\ntype PackageHelperPlan = 'static' | 'dynamic' | 'ssrStatic';\n\n/**\n * Decides, once per package import, which helper family applies to this file.\n * The import rewrite and the per-call rewrite must both derive from this\n * single decision, or the emitted helper and its argument shape diverge.\n *\n * Fetch wins over `ssrStatic`: fetch dictionaries are runtime content, so the\n * server must keep the real fetch path instead of rendering build-time JSON.\n */\nconst resolveHelperPlan = (\n packageName: string,\n importMode: ImportMode | undefined,\n isServer: boolean | undefined,\n packageHasDynamicCall: boolean,\n packageHasFetchCall: boolean\n): PackageHelperPlan => {\n if (!isDynamicPackage(packageName)) return 'static';\n\n if (importMode === 'fetch' || packageHasFetchCall) return 'dynamic';\n\n if (importMode === 'dynamic' || packageHasDynamicCall) {\n return isServer === true ? 'ssrStatic' : 'dynamic';\n }\n\n return 'static';\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 * ### 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}): PluginObject<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._compatCallerMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = 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 isIncluded = getNormalizedFilesListSet(this.opts.filesList).has(\n filename\n );\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 // Compat callers the optimize pass can rewrite (injected by the\n // compat packages' bundler plugins — nothing is hard-coded here).\n const rewritableCompatCallers = getRewritableCallers(\n state.opts.compatCallers ?? []\n );\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 const isNativePackage = PACKAGE_LIST.includes(src);\n const compatCallersForSource = rewritableCompatCallers.filter(\n (descriptor) => descriptor.importSources.includes(src)\n );\n\n if (!isNativePackage && compatCallersForSource.length === 0) {\n return;\n }\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 (isNativePackage && isCallerName(importedName)) {\n state._callerMap?.set(spec.local.name, importedName);\n state._callerPackageMap?.set(spec.local.name, src);\n }\n\n const compatDescriptor = compatCallersForSource.find(\n (descriptor) => descriptor.callerName === importedName\n );\n if (compatDescriptor) {\n state._compatCallerMap?.set(\n spec.local.name,\n compatDescriptor\n );\n }\n }\n },\n });\n\n // Pre-pass to determine if dictionary-level overrides require the\n // dynamic helper in an otherwise static file, and to disable the\n // rewrite for compat callers with unresolvable call sites.\n const packagesWithDynamicCall = new Set<string>();\n const packagesWithFetchCall = new Set<string>();\n let compatHasDynamicCall = false;\n const unresolvableCompatLocalNames = 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 compatDescriptor = state._compatCallerMap?.get(callee.name);\n if (compatDescriptor) {\n const namespaceMatch = resolveCompatNamespaceMatch(\n t,\n path.node.arguments,\n compatDescriptor\n );\n\n if (!namespaceMatch) {\n // Dynamic/absent namespace: the whole local caller must keep\n // its original implementation — rewriting the import while\n // leaving this call untouched would hand a raw namespace\n // string to the dictionary-accepting helper.\n unresolvableCompatLocalNames.add(callee.name);\n return;\n }\n\n const { dictionaryKey } = splitNamespace(\n namespaceMatch.fullNamespace\n );\n const compatOverrideMode =\n state.opts.dictionaryModeMap?.[dictionaryKey];\n if (\n compatOverrideMode === 'dynamic' ||\n compatOverrideMode === 'fetch'\n ) {\n compatHasDynamicCall = true;\n }\n return;\n }\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 for (const localName of unresolvableCompatLocalNames) {\n state._compatCallerMap?.delete(localName);\n }\n\n const getHelperPlan = (packageName: string): PackageHelperPlan =>\n resolveHelperPlan(\n packageName,\n state.opts.importMode,\n state.opts.isServer,\n packagesWithDynamicCall.has(packageName),\n packagesWithFetchCall.has(packageName)\n );\n\n // Compat helpers are swapped per file (one import specifier serves\n // every call), so the dynamic decision is file-level: a global\n // dynamic/fetch mode or any per-dictionary override flips all\n // rewritten compat calls to the dynamic helper.\n const compatUseDynamicHelpers =\n state.opts.importMode === 'dynamic' ||\n state.opts.importMode === 'fetch' ||\n compatHasDynamicCall;\n\n programPath.traverse({\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n // Compat caller import rename: point the specifier at the\n // dictionary-accepting helper exported by the compat package\n // (`useTranslation` → `useDictionary`), keeping the local alias\n // so call sites read unchanged. Locals with unresolvable call\n // sites were dropped from the map and keep the original import.\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const compatDescriptor = state._compatCallerMap?.get(\n spec.local.name\n );\n if (!compatDescriptor) continue;\n if (!compatDescriptor.importSources.includes(src)) continue;\n\n spec.imported = t.identifier(\n compatUseDynamicHelpers\n ? compatDescriptor.dynamicReplacement!\n : compatDescriptor.staticReplacement!\n );\n }\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n // Per-import swap, mirrored across bundles — Solid hydration\n // ids rely on the SSR and client helpers consuming one\n // resource slot per call alike (see solid-intlayer/server).\n const helperPlan = getHelperPlan(src);\n const serverSource =\n helperPlan === 'ssrStatic'\n ? SSR_STATIC_IMPORT_SOURCE[src]\n : undefined;\n\n const helperMap: Record<string, string> =\n helperPlan === 'dynamic'\n ? DYNAMIC_HELPER_MAP\n : STATIC_IMPORT_FUNCTION;\n\n const serverSpecifiers: BabelTypes.ImportSpecifier[] = [];\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 if (serverSource && importedName === 'useIntlayer') {\n spec.imported = t.identifier('useDictionary');\n serverSpecifiers.push(spec);\n continue;\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 if (serverSpecifiers.length > 0 && serverSource) {\n // Move the helper to the /server entry, keeping any other\n // specifiers (useLocale, …) on the original import.\n path.insertAfter(\n t.importDeclaration(\n serverSpecifiers,\n t.stringLiteral(serverSource)\n )\n );\n path.node.specifiers = path.node.specifiers.filter(\n (spec) =>\n !serverSpecifiers.includes(\n spec as BabelTypes.ImportSpecifier\n )\n );\n if (path.node.specifiers.length === 0) {\n path.remove();\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 // Compat caller rewrite, e.g. (mirroring the SWC plugin):\n // static: useTranslation('about.counter', opts)\n // → useDictionary(_hash, 'counter', opts)\n // dynamic: useTranslation('about.counter', opts)\n // → useDictionaryDynamic(_hash_dyn, 'about', 'counter', opts)\n // option: useI18n({ namespace: 'about' })\n // → useDictionary(_hash, {})\n // fixed: useLingui() → useDictionary(_hash)\n const compatDescriptor = state._compatCallerMap?.get(callee.name);\n if (compatDescriptor) {\n const callArguments = path.node.arguments;\n const namespaceMatch = resolveCompatNamespaceMatch(\n t,\n callArguments,\n compatDescriptor\n );\n if (!namespaceMatch) return; // filtered by the pre-pass — stay safe\n\n state._hasValidImport = true;\n\n const { dictionaryKey, keyPrefix } = splitNamespace(\n namespaceMatch.fullNamespace\n );\n const compatOverrideMode =\n state.opts.dictionaryModeMap?.[dictionaryKey];\n\n // The import specifier serves every call in the file, so a\n // dynamic file receives a dynamic loader for every call.\n let compatCallMode: ImportMode = 'static';\n if (compatUseDynamicHelpers) {\n if (\n compatOverrideMode === 'dynamic' ||\n compatOverrideMode === 'fetch'\n ) {\n compatCallMode = compatOverrideMode;\n } else if (\n state.opts.importMode === 'dynamic' ||\n state.opts.importMode === 'fetch'\n ) {\n compatCallMode = state.opts.importMode;\n } else {\n compatCallMode = 'dynamic';\n }\n }\n\n let dictionaryIdent: BabelTypes.Identifier;\n if (compatCallMode === 'static') {\n let staticIdent = state._newStaticImports?.get(dictionaryKey);\n if (!staticIdent) {\n staticIdent = makeIdent(dictionaryKey, t);\n state._newStaticImports?.set(dictionaryKey, staticIdent);\n }\n dictionaryIdent = staticIdent;\n } else {\n let dynamicIdent =\n state._newDynamicImports?.get(dictionaryKey);\n if (!dynamicIdent) {\n const hash = getPathHash(dictionaryKey);\n const suffix = compatCallMode === 'fetch' ? 'fetch' : 'dyn';\n dynamicIdent = t.identifier(`_${hash}_${suffix}`);\n state._newDynamicImports?.set(dictionaryKey, dynamicIdent);\n }\n dictionaryIdent = dynamicIdent;\n }\n\n if (namespaceMatch.argumentIndex !== undefined) {\n // Positional namespace: replace the string with the\n // dictionary, then (dynamic) key and (nested) prefix.\n callArguments[namespaceMatch.argumentIndex] = t.identifier(\n dictionaryIdent.name\n );\n const insertAt = namespaceMatch.argumentIndex + 1;\n const insertedArguments: BabelTypes.Expression[] = [];\n if (compatCallMode !== 'static') {\n insertedArguments.push(t.stringLiteral(dictionaryKey));\n }\n if (keyPrefix) {\n insertedArguments.push(t.stringLiteral(keyPrefix));\n }\n callArguments.splice(insertAt, 0, ...insertedArguments);\n } else if (compatCallMode !== 'static') {\n // Fixed / option namespace, dynamic helper: prepend the\n // loader and the dictionary key.\n callArguments.unshift(\n t.identifier(dictionaryIdent.name),\n t.stringLiteral(dictionaryKey)\n );\n } else {\n // Fixed / option namespace, static helper: prepend the\n // dictionary object.\n callArguments.unshift(t.identifier(dictionaryIdent.name));\n }\n\n // Option namespace: leave only the key-prefix remainder in the\n // options object (or drop the property for a plain namespace),\n // so the runtime helper does not re-apply the dictionary key\n // as a lookup prefix.\n if (\n namespaceMatch.optionProperty &&\n namespaceMatch.optionsObject\n ) {\n if (keyPrefix) {\n namespaceMatch.optionProperty.value =\n t.stringLiteral(keyPrefix);\n } else {\n namespaceMatch.optionsObject.properties =\n namespaceMatch.optionsObject.properties.filter(\n (property) => property !== namespaceMatch.optionProperty\n );\n }\n }\n\n return;\n }\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 helperPlan =\n callerPackage === undefined\n ? 'static'\n : getHelperPlan(callerPackage);\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'.\n let perCallMode: ImportMode = 'static';\n\n if (isUseIntlayer && helperPlan === 'dynamic') {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic' || importMode === 'fetch') {\n perCallMode = importMode;\n }\n } else if (isUseIntlayer && helperPlan === 'static') {\n // The global mode is static, but a per-dictionary override can\n // still force dynamic/fetch for this specific call.\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
|
+
{"version":3,"file":"babel-plugin-intlayer-optimize.cjs","names":["getPathHash","normalizePath","relative","dirname","join","getNormalizedFilesListSet","getRewritableCallers"],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObject, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n type CallerDescriptor,\n getRewritableCallers,\n} from '@intlayer/config/callers';\nimport { normalizePath } from '@intlayer/config/utils';\nimport { getPathHash } from '@intlayer/engine/utils';\nimport { getNormalizedFilesListSet } from './normalizedFilesList';\n\nconst PACKAGE_LIST = [\n 'intlayer',\n '@intlayer/core',\n '@intlayer/core/interpreter',\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/** Import rename table applied when the helper plan for a package is `dynamic`. */\nconst DYNAMIC_HELPER_MAP: Record<string, string> = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n};\n\n/**\n * Packages whose SSR-static `useDictionary` lives in a `/server` subpath\n * because it differs from the root one. Solid's reserves one hydration\n * resource slot so hydration ids stay aligned with the client's\n * `useDictionaryDynamic`; for other frameworks the root `useDictionary` is\n * already the correct SSR-static implementation.\n */\nconst SSR_STATIC_IMPORT_SOURCE: Partial<Record<string, string>> = {\n 'solid-intlayer': 'solid-intlayer/server',\n};\n\ntype CallerName = (typeof CALLER_LIST)[number];\ntype ImportMode = 'static' | 'dynamic' | 'fetch';\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 * Keys of the dictionaries that reference other dictionaries through\n * `nest()`.\n *\n * For those, the injected static import points at the generated companion\n * module (`<dictionariesDir>/nested/<key>.mjs`) instead of the raw JSON. The\n * companion re-exports the dictionary with its nest targets attached, so\n * `getNesting` resolves them from that local reference rather than from the\n * global registry this plugin empties — and each target lands in the chunk of\n * the dictionary referencing it.\n *\n * Dynamic and fetch modes need nothing here: their generated loaders already\n * attach the same targets per locale.\n */\n nestingDictionaryKeys?: string[];\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 * Compat-adapter caller descriptors injected by the compat packages'\n * bundler plugins (e.g. `@intlayer/react-i18next/plugin`).\n *\n * Callers carrying `staticReplacement` / `dynamicReplacement` are rewritten\n * the same way as native `useIntlayer` calls: the namespace string argument\n * is replaced by a pre-imported dictionary object and the import specifier\n * is re-pointed to the dictionary-accepting variant, e.g.\n * `useTranslation('about')` → `useDictionary(_dictHash)`.\n *\n * No compat-specific name is hard-coded in this plugin — the whole rewrite\n * is driven by these descriptors.\n */\n compatCallers?: CallerDescriptor[];\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 /** map from local identifier name to the compat caller descriptor it was imported as */\n _compatCallerMap?: Map<string, CallerDescriptor>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: 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\n/**\n * Builds the module specifier pointing at `targetPath` from `fromFile`, with\n * forward slashes and an explicit `./` prefix so bundlers never treat it as a\n * bare package specifier.\n */\nconst toRelativeSpecifier = (fromFile: string, targetPath: string): string => {\n // Fix windows path\n const relativePath = normalizePath(relative(dirname(fromFile), targetPath));\n\n // Fix relative path\n if (!relativePath.startsWith('./') && !relativePath.startsWith('../')) {\n return `./${relativePath}`;\n }\n\n return relativePath;\n};\n\n/**\n * Subdirectory of the compiled dictionaries holding the companion modules that\n * re-export a dictionary with its `nest()` targets attached. Mirrors\n * `NESTED_DICTIONARIES_SUBDIR` in `@intlayer/engine`.\n */\nconst NESTED_DICTIONARIES_SUBDIR = 'nested';\n\nconst computeImport = (\n fromFile: string,\n dictionariesDir: string,\n dynamicDictionariesDir: string,\n fetchDictionariesDir: string,\n key: string,\n importMode: 'static' | 'dynamic' | 'fetch',\n hasNestedDictionaries = false\n): string => {\n // Static mode is the only one needing the companion: the dynamic and fetch\n // loaders already attach the nest targets per locale.\n let dictionaryPath = hasNestedDictionaries\n ? join(dictionariesDir, NESTED_DICTIONARIES_SUBDIR, `${key}.mjs`)\n : join(dictionariesDir, `${key}.json`);\n\n if (importMode === 'fetch') {\n dictionaryPath = join(fetchDictionariesDir, `${key}.mjs`);\n }\n\n if (importMode === 'dynamic') {\n dictionaryPath = join(dynamicDictionariesDir, `${key}.mjs`);\n }\n\n return toRelativeSpecifier(fromFile, dictionaryPath);\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\n/**\n * Splits a namespace string at the first `.` to separate the dictionary key\n * from an optional key prefix for nested namespaces, mirroring the SWC\n * plugin's `split_namespace`.\n *\n * `'about'` → `{ dictionaryKey: 'about', keyPrefix: '' }`\n * `'about.counter'` → `{ dictionaryKey: 'about', keyPrefix: 'counter' }`\n */\nconst splitNamespace = (\n namespace: string\n): { dictionaryKey: string; keyPrefix: string } => {\n const dotPosition = namespace.indexOf('.');\n if (dotPosition === -1) return { dictionaryKey: namespace, keyPrefix: '' };\n return {\n dictionaryKey: namespace.slice(0, dotPosition),\n keyPrefix: namespace.slice(dotPosition + 1),\n };\n};\n\n/**\n * Result of statically resolving the namespace of a compat caller call-site.\n */\ntype CompatNamespaceMatch = {\n /** The full namespace string, e.g. `'about.counter'`. */\n fullNamespace: string;\n /** Index of the positional namespace argument, when read from an argument. */\n argumentIndex?: number;\n /**\n * The options-object property holding the namespace, when read from an\n * option. The rewrite mutates it in place (key-prefix remainder) or removes\n * it from `optionsObject`.\n */\n optionProperty?: BabelTypes.ObjectProperty;\n /** The options object owning `optionProperty`. */\n optionsObject?: BabelTypes.ObjectExpression;\n};\n\n/**\n * Statically resolves the namespace of a compat caller call-site from its\n * descriptor's `namespaceSources` (argument / option / fixed — the\n * per-message-id `path-first-segment` form cannot bind one dictionary to the\n * call site and is skipped). Returns `undefined` when the namespace is absent\n * or dynamic, in which case the call is left untouched and resolves through\n * the runtime dictionary registry.\n */\nconst resolveCompatNamespaceMatch = (\n t: typeof BabelTypes,\n callArguments: BabelTypes.CallExpression['arguments'],\n descriptor: CallerDescriptor\n): CompatNamespaceMatch | undefined => {\n for (const source of descriptor.namespaceSources) {\n if (source.from === 'fixed') {\n return { fullNamespace: source.value };\n }\n\n if (source.from === 'argument') {\n const namespace = getKeyFromArgument(callArguments[source.index], t);\n if (namespace !== undefined) {\n return { fullNamespace: namespace, argumentIndex: source.index };\n }\n continue;\n }\n\n if (source.from === 'option') {\n const optionsArgument = callArguments[source.argumentIndex];\n if (!optionsArgument || !t.isObjectExpression(optionsArgument)) continue;\n\n for (const property of optionsArgument.properties) {\n if (!t.isObjectProperty(property)) continue;\n const keyMatches =\n (t.isIdentifier(property.key) &&\n property.key.name === source.property) ||\n (t.isStringLiteral(property.key) &&\n property.key.value === source.property);\n if (!keyMatches) continue;\n\n const namespace = getKeyFromArgument(property.value, t);\n if (namespace !== undefined) {\n return {\n fullNamespace: namespace,\n optionProperty: property,\n optionsObject: optionsArgument,\n };\n }\n }\n }\n }\n\n return undefined;\n};\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\n/**\n * Helper family every `useIntlayer`/`getIntlayer` call from one package import\n * resolves to in the current file. `ssrStatic` is the SSR bundle of a\n * dynamic-mode file: rewritten to the static `useDictionary` (from the\n * package's `/server` entry when it has one — see\n * `SSR_STATIC_IMPORT_SOURCE`) so the server renders static JSON while the\n * client keeps the dynamic loader.\n */\ntype PackageHelperPlan = 'static' | 'dynamic' | 'ssrStatic';\n\n/**\n * Decides, once per package import, which helper family applies to this file.\n * The import rewrite and the per-call rewrite must both derive from this\n * single decision, or the emitted helper and its argument shape diverge.\n *\n * Fetch wins over `ssrStatic`: fetch dictionaries are runtime content, so the\n * server must keep the real fetch path instead of rendering build-time JSON.\n */\nconst resolveHelperPlan = (\n packageName: string,\n importMode: ImportMode | undefined,\n isServer: boolean | undefined,\n packageHasDynamicCall: boolean,\n packageHasFetchCall: boolean\n): PackageHelperPlan => {\n if (!isDynamicPackage(packageName)) return 'static';\n\n if (importMode === 'fetch' || packageHasFetchCall) return 'dynamic';\n\n if (importMode === 'dynamic' || packageHasDynamicCall) {\n return isServer === true ? 'ssrStatic' : 'dynamic';\n }\n\n return 'static';\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 * ### 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}): PluginObject<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._compatCallerMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = 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 isIncluded = getNormalizedFilesListSet(this.opts.filesList).has(\n filename\n );\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 // Compat callers the optimize pass can rewrite (injected by the\n // compat packages' bundler plugins — nothing is hard-coded here).\n const rewritableCompatCallers = getRewritableCallers(\n state.opts.compatCallers ?? []\n );\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 const isNativePackage = PACKAGE_LIST.includes(src);\n const compatCallersForSource = rewritableCompatCallers.filter(\n (descriptor) => descriptor.importSources.includes(src)\n );\n\n if (!isNativePackage && compatCallersForSource.length === 0) {\n return;\n }\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 (isNativePackage && isCallerName(importedName)) {\n state._callerMap?.set(spec.local.name, importedName);\n state._callerPackageMap?.set(spec.local.name, src);\n }\n\n const compatDescriptor = compatCallersForSource.find(\n (descriptor) => descriptor.callerName === importedName\n );\n if (compatDescriptor) {\n state._compatCallerMap?.set(\n spec.local.name,\n compatDescriptor\n );\n }\n }\n },\n });\n\n // Pre-pass to determine if dictionary-level overrides require the\n // dynamic helper in an otherwise static file, and to disable the\n // rewrite for compat callers with unresolvable call sites.\n const packagesWithDynamicCall = new Set<string>();\n const packagesWithFetchCall = new Set<string>();\n let compatHasDynamicCall = false;\n const unresolvableCompatLocalNames = 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 compatDescriptor = state._compatCallerMap?.get(callee.name);\n if (compatDescriptor) {\n const namespaceMatch = resolveCompatNamespaceMatch(\n t,\n path.node.arguments,\n compatDescriptor\n );\n\n if (!namespaceMatch) {\n // Dynamic/absent namespace: the whole local caller must keep\n // its original implementation — rewriting the import while\n // leaving this call untouched would hand a raw namespace\n // string to the dictionary-accepting helper.\n unresolvableCompatLocalNames.add(callee.name);\n return;\n }\n\n const { dictionaryKey } = splitNamespace(\n namespaceMatch.fullNamespace\n );\n const compatOverrideMode =\n state.opts.dictionaryModeMap?.[dictionaryKey];\n if (\n compatOverrideMode === 'dynamic' ||\n compatOverrideMode === 'fetch'\n ) {\n compatHasDynamicCall = true;\n }\n return;\n }\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 for (const localName of unresolvableCompatLocalNames) {\n state._compatCallerMap?.delete(localName);\n }\n\n const getHelperPlan = (packageName: string): PackageHelperPlan =>\n resolveHelperPlan(\n packageName,\n state.opts.importMode,\n state.opts.isServer,\n packagesWithDynamicCall.has(packageName),\n packagesWithFetchCall.has(packageName)\n );\n\n // Compat helpers are swapped per file (one import specifier serves\n // every call), so the dynamic decision is file-level: a global\n // dynamic/fetch mode or any per-dictionary override flips all\n // rewritten compat calls to the dynamic helper.\n const compatUseDynamicHelpers =\n state.opts.importMode === 'dynamic' ||\n state.opts.importMode === 'fetch' ||\n compatHasDynamicCall;\n\n programPath.traverse({\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n // Compat caller import rename: point the specifier at the\n // dictionary-accepting helper exported by the compat package\n // (`useTranslation` → `useDictionary`), keeping the local alias\n // so call sites read unchanged. Locals with unresolvable call\n // sites were dropped from the map and keep the original import.\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const compatDescriptor = state._compatCallerMap?.get(\n spec.local.name\n );\n if (!compatDescriptor) continue;\n if (!compatDescriptor.importSources.includes(src)) continue;\n\n spec.imported = t.identifier(\n compatUseDynamicHelpers\n ? compatDescriptor.dynamicReplacement!\n : compatDescriptor.staticReplacement!\n );\n }\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n // Per-import swap, mirrored across bundles — Solid hydration\n // ids rely on the SSR and client helpers consuming one\n // resource slot per call alike (see solid-intlayer/server).\n const helperPlan = getHelperPlan(src);\n const serverSource =\n helperPlan === 'ssrStatic'\n ? SSR_STATIC_IMPORT_SOURCE[src]\n : undefined;\n\n const helperMap: Record<string, string> =\n helperPlan === 'dynamic'\n ? DYNAMIC_HELPER_MAP\n : STATIC_IMPORT_FUNCTION;\n\n const serverSpecifiers: BabelTypes.ImportSpecifier[] = [];\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 if (serverSource && importedName === 'useIntlayer') {\n spec.imported = t.identifier('useDictionary');\n serverSpecifiers.push(spec);\n continue;\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 if (serverSpecifiers.length > 0 && serverSource) {\n // Move the helper to the /server entry, keeping any other\n // specifiers (useLocale, …) on the original import.\n path.insertAfter(\n t.importDeclaration(\n serverSpecifiers,\n t.stringLiteral(serverSource)\n )\n );\n path.node.specifiers = path.node.specifiers.filter(\n (spec) =>\n !serverSpecifiers.includes(\n spec as BabelTypes.ImportSpecifier\n )\n );\n if (path.node.specifiers.length === 0) {\n path.remove();\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 // Compat caller rewrite, e.g. (mirroring the SWC plugin):\n // static: useTranslation('about.counter', opts)\n // → useDictionary(_hash, 'counter', opts)\n // dynamic: useTranslation('about.counter', opts)\n // → useDictionaryDynamic(_hash_dyn, 'about', 'counter', opts)\n // option: useI18n({ namespace: 'about' })\n // → useDictionary(_hash, {})\n // fixed: useLingui() → useDictionary(_hash)\n const compatDescriptor = state._compatCallerMap?.get(callee.name);\n if (compatDescriptor) {\n const callArguments = path.node.arguments;\n const namespaceMatch = resolveCompatNamespaceMatch(\n t,\n callArguments,\n compatDescriptor\n );\n if (!namespaceMatch) return; // filtered by the pre-pass — stay safe\n\n state._hasValidImport = true;\n\n const { dictionaryKey, keyPrefix } = splitNamespace(\n namespaceMatch.fullNamespace\n );\n const compatOverrideMode =\n state.opts.dictionaryModeMap?.[dictionaryKey];\n\n // The import specifier serves every call in the file, so a\n // dynamic file receives a dynamic loader for every call.\n let compatCallMode: ImportMode = 'static';\n if (compatUseDynamicHelpers) {\n if (\n compatOverrideMode === 'dynamic' ||\n compatOverrideMode === 'fetch'\n ) {\n compatCallMode = compatOverrideMode;\n } else if (\n state.opts.importMode === 'dynamic' ||\n state.opts.importMode === 'fetch'\n ) {\n compatCallMode = state.opts.importMode;\n } else {\n compatCallMode = 'dynamic';\n }\n }\n\n let dictionaryIdent: BabelTypes.Identifier;\n if (compatCallMode === 'static') {\n let staticIdent = state._newStaticImports?.get(dictionaryKey);\n if (!staticIdent) {\n staticIdent = makeIdent(dictionaryKey, t);\n state._newStaticImports?.set(dictionaryKey, staticIdent);\n }\n dictionaryIdent = staticIdent;\n } else {\n let dynamicIdent =\n state._newDynamicImports?.get(dictionaryKey);\n if (!dynamicIdent) {\n const hash = getPathHash(dictionaryKey);\n const suffix = compatCallMode === 'fetch' ? 'fetch' : 'dyn';\n dynamicIdent = t.identifier(`_${hash}_${suffix}`);\n state._newDynamicImports?.set(dictionaryKey, dynamicIdent);\n }\n dictionaryIdent = dynamicIdent;\n }\n\n if (namespaceMatch.argumentIndex !== undefined) {\n // Positional namespace: replace the string with the\n // dictionary, then (dynamic) key and (nested) prefix.\n callArguments[namespaceMatch.argumentIndex] = t.identifier(\n dictionaryIdent.name\n );\n const insertAt = namespaceMatch.argumentIndex + 1;\n const insertedArguments: BabelTypes.Expression[] = [];\n if (compatCallMode !== 'static') {\n insertedArguments.push(t.stringLiteral(dictionaryKey));\n }\n if (keyPrefix) {\n insertedArguments.push(t.stringLiteral(keyPrefix));\n }\n callArguments.splice(insertAt, 0, ...insertedArguments);\n } else if (compatCallMode !== 'static') {\n // Fixed / option namespace, dynamic helper: prepend the\n // loader and the dictionary key.\n callArguments.unshift(\n t.identifier(dictionaryIdent.name),\n t.stringLiteral(dictionaryKey)\n );\n } else {\n // Fixed / option namespace, static helper: prepend the\n // dictionary object.\n callArguments.unshift(t.identifier(dictionaryIdent.name));\n }\n\n // Option namespace: leave only the key-prefix remainder in the\n // options object (or drop the property for a plain namespace),\n // so the runtime helper does not re-apply the dictionary key\n // as a lookup prefix.\n if (\n namespaceMatch.optionProperty &&\n namespaceMatch.optionsObject\n ) {\n if (keyPrefix) {\n namespaceMatch.optionProperty.value =\n t.stringLiteral(keyPrefix);\n } else {\n namespaceMatch.optionsObject.properties =\n namespaceMatch.optionsObject.properties.filter(\n (property) => property !== namespaceMatch.optionProperty\n );\n }\n }\n\n return;\n }\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 helperPlan =\n callerPackage === undefined\n ? 'static'\n : getHelperPlan(callerPackage);\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'.\n let perCallMode: ImportMode = 'static';\n\n if (isUseIntlayer && helperPlan === 'dynamic') {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic' || importMode === 'fetch') {\n perCallMode = importMode;\n }\n } else if (isUseIntlayer && helperPlan === 'static') {\n // The global mode is static, but a per-dictionary override can\n // still force dynamic/fetch for this specific call.\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 const nestingDictionaryKeys = new Set(\n state.opts.nestingDictionaryKeys ?? []\n );\n\n // Generate static JSON imports (getIntlayer always uses JSON dictionaries)\n for (const [key, ident] of state._newStaticImports!) {\n // Dictionaries holding `nest()` references are imported through\n // their companion module, which re-exports them with the nest\n // targets attached.\n const hasNestedDictionaries = nestingDictionaryKeys.has(key);\n\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static',\n hasNestedDictionaries\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 if (!hasNestedDictionaries) {\n importDeclarationNode.attributes = [\n t.importAttribute(\n t.identifier('type'),\n t.stringLiteral('json')\n ),\n ];\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,9 +1,14 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
2
3
|
const require_babel_plugin_intlayer_usage_analyzer = require('./babel-plugin-intlayer-usage-analyzer.cjs');
|
|
3
4
|
const require_extractScriptBlocks = require('./extractScriptBlocks.cjs');
|
|
4
5
|
const require_babel_plugin_intlayer_field_rename = require('./babel-plugin-intlayer-field-rename.cjs');
|
|
5
6
|
const require_transformers = require('./transformers.cjs');
|
|
6
7
|
let node_path = require("node:path");
|
|
8
|
+
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
9
|
+
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
10
|
+
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
11
|
+
let _intlayer_engine_utils = require("@intlayer/engine/utils");
|
|
7
12
|
let node_fs = require("node:fs");
|
|
8
13
|
let _babel_core = require("@babel/core");
|
|
9
14
|
|
|
@@ -11,7 +16,7 @@ let _babel_core = require("@babel/core");
|
|
|
11
16
|
/**
|
|
12
17
|
* Cache of built {@link PruneContext} objects, keyed by the project's
|
|
13
18
|
* `baseDir`. Each context is built exactly once per Node.js process:
|
|
14
|
-
* {@link
|
|
19
|
+
* {@link runIntlayerPurgePipeline} registers the context before running so every
|
|
15
20
|
* subsequent transform is a no-op cache hit.
|
|
16
21
|
*/
|
|
17
22
|
const _pruneContextCache = /* @__PURE__ */ new Map();
|
|
@@ -165,7 +170,8 @@ const analyzeSourceFileSync = (sourceFilePath, pruneContext, compatCallers) => {
|
|
|
165
170
|
* `buildStart` hook. Results are stored in
|
|
166
171
|
* `pruneContext.dictionaryKeyToFieldRenameMap`.
|
|
167
172
|
*/
|
|
168
|
-
const buildRenameMapsSynchronously = (dictionariesDir, dynamicDictionariesDir, dictionaryKeyToImportModeMap, pruneContext) => {
|
|
173
|
+
const buildRenameMapsSynchronously = (dictionariesDir, dynamicDictionariesDir, dictionaryKeyToImportModeMap, pruneContext, logger) => {
|
|
174
|
+
let partiallyMinifiedDictionariesCount = 0;
|
|
169
175
|
for (const [dictionaryKey, fieldUsage] of pruneContext.dictionaryKeyToFieldUsageMap) {
|
|
170
176
|
if (fieldUsage === "all") continue;
|
|
171
177
|
if (dictionaryKeyToImportModeMap[dictionaryKey] === "fetch") continue;
|
|
@@ -189,12 +195,50 @@ const buildRenameMapsSynchronously = (dictionariesDir, dynamicDictionariesDir, d
|
|
|
189
195
|
if (!dictionaryContent) continue;
|
|
190
196
|
const nestedRenameMap = require_babel_plugin_intlayer_field_rename.buildNestedRenameMapFromContent(dictionaryContent);
|
|
191
197
|
const opaqueFieldMap = pruneContext.dictionaryKeysWithOpaqueFields.get(dictionaryKey);
|
|
192
|
-
if (opaqueFieldMap)
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
198
|
+
if (opaqueFieldMap) {
|
|
199
|
+
const dangerousOccurrences = [...opaqueFieldMap.values()].filter((occurrence) => (require_babel_plugin_intlayer_field_rename.getNestedRenameEntryAtPath(nestedRenameMap, occurrence.fieldPath)?.children.size ?? 0) > 0);
|
|
200
|
+
if (dangerousOccurrences.length > 0) {
|
|
201
|
+
partiallyMinifiedDictionariesCount += 1;
|
|
202
|
+
logger([
|
|
203
|
+
`Dictionary`,
|
|
204
|
+
(0, _intlayer_config_logger.colorizeKey)(dictionaryKey),
|
|
205
|
+
`partially minified.`,
|
|
206
|
+
...dangerousOccurrences.flatMap((occurrence) => [
|
|
207
|
+
`\n Opaque field:`,
|
|
208
|
+
(0, _intlayer_config_logger.colorize)(`'${occurrence.fieldPath.join(".")}'`, _intlayer_config_colors.BLUE),
|
|
209
|
+
`(nested keys preserved for stability).`,
|
|
210
|
+
...occurrence.locations.map((location) => `\n at ${(0, _intlayer_engine_utils.formatPath)(location)}`)
|
|
211
|
+
])
|
|
212
|
+
], {
|
|
213
|
+
level: "warn",
|
|
214
|
+
isVerbose: true
|
|
215
|
+
});
|
|
216
|
+
for (const occurrence of dangerousOccurrences) {
|
|
217
|
+
const renameEntry = require_babel_plugin_intlayer_field_rename.getNestedRenameEntryAtPath(nestedRenameMap, occurrence.fieldPath);
|
|
218
|
+
if (renameEntry) renameEntry.children = /* @__PURE__ */ new Map();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
195
221
|
}
|
|
196
222
|
if (nestedRenameMap.size > 0) pruneContext.dictionaryKeyToFieldRenameMap.set(dictionaryKey, nestedRenameMap);
|
|
197
223
|
}
|
|
224
|
+
if (partiallyMinifiedDictionariesCount > 0) logger([
|
|
225
|
+
`Partially minified`,
|
|
226
|
+
(0, _intlayer_config_logger.colorizeNumber)(partiallyMinifiedDictionariesCount),
|
|
227
|
+
`dictionar${partiallyMinifiedDictionariesCount === 1 ? "y" : "ies"}`,
|
|
228
|
+
`(preserved nested keys for opaque fields).`
|
|
229
|
+
]);
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Names of the top-level content fields of a compiled dictionary, whatever
|
|
233
|
+
* shape its `content` uses. Used to report which fields the purge removed.
|
|
234
|
+
*/
|
|
235
|
+
const readContentFieldNames = (content) => {
|
|
236
|
+
if (isTranslationNode(content)) {
|
|
237
|
+
const firstLocaleValue = Object.values(content.translation)[0];
|
|
238
|
+
return isPlainRecord(firstLocaleValue) ? Object.keys(firstLocaleValue) : [];
|
|
239
|
+
}
|
|
240
|
+
if (isPlainRecord(content)) return Object.keys(content);
|
|
241
|
+
return [];
|
|
198
242
|
};
|
|
199
243
|
/**
|
|
200
244
|
* Reads a compiled dictionary JSON file, applies the purge and/or minify
|
|
@@ -204,7 +248,7 @@ const buildRenameMapsSynchronously = (dictionariesDir, dynamicDictionariesDir, d
|
|
|
204
248
|
* static dictionaries keep `{ key, content }`, dynamic per-locale
|
|
205
249
|
* dictionaries additionally keep `locale`.
|
|
206
250
|
*/
|
|
207
|
-
const processDictionaryFile = (filePath, dictionaryKind, pruneContext, shouldPurge, shouldMinify) => {
|
|
251
|
+
const processDictionaryFile = (filePath, dictionaryKind, pruneContext, shouldPurge, shouldMinify, logger, stats) => {
|
|
208
252
|
let parsedDict;
|
|
209
253
|
try {
|
|
210
254
|
parsedDict = JSON.parse((0, node_fs.readFileSync)(filePath, "utf-8"));
|
|
@@ -212,19 +256,56 @@ const processDictionaryFile = (filePath, dictionaryKind, pruneContext, shouldPur
|
|
|
212
256
|
return;
|
|
213
257
|
}
|
|
214
258
|
const { key: dictionaryKey } = parsedDict;
|
|
215
|
-
if (!dictionaryKey)
|
|
259
|
+
if (!dictionaryKey) {
|
|
260
|
+
logger([
|
|
261
|
+
`Dictionary file`,
|
|
262
|
+
(0, _intlayer_engine_utils.formatPath)(filePath),
|
|
263
|
+
`is missing a "key" field. Skipping prune for this file.`
|
|
264
|
+
], { level: "warn" });
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
216
267
|
if (pruneContext.dictionariesWithEdgeCases.has(dictionaryKey)) return;
|
|
217
268
|
let modified = false;
|
|
218
269
|
if (shouldPurge) {
|
|
219
270
|
const fieldUsage = pruneContext.dictionaryKeyToFieldUsageMap.get(dictionaryKey);
|
|
220
271
|
if (fieldUsage && fieldUsage !== "all") {
|
|
221
|
-
const
|
|
272
|
+
const pruneDictionaryContent = dictionaryKind === "static" ? pruneStaticDictionaryContent : pruneDynamicDictionaryContent;
|
|
273
|
+
const originalFieldNames = readContentFieldNames(parsedDict.content);
|
|
274
|
+
const { prunedDictionary, wasRecognised } = pruneDictionaryContent(parsedDict, fieldUsage);
|
|
222
275
|
if (!wasRecognised) {
|
|
223
276
|
pruneContext.dictionariesWithEdgeCases.add(dictionaryKey);
|
|
277
|
+
logger([
|
|
278
|
+
`Unrecognised content structure in dictionary`,
|
|
279
|
+
(0, _intlayer_config_logger.colorizeKey)(dictionaryKey),
|
|
280
|
+
`(file:`,
|
|
281
|
+
`${(0, _intlayer_engine_utils.formatPath)(filePath)}).`,
|
|
282
|
+
`Skipping prune for this dictionary.`
|
|
283
|
+
], { level: "warn" });
|
|
224
284
|
return;
|
|
225
285
|
}
|
|
286
|
+
const removedFieldNames = originalFieldNames.filter((fieldName) => !fieldUsage.has(fieldName));
|
|
287
|
+
if (removedFieldNames.length > 0) {
|
|
288
|
+
stats.prunedFieldsCountPerDictionary.set(dictionaryKey, removedFieldNames.length);
|
|
289
|
+
if (!stats.loggedPrunedDictionaryKeys.has(dictionaryKey)) {
|
|
290
|
+
stats.loggedPrunedDictionaryKeys.add(dictionaryKey);
|
|
291
|
+
logger([
|
|
292
|
+
`Pruned`,
|
|
293
|
+
(0, _intlayer_config_logger.colorizeNumber)(removedFieldNames.length),
|
|
294
|
+
`unused field${removedFieldNames.length === 1 ? "" : "s"} from`,
|
|
295
|
+
`${(0, _intlayer_config_logger.colorizeKey)(dictionaryKey)}:`,
|
|
296
|
+
removedFieldNames.map((fieldName) => (0, _intlayer_config_logger.colorize)(fieldName, _intlayer_config_colors.GREY_LIGHT)).join(", ")
|
|
297
|
+
], { isVerbose: true });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
226
300
|
parsedDict = prunedDictionary;
|
|
227
301
|
modified = true;
|
|
302
|
+
} else if (!fieldUsage && pruneContext.hasUnparsableSourceFiles && !stats.loggedIncompleteAnalysisKeys.has(dictionaryKey)) {
|
|
303
|
+
stats.loggedIncompleteAnalysisKeys.add(dictionaryKey);
|
|
304
|
+
logger([
|
|
305
|
+
`Skipping prune for dictionary`,
|
|
306
|
+
(0, _intlayer_config_logger.colorizeKey)(dictionaryKey),
|
|
307
|
+
`: analysis is incomplete due to earlier source-file parse failures.`
|
|
308
|
+
], { level: "warn" });
|
|
228
309
|
}
|
|
229
310
|
}
|
|
230
311
|
if (shouldMinify) {
|
|
@@ -247,41 +328,104 @@ const processDictionaryFile = (filePath, dictionaryKind, pruneContext, shouldPur
|
|
|
247
328
|
(0, node_fs.writeFileSync)(filePath, JSON.stringify(outputDict), "utf-8");
|
|
248
329
|
} catch {}
|
|
249
330
|
};
|
|
250
|
-
const processAllDictionaryFiles = (dictionariesDir, dynamicDictionariesDir, pruneContext, shouldPurge, shouldMinify) => {
|
|
331
|
+
const processAllDictionaryFiles = (dictionariesDir, dynamicDictionariesDir, pruneContext, shouldPurge, shouldMinify, logger) => {
|
|
332
|
+
const stats = {
|
|
333
|
+
prunedFieldsCountPerDictionary: /* @__PURE__ */ new Map(),
|
|
334
|
+
loggedPrunedDictionaryKeys: /* @__PURE__ */ new Set(),
|
|
335
|
+
loggedIncompleteAnalysisKeys: /* @__PURE__ */ new Set()
|
|
336
|
+
};
|
|
251
337
|
if ((0, node_fs.existsSync)(dictionariesDir)) for (const entry of (0, node_fs.readdirSync)(dictionariesDir)) {
|
|
252
338
|
if (!entry.endsWith(".json")) continue;
|
|
253
|
-
processDictionaryFile((0, node_path.join)(dictionariesDir, entry), "static", pruneContext, shouldPurge, shouldMinify);
|
|
339
|
+
processDictionaryFile((0, node_path.join)(dictionariesDir, entry), "static", pruneContext, shouldPurge, shouldMinify, logger, stats);
|
|
254
340
|
}
|
|
255
341
|
if ((0, node_fs.existsSync)(dynamicDictionariesDir)) for (const keyDir of (0, node_fs.readdirSync)(dynamicDictionariesDir)) {
|
|
256
342
|
const keyDirPath = (0, node_path.join)(dynamicDictionariesDir, keyDir);
|
|
257
343
|
try {
|
|
258
344
|
for (const localeFile of (0, node_fs.readdirSync)(keyDirPath)) {
|
|
259
345
|
if (!localeFile.endsWith(".json")) continue;
|
|
260
|
-
processDictionaryFile((0, node_path.join)(keyDirPath, localeFile), "dynamic", pruneContext, shouldPurge, shouldMinify);
|
|
346
|
+
processDictionaryFile((0, node_path.join)(keyDirPath, localeFile), "dynamic", pruneContext, shouldPurge, shouldMinify, logger, stats);
|
|
261
347
|
}
|
|
262
348
|
} catch {}
|
|
263
349
|
}
|
|
350
|
+
const totalPrunedFieldsCount = [...stats.prunedFieldsCountPerDictionary.values()].reduce((total, count) => total + count, 0);
|
|
351
|
+
const totalPrunedDictionariesCount = stats.prunedFieldsCountPerDictionary.size;
|
|
352
|
+
if (totalPrunedFieldsCount > 0) logger([
|
|
353
|
+
`Pruned`,
|
|
354
|
+
(0, _intlayer_config_logger.colorizeNumber)(totalPrunedFieldsCount),
|
|
355
|
+
`unused field${totalPrunedFieldsCount === 1 ? "" : "s"} across`,
|
|
356
|
+
(0, _intlayer_config_logger.colorizeNumber)(totalPrunedDictionariesCount),
|
|
357
|
+
`dictionar${totalPrunedDictionariesCount === 1 ? "y" : "ies"}.`
|
|
358
|
+
]);
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
* Explains why the requested steps did nothing: the visual editor needs the
|
|
362
|
+
* full dictionary content, so both purge and minify stand down when it is on.
|
|
363
|
+
*/
|
|
364
|
+
const logStepDisabledByEditor = (logger, purge, minify) => {
|
|
365
|
+
const explainDisabled = (stepLabel) => logger([
|
|
366
|
+
stepLabel,
|
|
367
|
+
"is",
|
|
368
|
+
(0, _intlayer_config_logger.colorize)("disabled", _intlayer_config_colors.GREY_DARK),
|
|
369
|
+
"because",
|
|
370
|
+
(0, _intlayer_config_logger.colorize)("editor.enabled", _intlayer_config_colors.BLUE),
|
|
371
|
+
"is",
|
|
372
|
+
(0, _intlayer_config_logger.colorize)("true", _intlayer_config_colors.GREY_DARK),
|
|
373
|
+
(0, _intlayer_config_logger.colorize)("— the editor requires full dictionary content", _intlayer_config_colors.GREY)
|
|
374
|
+
]);
|
|
375
|
+
if (purge) explainDisabled("Dictionary purge");
|
|
376
|
+
if (minify) explainDisabled("Dictionary minification");
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* Reports the dictionaries whose consumption could not be tracked statically,
|
|
380
|
+
* with the source files responsible — those keep their full content.
|
|
381
|
+
*/
|
|
382
|
+
const logUntrackedBindings = (logger, pruneContext) => {
|
|
383
|
+
for (const [dictionaryKey, sourceFilePaths] of pruneContext.dictionaryKeysWithUntrackedBindings) logger([
|
|
384
|
+
`Dictionary`,
|
|
385
|
+
(0, _intlayer_config_logger.colorizeKey)(dictionaryKey),
|
|
386
|
+
`cannot be purged or minified.`,
|
|
387
|
+
`\n Reason: the result of`,
|
|
388
|
+
`${(0, _intlayer_config_logger.colorize)(`useIntlayer(`, _intlayer_config_colors.GREY_LIGHT)}${(0, _intlayer_config_logger.colorizeKey)(`'${dictionaryKey}'`)}${(0, _intlayer_config_logger.colorize)(`)`, _intlayer_config_colors.GREY_LIGHT)}`,
|
|
389
|
+
`is assigned to a plain variable in:`,
|
|
390
|
+
...sourceFilePaths.map((filePath) => `\n - ${(0, _intlayer_engine_utils.formatPath)(filePath)}`)
|
|
391
|
+
], { level: "warn" });
|
|
264
392
|
};
|
|
265
393
|
/**
|
|
266
394
|
* Runs the full purge/minify pipeline for the given options, using a
|
|
267
395
|
* module-level cache so the work happens at most once per process per
|
|
268
396
|
* unique `baseDir`.
|
|
397
|
+
*
|
|
398
|
+
* Exported so bundler integrations that do not go through Babel can drive the
|
|
399
|
+
* same pipeline. The Next.js integration is the main consumer: its SWC plugin
|
|
400
|
+
* runs as a per-file Wasm transform with no filesystem access, so the analysis
|
|
401
|
+
* and the dictionary rewrite happen here, in Node, and only the resulting
|
|
402
|
+
* field-rename tables (see {@link serializeFieldRenameMap}) are forwarded to
|
|
403
|
+
* the plugin.
|
|
404
|
+
*
|
|
405
|
+
* **This performs file I/O**: it reads every source file listed in
|
|
406
|
+
* `componentFilesList` and overwrites the compiled dictionary JSON files
|
|
407
|
+
* in-place. Call it at most once per build, after the dictionaries have been
|
|
408
|
+
* built.
|
|
269
409
|
*/
|
|
270
|
-
const
|
|
271
|
-
const { baseDir, purge, minify, optimize, editorEnabled, dictionariesDir, dynamicDictionariesDir, componentFilesList, dictionaryKeyToImportModeMap, compatCallers } = options;
|
|
410
|
+
const runIntlayerPurgePipeline = (options) => {
|
|
411
|
+
const { baseDir, purge, minify, optimize, editorEnabled, dictionariesDir, dynamicDictionariesDir, componentFilesList, dictionaryKeyToImportModeMap, nestedDictionaryReferences, compatCallers, logConfig } = options;
|
|
272
412
|
const cachedContext = _pruneContextCache.get(baseDir);
|
|
273
413
|
if (cachedContext) return cachedContext;
|
|
274
414
|
const pruneContext = require_babel_plugin_intlayer_usage_analyzer.createPruneContext();
|
|
275
415
|
_pruneContextCache.set(baseDir, pruneContext);
|
|
416
|
+
const logger = (0, _intlayer_config_logger.getAppLogger)(logConfig);
|
|
276
417
|
const shouldPurge = purge && !editorEnabled;
|
|
277
418
|
const shouldMinify = minify && !editorEnabled;
|
|
419
|
+
if (editorEnabled && (purge || minify)) logStepDisabledByEditor(logger, purge, minify);
|
|
278
420
|
if (!shouldPurge && !shouldMinify || optimize === false) return pruneContext;
|
|
279
421
|
for (const sourceFilePath of componentFilesList) {
|
|
280
422
|
if (!require_transformers.SOURCE_FILE_REGEX.test(sourceFilePath)) continue;
|
|
281
423
|
analyzeSourceFileSync(sourceFilePath, pruneContext, compatCallers);
|
|
282
424
|
}
|
|
283
|
-
if (
|
|
284
|
-
|
|
425
|
+
if (nestedDictionaryReferences) require_babel_plugin_intlayer_usage_analyzer.preserveNestedDictionaryFields(pruneContext, nestedDictionaryReferences);
|
|
426
|
+
logUntrackedBindings(logger, pruneContext);
|
|
427
|
+
if (shouldMinify) buildRenameMapsSynchronously(dictionariesDir, dynamicDictionariesDir, dictionaryKeyToImportModeMap, pruneContext, logger);
|
|
428
|
+
processAllDictionaryFiles(dictionariesDir, dynamicDictionariesDir, pruneContext, shouldPurge, shouldMinify, logger);
|
|
285
429
|
return pruneContext;
|
|
286
430
|
};
|
|
287
431
|
/**
|
|
@@ -335,7 +479,7 @@ const runPurgePipeline = (options) => {
|
|
|
335
479
|
const intlayerPurgeBabelPlugin = (_babel) => ({
|
|
336
480
|
name: "intlayer-purge",
|
|
337
481
|
pre() {
|
|
338
|
-
|
|
482
|
+
runIntlayerPurgePipeline(this.opts);
|
|
339
483
|
},
|
|
340
484
|
visitor: {}
|
|
341
485
|
});
|
|
@@ -343,4 +487,5 @@ const intlayerPurgeBabelPlugin = (_babel) => ({
|
|
|
343
487
|
//#endregion
|
|
344
488
|
exports.getSharedPruneContext = getSharedPruneContext;
|
|
345
489
|
exports.intlayerPurgeBabelPlugin = intlayerPurgeBabelPlugin;
|
|
490
|
+
exports.runIntlayerPurgePipeline = runIntlayerPurgePipeline;
|
|
346
491
|
//# sourceMappingURL=babel-plugin-intlayer-purge.cjs.map
|