@intlayer/babel 9.5.1 → 9.5.2
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-optimize.cjs +30 -7
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/cjs/compat/optimizePass.cjs +302 -2
- package/dist/cjs/compat/optimizePass.cjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +30 -7
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/esm/compat/optimizePass.mjs +304 -4
- package/dist/esm/compat/optimizePass.mjs.map +1 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
- package/dist/types/compat/optimizePass.d.ts +49 -4
- package/dist/types/compat/optimizePass.d.ts.map +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimizePass.cjs","names":["getRewritableCallers","resolveNamespaceForRewrite","splitNamespace"],"sources":["../../../src/compat/optimizePass.ts"],"sourcesContent":["import type * as BabelTypes from '@babel/types';\nimport {\n type CallerDescriptor,\n getRewritableCallers,\n} from '@intlayer/config/callers';\nimport type {\n DictionaryImportRegistry,\n ImportMode,\n} from '../dictionaryImports';\nimport { splitNamespace } from '../staticAstReaders';\nimport { resolveNamespaceForRewrite } from './namespaceResolution';\n\n/**\n * Compat half of the optimize pass.\n *\n * Every adapter-specific behaviour of the build-time rewrite lives here:\n * matching a compat caller's import, resolving its namespace, and re-pointing\n * the import specifier at the dictionary-accepting helper.\n *\n * The pass works on plain AST nodes rather than `NodePath`s: the optimize\n * plugin collects the call sites in its single traversal and hands them over,\n * so nothing here walks the tree.\n *\n * It is created only when compat descriptors were injected by a compat\n * package's bundler plugin, so a plain intlayer build never allocates it —\n * {@link createCompatOptimizePass} returns `null` for an empty registry.\n */\nexport type CompatOptimizePass = {\n /**\n * Whether `importSource` exports at least one rewritable compat caller, so\n * the optimize plugin knows the import is worth inspecting even though it is\n * not a native intlayer package.\n */\n ownsImportSource: (importSource: string) => boolean;\n /** Records the local alias one import specifier introduces. */\n noteImport: (\n importSource: string,\n importedName: string,\n localName: string\n ) => void;\n /** Whether `localName` was bound to a compat caller by an import. */\n ownsLocalName: (localName: string) => boolean;\n /** Whether the file imported any compat caller at all. */\n hasCallers: () => boolean;\n /**\n * Resolves the namespace of every collected call, dropping the callers that\n * cannot be rewritten and deciding the file-level helper family. Must run\n * after every import was noted and before any rewrite.\n */\n analyzeCalls: (callNodes: readonly BabelTypes.CallExpression[]) => void;\n /** Rewrites one compat call site, if its caller survived {@link analyzeCalls}. */\n rewriteCall: (callNode: BabelTypes.CallExpression) => void;\n /** Re-points the compat specifiers of one import declaration. */\n rewriteImportSpecifiers: (importNode: BabelTypes.ImportDeclaration) => void;\n};\n\n/**\n * Rewritable slice of a descriptor registry, cached by array reference.\n *\n * Babel reuses one plugin-options object for every file of a build, so the\n * filter runs once per build instead of once per transformed file.\n */\nconst rewritableCallersCache = new WeakMap<\n readonly CallerDescriptor[],\n readonly CallerDescriptor[]\n>();\n\nconst getCachedRewritableCallers = (\n compatCallers: readonly CallerDescriptor[]\n): readonly CallerDescriptor[] => {\n let rewritable = rewritableCallersCache.get(compatCallers);\n\n if (!rewritable) {\n rewritable = getRewritableCallers([...compatCallers]);\n rewritableCallersCache.set(compatCallers, rewritable);\n }\n\n return rewritable;\n};\n\n/**\n * `importSource` → the callers it exports, indexed by their imported name.\n *\n * Built once per descriptor registry so matching an import specifier is two\n * map lookups instead of a scan over every descriptor's `importSources`.\n */\ntype CallerIndex = Map<string, Map<string, CallerDescriptor>>;\n\nconst callerIndexCache = new WeakMap<\n readonly CallerDescriptor[],\n CallerIndex\n>();\n\nconst getCallerIndex = (\n rewritableCallers: readonly CallerDescriptor[]\n): CallerIndex => {\n let index = callerIndexCache.get(rewritableCallers);\n\n if (!index) {\n index = new Map();\n\n for (const descriptor of rewritableCallers) {\n for (const importSource of descriptor.importSources) {\n let byName = index.get(importSource);\n\n if (!byName) {\n byName = new Map();\n index.set(importSource, byName);\n }\n\n byName.set(descriptor.callerName, descriptor);\n }\n }\n\n callerIndexCache.set(rewritableCallers, index);\n }\n\n return index;\n};\n\n/**\n * Builds the compat optimize pass for one source file, or `null` when no\n * compat caller was injected.\n *\n * @param babelTypes - Babel's type helpers.\n * @param compatCallers - Descriptors injected by the compat packages' plugins.\n * @param imports - Shared dictionary-import registry for the file.\n * @param buildModes - The file's global import mode and per-dictionary overrides.\n */\nexport const createCompatOptimizePass = (\n babelTypes: typeof BabelTypes,\n compatCallers: readonly CallerDescriptor[],\n imports: DictionaryImportRegistry,\n buildModes: {\n importMode: ImportMode | undefined;\n dictionaryModeMap?: Record<string, ImportMode | undefined>;\n }\n): CompatOptimizePass | null => {\n const rewritableCallers = getCachedRewritableCallers(compatCallers);\n if (rewritableCallers.length === 0) return null;\n\n const callerIndex = getCallerIndex(rewritableCallers);\n const { importMode, dictionaryModeMap } = buildModes;\n\n /** Local alias → the descriptor it was imported as. */\n const callersByLocalName = new Map<string, CallerDescriptor>();\n\n /**\n * File-level decision: one import specifier serves every call in the file, so\n * a global dynamic/fetch mode — or any per-dictionary override reached from\n * this file — flips all rewritten compat calls to the dynamic helper.\n */\n let useDynamicHelpers = false;\n\n /** Narrows to the two modes that resolve through a per-locale loader. */\n const isDynamicMode = (\n mode: ImportMode | undefined\n ): mode is 'dynamic' | 'fetch' => mode === 'dynamic' || mode === 'fetch';\n\n /** Import mode a compat call site resolves to for `dictionaryKey`. */\n const importModeFor = (dictionaryKey: string): ImportMode => {\n if (!useDynamicHelpers) return 'static';\n\n const override = dictionaryModeMap?.[dictionaryKey];\n if (isDynamicMode(override)) return override;\n\n return isDynamicMode(importMode) ? importMode : 'dynamic';\n };\n\n return {\n ownsImportSource: (importSource) => callerIndex.has(importSource),\n\n noteImport: (importSource, importedName, localName) => {\n const descriptor = callerIndex.get(importSource)?.get(importedName);\n if (descriptor) callersByLocalName.set(localName, descriptor);\n },\n\n ownsLocalName: (localName) => callersByLocalName.has(localName),\n\n hasCallers: () => callersByLocalName.size > 0,\n\n analyzeCalls: (callNodes) => {\n if (callersByLocalName.size === 0) return;\n\n /**\n * Locals with at least one call site whose namespace could not be read:\n * one import specifier serves every call in the file, so re-pointing it\n * while leaving those calls untouched would hand a raw namespace string\n * — or nothing at all — to the dictionary-accepting helper.\n */\n const unresolvableLocalNames = new Set<string>();\n let hasDynamicCall = false;\n\n for (const callNode of callNodes) {\n const callee = callNode.callee;\n if (!babelTypes.isIdentifier(callee)) continue;\n\n const descriptor = callersByLocalName.get(callee.name);\n if (!descriptor) continue;\n\n const namespaceMatch = resolveNamespaceForRewrite(\n babelTypes,\n callNode.arguments,\n descriptor\n );\n\n // No readable namespace — a computed key, or a call that passes none\n // at all (`useTranslations()`). Either way the dictionary is unknown at\n // build time, so the call keeps resolving through the runtime registry\n // and holds back the siblings sharing its import.\n if (!namespaceMatch) {\n unresolvableLocalNames.add(callee.name);\n continue;\n }\n\n const { dictionaryKey } = splitNamespace(namespaceMatch.fullNamespace);\n if (isDynamicMode(dictionaryModeMap?.[dictionaryKey])) {\n hasDynamicCall = true;\n }\n }\n\n for (const localName of unresolvableLocalNames) {\n callersByLocalName.delete(localName);\n }\n\n useDynamicHelpers = isDynamicMode(importMode) || hasDynamicCall;\n },\n\n rewriteCall: (callNode) => {\n const callee = callNode.callee;\n if (!babelTypes.isIdentifier(callee)) return;\n\n const descriptor = callersByLocalName.get(callee.name);\n if (!descriptor) return;\n\n const callArguments = callNode.arguments;\n const namespaceMatch = resolveNamespaceForRewrite(\n babelTypes,\n callArguments,\n descriptor\n );\n // Filtered out by `analyzeCalls` — the import keeps its original specifier.\n if (!namespaceMatch) return;\n\n const { dictionaryKey, keyPrefix } = splitNamespace(\n namespaceMatch.fullNamespace\n );\n const mode = importModeFor(dictionaryKey);\n const ident = imports.identFor(dictionaryKey, mode);\n const isDynamicHelper = mode !== 'static';\n\n if (namespaceMatch.argumentIndex !== undefined) {\n // Positional namespace: replace the string with the dictionary, then\n // the (dynamic) key and the (nested) prefix.\n // useTranslation('about.counter', opts)\n // static → useDictionary(_hash, 'counter', opts)\n // dynamic → useDictionaryDynamic(_hash_dyn, 'about', 'counter', opts)\n callArguments[namespaceMatch.argumentIndex] = babelTypes.identifier(\n ident.name\n );\n\n const insertedArguments: BabelTypes.Expression[] = [];\n if (isDynamicHelper) {\n insertedArguments.push(babelTypes.stringLiteral(dictionaryKey));\n }\n if (keyPrefix) {\n insertedArguments.push(babelTypes.stringLiteral(keyPrefix));\n }\n callArguments.splice(\n namespaceMatch.argumentIndex + 1,\n 0,\n ...insertedArguments\n );\n } else if (isDynamicHelper) {\n // Fixed / option namespace: prepend the loader and the dictionary key.\n callArguments.unshift(\n babelTypes.identifier(ident.name),\n babelTypes.stringLiteral(dictionaryKey)\n );\n } else {\n // Fixed / option namespace, static helper: prepend the dictionary.\n // useLingui() → useDictionary(_hash)\n callArguments.unshift(babelTypes.identifier(ident.name));\n }\n\n // Option namespace: leave only the key-prefix remainder in the options\n // object (or drop the property entirely), so the runtime helper does not\n // re-apply the dictionary key as a lookup prefix.\n // useI18n({ namespace: 'about' }) → useDictionary(_hash, {})\n if (namespaceMatch.optionProperty && namespaceMatch.optionsObject) {\n if (keyPrefix) {\n namespaceMatch.optionProperty.value =\n babelTypes.stringLiteral(keyPrefix);\n } else {\n namespaceMatch.optionsObject.properties =\n namespaceMatch.optionsObject.properties.filter(\n (property) => property !== namespaceMatch.optionProperty\n );\n }\n }\n },\n\n rewriteImportSpecifiers: (importNode) => {\n const byName = callerIndex.get(importNode.source.value);\n if (!byName) return;\n\n for (const specifier of importNode.specifiers) {\n if (!babelTypes.isImportSpecifier(specifier)) continue;\n\n // Only a specifier still held by `callersByLocalName` is rewritable —\n // `analyzeCalls` removed the ones with an unresolvable call site.\n const descriptor = callersByLocalName.get(specifier.local.name);\n if (!descriptor || !byName.has(descriptor.callerName)) continue;\n\n // Keep the local alias so call sites read unchanged; only the imported\n // name moves to the dictionary-accepting helper.\n specifier.imported = babelTypes.identifier(\n useDynamicHelpers\n ? descriptor.dynamicReplacement!\n : descriptor.staticReplacement!\n );\n }\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"optimizePass.cjs","names":["getRewritableCallers","resolveNamespaceForRewrite","resolveNamespaceForAnalysis","readJsxAttributeString","readObjectPropertyNode","readStaticString","splitNamespace"],"sources":["../../../src/compat/optimizePass.ts"],"sourcesContent":["import type * as BabelTypes from '@babel/types';\nimport {\n type CallerDescriptor,\n getRewritableCallers,\n} from '@intlayer/config/callers';\nimport type {\n DictionaryImportRegistry,\n ImportMode,\n} from '../dictionaryImports';\nimport {\n ABSENT_VALUE,\n readJsxAttributeString,\n readObjectPropertyNode,\n readStaticString,\n splitNamespace,\n} from '../staticAstReaders';\nimport {\n resolveNamespaceForAnalysis,\n resolveNamespaceForRewrite,\n} from './namespaceResolution';\n\n/**\n * Compat half of the optimize pass.\n *\n * Every adapter-specific behaviour of the build-time rewrite lives here:\n * matching a compat caller's import, resolving its namespace, and re-pointing\n * the import specifier at the dictionary-accepting helper.\n *\n * The pass works on plain AST nodes rather than `NodePath`s: the optimize\n * plugin collects the call sites in its single traversal and hands them over,\n * so nothing here walks the tree.\n *\n * It is created only when compat descriptors were injected by a compat\n * package's bundler plugin, so a plain intlayer build never allocates it —\n * {@link createCompatOptimizePass} returns `null` for an empty registry.\n */\nexport type CompatOptimizePass = {\n /**\n * Whether `importSource` exports at least one rewritable compat caller, so\n * the optimize plugin knows the import is worth inspecting even though it is\n * not a native intlayer package.\n */\n ownsImportSource: (importSource: string) => boolean;\n /** Records the local alias one import specifier introduces. */\n noteImport: (\n importSource: string,\n importedName: string,\n localName: string\n ) => void;\n /** Whether `localName` was bound to a compat caller by an import. */\n ownsLocalName: (localName: string) => boolean;\n /**\n * Records the names a compat call's result was destructured into\n * (`const { i18n, _, t } = useLingui()`), so a bare `t('…')` call in the\n * file is read as a message-id site of that library. Names that are not\n * message callers of the library are ignored.\n */\n noteDestructuredResult: (localCallerName: string, names: string[]) => void;\n /** Whether the file imported any compat caller at all. */\n hasCallers: () => boolean;\n /**\n * Whether the file imported a root-scope caller whose dictionaries are\n * named by message ids (`useLingui()`), so the traversal must also hand\n * over the id-carrying sites through {@link collectMessageIdSite}. Valid\n * once every import was noted.\n */\n needsMessageIdSites: () => boolean;\n /**\n * Records one node that may carry a message id for a root-scope caller: a\n * call (`i18n._('footer.github')`, `t({ id })`), a tagged template\n * (``t`…` ``) or a JSX opening element (`<Trans id=\"…\" />`). Nodes that\n * match no message caller are ignored.\n */\n collectMessageIdSite: (\n node:\n | BabelTypes.CallExpression\n | BabelTypes.TaggedTemplateExpression\n | BabelTypes.JSXOpeningElement\n ) => void;\n /**\n * Whether the node is an element of a compat JSX caller bound by its id\n * attribute (`<Trans id=\"…\" />`) imported by the file — as source JSX, or\n * already compiled by the framework plugin into `jsx(Trans, { id })`.\n */\n ownsJsxSite: (node: JsxSiteNode) => boolean;\n /**\n * Resolves the namespace of every collected call and element, dropping the\n * callers that cannot be rewritten and deciding the file-level helper\n * family. Must run after every import was noted and every message-id site\n * collected, and before any rewrite.\n *\n * @param countReferences - Number of references a local name has in the\n * file. A JSX caller is only re-pointed when every reference is a bound\n * element: one passed around as a value (`component={Trans}`) would reach\n * the dictionary-accepting replacement without its dictionary.\n */\n analyzeCalls: (\n callNodes: readonly BabelTypes.CallExpression[],\n jsxSites?: readonly JsxSiteNode[],\n countReferences?: (localName: string) => number\n ) => void;\n /** Rewrites one compat call site, if its caller survived {@link analyzeCalls}. */\n rewriteCall: (callNode: BabelTypes.CallExpression) => void;\n /**\n * Binds one compat JSX element, if its caller survived {@link analyzeCalls}:\n * adds the `dictionary` prop naming the dictionary its id addresses.\n */\n rewriteJsxSite: (node: JsxSiteNode) => void;\n /** Re-points the compat specifiers of one import declaration. */\n rewriteImportSpecifiers: (importNode: BabelTypes.ImportDeclaration) => void;\n};\n\n/**\n * A compat JSX element as the pass may meet it: the source element, or the\n * call the automatic/classic JSX runtime compiled it into — the optimize\n * transform runs after the framework plugin, so on Vite the compiled form is\n * the usual one.\n */\nexport type JsxSiteNode =\n | BabelTypes.JSXOpeningElement\n | BabelTypes.CallExpression;\n\n/**\n * Factories a JSX element compiles into — `jsx(Trans, props)` /\n * `_jsxs(Trans, props)` / `jsxRuntime.jsxDEV(Trans, props)` for the automatic\n * runtime, `React.createElement(Trans, props)` for the classic one. The\n * transform aliases the import (`_jsx`), hence the optional underscores.\n */\nconst COMPILED_JSX_FACTORY_PATTERN = /^_*(jsxs?|jsxDEV|createElement)$/;\n\n/**\n * Rewritable slice of a descriptor registry, cached by array reference.\n *\n * Babel reuses one plugin-options object for every file of a build, so the\n * filter runs once per build instead of once per transformed file.\n */\nconst rewritableCallersCache = new WeakMap<\n readonly CallerDescriptor[],\n readonly CallerDescriptor[]\n>();\n\nconst getCachedRewritableCallers = (\n compatCallers: readonly CallerDescriptor[]\n): readonly CallerDescriptor[] => {\n let rewritable = rewritableCallersCache.get(compatCallers);\n\n if (!rewritable) {\n rewritable = getRewritableCallers([...compatCallers]);\n rewritableCallersCache.set(compatCallers, rewritable);\n }\n\n return rewritable;\n};\n\n/**\n * `importSource` → the callers it exports, indexed by their imported name.\n *\n * Built once per descriptor registry so matching an import specifier is two\n * map lookups instead of a scan over every descriptor's `importSources`.\n */\ntype CallerIndex = Map<string, Map<string, CallerDescriptor>>;\n\nconst callerIndexCache = new WeakMap<\n readonly CallerDescriptor[],\n CallerIndex\n>();\n\nconst getCallerIndex = (\n rewritableCallers: readonly CallerDescriptor[]\n): CallerIndex => {\n let index = callerIndexCache.get(rewritableCallers);\n\n if (!index) {\n index = new Map();\n\n for (const descriptor of rewritableCallers) {\n for (const importSource of descriptor.importSources) {\n let byName = index.get(importSource);\n\n if (!byName) {\n byName = new Map();\n index.set(importSource, byName);\n }\n\n byName.set(descriptor.callerName, descriptor);\n }\n }\n\n callerIndexCache.set(rewritableCallers, index);\n }\n\n return index;\n};\n\n/**\n * Prop through which a bound compat JSX element (`<Trans>`) receives its\n * dictionary — the static dictionary, or a `[loader, key]` pair in dynamic\n * mode. The compat package's replacement component reads it.\n */\nconst JSX_DICTIONARY_ATTRIBUTE = 'dictionary';\n\n/**\n * Whether a descriptor's call sites carry the message id themselves, with the\n * dictionary named by the id's first dot-segment (lingui's `_` / `t` /\n * `<Trans>`, react-intl's `formatMessage`). These are the sites a root-scope\n * binding reads its dictionaries from.\n */\nconst isMessageIdCaller = (descriptor: CallerDescriptor): boolean =>\n descriptor.translationFunction === 'self' &&\n descriptor.namespaceSources.some(\n (source) => source.from === 'path-first-segment'\n );\n\n/**\n * `library` → its message-id callers, cached by registry reference.\n *\n * Read from the full registry rather than its rewritable slice: the id\n * callers are matched as methods or JSX and are never rewritten themselves —\n * they only name the dictionaries a root-scope call in the same file binds.\n */\nconst messageIdCallersCache = new WeakMap<\n readonly CallerDescriptor[],\n Map<string, CallerDescriptor[]>\n>();\n\nconst getMessageIdCallersByLibrary = (\n compatCallers: readonly CallerDescriptor[]\n): Map<string, CallerDescriptor[]> => {\n let byLibrary = messageIdCallersCache.get(compatCallers);\n\n if (!byLibrary) {\n byLibrary = new Map();\n\n for (const descriptor of compatCallers) {\n if (!isMessageIdCaller(descriptor)) continue;\n\n let descriptors = byLibrary.get(descriptor.library);\n\n if (!descriptors) {\n descriptors = [];\n byLibrary.set(descriptor.library, descriptors);\n }\n\n descriptors.push(descriptor);\n }\n\n messageIdCallersCache.set(compatCallers, byLibrary);\n }\n\n return byLibrary;\n};\n\n/**\n * The dictionaries a library's root-scope calls bind in the current file:\n * the first segment of every static message id, or `undefined` once a single\n * id could not be read — a computed id may address any dictionary, so the\n * calls must keep resolving through the runtime registry.\n */\ntype RootScopeBinding = Set<string> | undefined;\n\n/**\n * Builds the compat optimize pass for one source file, or `null` when no\n * compat caller was injected.\n *\n * @param babelTypes - Babel's type helpers.\n * @param compatCallers - Descriptors injected by the compat packages' plugins.\n * @param imports - Shared dictionary-import registry for the file.\n * @param buildModes - The file's global import mode and per-dictionary overrides.\n */\nexport const createCompatOptimizePass = (\n babelTypes: typeof BabelTypes,\n compatCallers: readonly CallerDescriptor[],\n imports: DictionaryImportRegistry,\n buildModes: {\n importMode: ImportMode | undefined;\n dictionaryModeMap?: Record<string, ImportMode | undefined>;\n }\n): CompatOptimizePass | null => {\n const rewritableCallers = getCachedRewritableCallers(compatCallers);\n if (rewritableCallers.length === 0) return null;\n\n const callerIndex = getCallerIndex(rewritableCallers);\n const messageIdCallersByLibrary = getMessageIdCallersByLibrary(compatCallers);\n const { importMode, dictionaryModeMap } = buildModes;\n\n /** Local alias → the descriptor it was imported as. */\n const callersByLocalName = new Map<string, CallerDescriptor>();\n\n /**\n * Root-scope binding per library, filled from the message-id sites the\n * traversal hands over. A library is present only once a root-scope caller\n * of it was imported, so the sites of other libraries are never read.\n */\n const rootScopeBindings = new Map<string, RootScopeBinding>();\n\n /**\n * Local names a bare message call may use per library: message callers\n * imported from the library (`import { t } from '@lingui/macro'`) and\n * names destructured from a root-scope call's result\n * (`const { _ } = useLingui()`). A bare `t('…')` bound to anything else —\n * say a local wrapper — is not a message-id site, mirroring the usage\n * analyser; method calls (`i18n._('…')`) match by method name alone.\n */\n const bareMessageCallerNames = new Map<string, Set<string>>();\n\n /**\n * Bare calls met during the traversal, decided once every binding name is\n * known — a destructuring may sit below the call sites in source order.\n */\n const pendingBareCalls: {\n library: string;\n name: string;\n node: BabelTypes.CallExpression;\n }[] = [];\n\n const addBareMessageCallerName = (library: string, name: string): void => {\n let names = bareMessageCallerNames.get(library);\n if (!names) {\n names = new Set();\n bareMessageCallerNames.set(library, names);\n }\n names.add(name);\n };\n\n /**\n * File-level decision: one import specifier serves every call in the file, so\n * a global dynamic/fetch mode — or any per-dictionary override reached from\n * this file — flips all rewritten compat calls to the dynamic helper.\n */\n let useDynamicHelpers = false;\n\n /** Narrows to the two modes that resolve through a per-locale loader. */\n const isDynamicMode = (\n mode: ImportMode | undefined\n ): mode is 'dynamic' | 'fetch' => mode === 'dynamic' || mode === 'fetch';\n\n /** Import mode a compat call site resolves to for `dictionaryKey`. */\n const importModeFor = (dictionaryKey: string): ImportMode => {\n if (!useDynamicHelpers) return 'static';\n\n const override = dictionaryModeMap?.[dictionaryKey];\n if (isDynamicMode(override)) return override;\n\n return isDynamicMode(importMode) ? importMode : 'dynamic';\n };\n\n /**\n * Whether a call binds through the root-scope path: its descriptor allows\n * it, the library has id callers to read from, and the call itself names\n * no dictionary (`useLingui()`).\n */\n const isRootScopeCall = (\n descriptor: CallerDescriptor,\n callArguments: BabelTypes.CallExpression['arguments']\n ): boolean =>\n descriptor.allowRootScope === true &&\n messageIdCallersByLibrary.has(descriptor.library) &&\n resolveNamespaceForRewrite(babelTypes, callArguments, descriptor) ===\n undefined;\n\n /** Name a callee or tag reads as, whether bare (`t`) or a method (`i18n.t`). */\n const readCalleeName = (\n node: BabelTypes.Node\n ): { name: string; isMethod: boolean } | undefined => {\n if (babelTypes.isIdentifier(node)) {\n return { name: node.name, isMethod: false };\n }\n if (\n babelTypes.isMemberExpression(node) &&\n babelTypes.isIdentifier(node.property) &&\n !node.computed\n ) {\n return { name: node.property.name, isMethod: true };\n }\n return undefined;\n };\n\n /** The id descriptor of `library` matching a callee name, if any. */\n const findMessageIdCaller = (\n library: string,\n callee: { name: string; isMethod: boolean } | undefined,\n shape: 'call' | 'tagged-template'\n ): CallerDescriptor | undefined => {\n if (!callee) return undefined;\n\n return messageIdCallersByLibrary\n .get(library)\n ?.find(\n (descriptor) =>\n descriptor.callerName === callee.name &&\n (shape === 'tagged-template'\n ? descriptor.matchAsTaggedTemplate === true\n : !callee.isMethod || descriptor.matchAsMethod === true)\n );\n };\n\n /** Records the dictionary key read from one message call's arguments. */\n const recordMessageCall = (\n library: string,\n descriptor: CallerDescriptor,\n callArguments: BabelTypes.CallExpression['arguments']\n ): void => {\n const resolved = resolveNamespaceForAnalysis(\n babelTypes,\n callArguments,\n descriptor.namespaceSources\n );\n\n recordRootScopeKey(\n library,\n typeof resolved === 'string' && resolved !== ABSENT_VALUE\n ? resolved\n : undefined\n );\n };\n\n /** Records one dictionary key for `library`, or poisons its binding. */\n const recordRootScopeKey = (\n library: string,\n dictionaryKey: string | undefined\n ): void => {\n const binding = rootScopeBindings.get(library);\n // Already poisoned: nothing can un-poison a file.\n if (binding === undefined) return;\n\n if (dictionaryKey === undefined) {\n rootScopeBindings.set(library, undefined);\n return;\n }\n\n binding.add(dictionaryKey);\n };\n\n /**\n * The dictionary an id-derived key binds: the key itself when the build\n * produced such a dictionary, else the library's whole-file catalog\n * (`messages` for lingui, `index` otherwise) with the id kept intact, else\n * `undefined` — nothing to bind safely.\n *\n * Id-derived keys are guesses, so the set of dictionaries the build actually\n * produced is required to tell a dictionary from a group inside the\n * whole-file catalog.\n */\n const settleDictionaryKey = (\n key: string,\n descriptor: CallerDescriptor\n ): string | undefined => {\n if (!dictionaryModeMap) return undefined;\n if (key in dictionaryModeMap) return key;\n\n const rootKey = descriptor.rootDictionaryKey ?? 'index';\n return rootKey in dictionaryModeMap ? rootKey : undefined;\n };\n\n /**\n * Settles every collected key of a library's root-scope binding, poisoning\n * it when one key has nothing to bind — or when no id was read at all, since\n * a call with nothing to bind must keep the registry.\n */\n const settleRootScopeBinding = (\n library: string,\n descriptor: CallerDescriptor\n ): void => {\n const binding = rootScopeBindings.get(library);\n if (binding === undefined || binding.size === 0) {\n rootScopeBindings.set(library, undefined);\n return;\n }\n\n const settled = new Set<string>();\n\n for (const key of binding) {\n const dictionaryKey = settleDictionaryKey(key, descriptor);\n if (dictionaryKey === undefined) {\n rootScopeBindings.set(library, undefined);\n return;\n }\n settled.add(dictionaryKey);\n }\n\n rootScopeBindings.set(library, settled);\n };\n\n /**\n * A JSX element in either of its shapes, reduced to what the pass needs:\n * the component's local name, its static id, and a way to add a prop.\n */\n type JsxSite = {\n localName: string;\n /** The static id attribute as a string node, `undefined` when dynamic or absent. */\n readId: (attributeName: string) => BabelTypes.StringLiteral | undefined;\n addProp: (name: string, value: BabelTypes.Expression) => void;\n };\n\n const readJsxSite = (node: JsxSiteNode): JsxSite | undefined => {\n if (babelTypes.isJSXOpeningElement(node)) {\n if (!babelTypes.isJSXIdentifier(node.name)) return undefined;\n\n return {\n localName: node.name.name,\n readId: (attributeName) =>\n readJsxAttributeString(babelTypes, node, attributeName),\n addProp: (name, value) => {\n node.attributes.push(\n babelTypes.jsxAttribute(\n babelTypes.jsxIdentifier(name),\n babelTypes.jsxExpressionContainer(value)\n )\n );\n },\n };\n }\n\n // Compiled form: `jsx(Trans, { id: \"…\" })` / `React.createElement(Trans, {…})`.\n const callee = readCalleeName(node.callee);\n if (!callee || !COMPILED_JSX_FACTORY_PATTERN.test(callee.name)) {\n return undefined;\n }\n\n const [component, props] = node.arguments;\n if (\n !babelTypes.isIdentifier(component) ||\n !babelTypes.isObjectExpression(props)\n ) {\n return undefined;\n }\n\n return {\n localName: component.name,\n readId: (attributeName) => {\n const idNode = readObjectPropertyNode(babelTypes, props, attributeName);\n if (idNode === ABSENT_VALUE) return undefined;\n const id = readStaticString(babelTypes, idNode);\n return id === undefined ? undefined : babelTypes.stringLiteral(id);\n },\n addProp: (name, value) => {\n props.properties.push(\n babelTypes.objectProperty(babelTypes.identifier(name), value)\n );\n },\n };\n };\n\n /** The compat JSX descriptor a site's component was imported as, if any. */\n const jsxDescriptorFor = (\n site: JsxSite | undefined\n ): CallerDescriptor | undefined => {\n if (!site) return undefined;\n const descriptor = callersByLocalName.get(site.localName);\n return descriptor?.jsxIdAttribute !== undefined ? descriptor : undefined;\n };\n\n /**\n * The dictionary a compat JSX element binds, read from the first segment of\n * its static id attribute — `undefined` when the id is dynamic or names\n * nothing the build produced.\n */\n const resolveJsxDictionaryKey = (\n site: JsxSite,\n descriptor: CallerDescriptor\n ): string | undefined => {\n const idAttribute = site.readId(descriptor.jsxIdAttribute!);\n if (!idAttribute) return undefined;\n\n const resolved = resolveNamespaceForAnalysis(\n babelTypes,\n [idAttribute],\n descriptor.namespaceSources\n );\n if (typeof resolved !== 'string' || resolved === ABSENT_VALUE) {\n return undefined;\n }\n\n return settleDictionaryKey(resolved, descriptor);\n };\n\n return {\n ownsImportSource: (importSource) => callerIndex.has(importSource),\n\n noteImport: (importSource, importedName, localName) => {\n for (const [library, descriptors] of messageIdCallersByLibrary) {\n if (\n descriptors.some(\n (candidate) =>\n candidate.callerName === importedName &&\n candidate.importSources.includes(importSource)\n )\n ) {\n addBareMessageCallerName(library, localName);\n }\n }\n\n const descriptor = callerIndex.get(importSource)?.get(importedName);\n if (!descriptor) return;\n\n callersByLocalName.set(localName, descriptor);\n\n if (\n descriptor.allowRootScope &&\n messageIdCallersByLibrary.has(descriptor.library) &&\n !rootScopeBindings.has(descriptor.library)\n ) {\n rootScopeBindings.set(descriptor.library, new Set());\n }\n },\n\n ownsLocalName: (localName) => callersByLocalName.has(localName),\n\n noteDestructuredResult: (localCallerName, names) => {\n const descriptor = callersByLocalName.get(localCallerName);\n if (!descriptor?.allowRootScope) return;\n\n const messageCallers = messageIdCallersByLibrary.get(descriptor.library);\n if (!messageCallers) return;\n\n for (const name of names) {\n if (messageCallers.some((candidate) => candidate.callerName === name)) {\n addBareMessageCallerName(descriptor.library, name);\n }\n }\n },\n\n hasCallers: () => callersByLocalName.size > 0,\n\n needsMessageIdSites: () => rootScopeBindings.size > 0,\n\n ownsJsxSite: (node) => jsxDescriptorFor(readJsxSite(node)) !== undefined,\n\n collectMessageIdSite: (node) => {\n for (const library of rootScopeBindings.keys()) {\n // An element — as JSX or as the call it compiled into — matched by\n // the component's name against the library's JSX id callers.\n const jsxSite = babelTypes.isTaggedTemplateExpression(node)\n ? undefined\n : readJsxSite(node);\n if (jsxSite) {\n const descriptor = messageIdCallersByLibrary\n .get(library)\n ?.find(\n (candidate) =>\n candidate.callerName === jsxSite.localName &&\n candidate.jsxIdAttribute !== undefined\n );\n if (!descriptor) continue;\n\n const idAttribute = jsxSite.readId(descriptor.jsxIdAttribute!);\n const resolved = idAttribute\n ? resolveNamespaceForAnalysis(\n babelTypes,\n [idAttribute],\n descriptor.namespaceSources\n )\n : undefined;\n\n recordRootScopeKey(\n library,\n typeof resolved === 'string' && resolved !== ABSENT_VALUE\n ? resolved\n : undefined\n );\n continue;\n }\n\n if (babelTypes.isJSXOpeningElement(node)) continue;\n\n if (babelTypes.isTaggedTemplateExpression(node)) {\n // A macro template (``t`Hello ${name}` ``) has no id until the\n // lingui macro plugin compiles it, so reaching one here means the\n // id is unknowable.\n const descriptor = findMessageIdCaller(\n library,\n readCalleeName(node.tag),\n 'tagged-template'\n );\n if (descriptor) recordRootScopeKey(library, undefined);\n continue;\n }\n\n const callee = readCalleeName(node.callee);\n const descriptor = findMessageIdCaller(library, callee, 'call');\n if (!descriptor || !callee) continue;\n\n if (!callee.isMethod) {\n pendingBareCalls.push({ library, name: callee.name, node });\n continue;\n }\n\n recordMessageCall(library, descriptor, node.arguments);\n }\n },\n\n analyzeCalls: (callNodes, jsxSites = [], countReferences) => {\n if (callersByLocalName.size === 0) return;\n\n /**\n * Locals with at least one call site whose namespace could not be read:\n * one import specifier serves every call in the file, so re-pointing it\n * while leaving those calls untouched would hand a raw namespace string\n * — or nothing at all — to the dictionary-accepting helper.\n */\n const unresolvableLocalNames = new Set<string>();\n let hasDynamicCall = false;\n const settledLibraries = new Set<string>();\n\n for (const { library, name, node } of pendingBareCalls) {\n if (!bareMessageCallerNames.get(library)?.has(name)) continue;\n\n const descriptor = findMessageIdCaller(\n library,\n { name, isMethod: false },\n 'call'\n );\n if (descriptor) recordMessageCall(library, descriptor, node.arguments);\n }\n pendingBareCalls.length = 0;\n\n for (const callNode of callNodes) {\n const callee = callNode.callee;\n if (!babelTypes.isIdentifier(callee)) continue;\n\n const descriptor = callersByLocalName.get(callee.name);\n if (!descriptor) continue;\n\n if (isRootScopeCall(descriptor, callNode.arguments)) {\n if (!settledLibraries.has(descriptor.library)) {\n settleRootScopeBinding(descriptor.library, descriptor);\n settledLibraries.add(descriptor.library);\n }\n\n const binding = rootScopeBindings.get(descriptor.library);\n if (binding === undefined) {\n unresolvableLocalNames.add(callee.name);\n continue;\n }\n\n for (const dictionaryKey of binding) {\n if (isDynamicMode(dictionaryModeMap?.[dictionaryKey])) {\n hasDynamicCall = true;\n }\n }\n continue;\n }\n\n const namespaceMatch = resolveNamespaceForRewrite(\n babelTypes,\n callNode.arguments,\n descriptor\n );\n\n // No readable namespace — a computed key, or a call that passes none\n // at all (`useTranslations()`). Either way the dictionary is unknown at\n // build time, so the call keeps resolving through the runtime registry\n // and holds back the siblings sharing its import.\n if (!namespaceMatch) {\n unresolvableLocalNames.add(callee.name);\n continue;\n }\n\n const { dictionaryKey } = splitNamespace(namespaceMatch.fullNamespace);\n if (isDynamicMode(dictionaryModeMap?.[dictionaryKey])) {\n hasDynamicCall = true;\n }\n }\n\n /** Bound elements seen per JSX caller local, to match against references. */\n const jsxSiteCounts = new Map<string, number>();\n\n for (const jsxNode of jsxSites) {\n const site = readJsxSite(jsxNode);\n const descriptor = jsxDescriptorFor(site);\n if (!site || !descriptor) continue;\n\n jsxSiteCounts.set(\n site.localName,\n (jsxSiteCounts.get(site.localName) ?? 0) + 1\n );\n\n const dictionaryKey = resolveJsxDictionaryKey(site, descriptor);\n if (dictionaryKey === undefined) {\n unresolvableLocalNames.add(site.localName);\n continue;\n }\n\n if (isDynamicMode(dictionaryModeMap?.[dictionaryKey])) {\n hasDynamicCall = true;\n }\n }\n\n // A JSX caller is re-pointed only when every reference to it is an\n // element the pass binds — the import specifier serves them all.\n for (const [localName, descriptor] of callersByLocalName) {\n if (descriptor.jsxIdAttribute === undefined) continue;\n\n const boundSites = jsxSiteCounts.get(localName) ?? 0;\n const references = countReferences?.(localName) ?? boundSites;\n if (boundSites === 0 || references !== boundSites) {\n unresolvableLocalNames.add(localName);\n }\n }\n\n for (const localName of unresolvableLocalNames) {\n callersByLocalName.delete(localName);\n }\n\n useDynamicHelpers = isDynamicMode(importMode) || hasDynamicCall;\n },\n\n rewriteCall: (callNode) => {\n const callee = callNode.callee;\n if (!babelTypes.isIdentifier(callee)) return;\n\n const descriptor = callersByLocalName.get(callee.name);\n if (!descriptor) return;\n\n const callArguments = callNode.arguments;\n\n if (isRootScopeCall(descriptor, callArguments)) {\n // Filtered out by `analyzeCalls` when poisoned — never reached here.\n const binding = rootScopeBindings.get(descriptor.library);\n if (binding === undefined) return;\n\n // Root scope: every dictionary named in the file, ids kept intact so\n // the runtime picks the dictionary by first segment.\n // useLingui()\n // static → useDictionary(_footer, _header)\n // dynamic → useDictionaryDynamic([_footer_dyn, 'footer'], …)\n for (const dictionaryKey of binding) {\n const mode = importModeFor(dictionaryKey);\n const ident = babelTypes.identifier(\n imports.identFor(dictionaryKey, mode).name\n );\n\n callArguments.push(\n mode === 'static'\n ? ident\n : babelTypes.arrayExpression([\n ident,\n babelTypes.stringLiteral(dictionaryKey),\n ])\n );\n }\n return;\n }\n\n const namespaceMatch = resolveNamespaceForRewrite(\n babelTypes,\n callArguments,\n descriptor\n );\n // Filtered out by `analyzeCalls` — the import keeps its original specifier.\n if (!namespaceMatch) return;\n\n const { dictionaryKey, keyPrefix } = splitNamespace(\n namespaceMatch.fullNamespace\n );\n const mode = importModeFor(dictionaryKey);\n const ident = imports.identFor(dictionaryKey, mode);\n const isDynamicHelper = mode !== 'static';\n\n if (namespaceMatch.argumentIndex !== undefined) {\n // Positional namespace: replace the string with the dictionary, then\n // the (dynamic) key and the (nested) prefix.\n // useTranslation('about.counter', opts)\n // static → useDictionary(_hash, 'counter', opts)\n // dynamic → useDictionaryDynamic(_hash_dyn, 'about', 'counter', opts)\n callArguments[namespaceMatch.argumentIndex] = babelTypes.identifier(\n ident.name\n );\n\n const insertedArguments: BabelTypes.Expression[] = [];\n if (isDynamicHelper) {\n insertedArguments.push(babelTypes.stringLiteral(dictionaryKey));\n }\n if (keyPrefix) {\n insertedArguments.push(babelTypes.stringLiteral(keyPrefix));\n }\n callArguments.splice(\n namespaceMatch.argumentIndex + 1,\n 0,\n ...insertedArguments\n );\n } else if (isDynamicHelper) {\n // Fixed / option namespace: prepend the loader and the dictionary key.\n callArguments.unshift(\n babelTypes.identifier(ident.name),\n babelTypes.stringLiteral(dictionaryKey)\n );\n } else {\n // Fixed / option namespace, static helper: prepend the dictionary.\n callArguments.unshift(babelTypes.identifier(ident.name));\n }\n\n // Option namespace: leave only the key-prefix remainder in the options\n // object (or drop the property entirely), so the runtime helper does not\n // re-apply the dictionary key as a lookup prefix.\n // useI18n({ namespace: 'about' }) → useDictionary(_hash, {})\n if (namespaceMatch.optionProperty && namespaceMatch.optionsObject) {\n if (keyPrefix) {\n namespaceMatch.optionProperty.value =\n babelTypes.stringLiteral(keyPrefix);\n } else {\n namespaceMatch.optionsObject.properties =\n namespaceMatch.optionsObject.properties.filter(\n (property) => property !== namespaceMatch.optionProperty\n );\n }\n }\n },\n\n rewriteJsxSite: (node) => {\n const site = readJsxSite(node);\n const descriptor = jsxDescriptorFor(site);\n if (!site || !descriptor) return;\n\n // Filtered out by `analyzeCalls` when unresolvable — never reached here.\n const dictionaryKey = resolveJsxDictionaryKey(site, descriptor);\n if (dictionaryKey === undefined) return;\n\n const mode = importModeFor(dictionaryKey);\n const ident = babelTypes.identifier(\n imports.identFor(dictionaryKey, mode).name\n );\n\n // The id stays intact; the element receives the dictionary it names.\n // <Trans id=\"footer.github\" />\n // static → <Trans id=\"footer.github\" dictionary={_footer} />\n // dynamic → <Trans id=\"footer.github\" dictionary={[_footer_dyn, 'footer']} />\n site.addProp(\n JSX_DICTIONARY_ATTRIBUTE,\n mode === 'static'\n ? ident\n : babelTypes.arrayExpression([\n ident,\n babelTypes.stringLiteral(dictionaryKey),\n ])\n );\n },\n\n rewriteImportSpecifiers: (importNode) => {\n const byName = callerIndex.get(importNode.source.value);\n if (!byName) return;\n\n for (const specifier of importNode.specifiers) {\n if (!babelTypes.isImportSpecifier(specifier)) continue;\n\n // Only a specifier still held by `callersByLocalName` is rewritable —\n // `analyzeCalls` removed the ones with an unresolvable call site.\n const descriptor = callersByLocalName.get(specifier.local.name);\n if (!descriptor || !byName.has(descriptor.callerName)) continue;\n\n // Keep the local alias so call sites read unchanged; only the imported\n // name moves to the dictionary-accepting helper.\n specifier.imported = babelTypes.identifier(\n useDynamicHelpers\n ? descriptor.dynamicReplacement!\n : descriptor.staticReplacement!\n );\n }\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -315,12 +315,34 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
315
315
|
}
|
|
316
316
|
const nativeCallNodes = [];
|
|
317
317
|
const compatCallNodes = [];
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Compat JSX elements bound by their id attribute (`<Trans id>`),
|
|
320
|
+
* as source JSX or as the `jsx(Trans, …)` call the framework plugin
|
|
321
|
+
* already compiled them into.
|
|
322
|
+
*/
|
|
323
|
+
const compatJsxNodes = [];
|
|
324
|
+
const collectMessageIds = compat?.needsMessageIdSites() ?? false;
|
|
325
|
+
if (callerMap.size > 0 || compat?.hasCallers()) programPath.traverse({
|
|
326
|
+
CallExpression(path) {
|
|
327
|
+
if (collectMessageIds) compat?.collectMessageIdSite(path.node);
|
|
328
|
+
if (compat?.ownsJsxSite(path.node)) compatJsxNodes.push(path.node);
|
|
329
|
+
const callee = path.node.callee;
|
|
330
|
+
if (!t.isIdentifier(callee)) return;
|
|
331
|
+
if (callerMap.has(callee.name)) nativeCallNodes.push(path.node);
|
|
332
|
+
else if (compat?.ownsLocalName(callee.name)) {
|
|
333
|
+
compatCallNodes.push(path.node);
|
|
334
|
+
const declarator = path.parent;
|
|
335
|
+
if (t.isVariableDeclarator(declarator) && t.isObjectPattern(declarator.id)) compat.noteDestructuredResult(callee.name, declarator.id.properties.flatMap((property) => t.isObjectProperty(property) && t.isIdentifier(property.value) ? [property.value.name] : []));
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
...collectMessageIds ? { TaggedTemplateExpression(path) {
|
|
339
|
+
compat?.collectMessageIdSite(path.node);
|
|
340
|
+
} } : {},
|
|
341
|
+
...compat ? { JSXOpeningElement(path) {
|
|
342
|
+
if (collectMessageIds) compat.collectMessageIdSite(path.node);
|
|
343
|
+
if (compat.ownsJsxSite(path.node)) compatJsxNodes.push(path.node);
|
|
344
|
+
} } : {}
|
|
345
|
+
});
|
|
324
346
|
const packagesWithDynamicCall = /* @__PURE__ */ new Set();
|
|
325
347
|
const packagesWithFetchCall = /* @__PURE__ */ new Set();
|
|
326
348
|
for (const callNode of nativeCallNodes) {
|
|
@@ -334,7 +356,7 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
334
356
|
if (overrideMode === "dynamic") packagesWithDynamicCall.add(callerPackage);
|
|
335
357
|
else if (overrideMode === "fetch") packagesWithFetchCall.add(callerPackage);
|
|
336
358
|
}
|
|
337
|
-
compat?.analyzeCalls(compatCallNodes);
|
|
359
|
+
compat?.analyzeCalls(compatCallNodes, compatJsxNodes, (localName) => programPath.scope.getBinding(localName)?.referencePaths.length ?? 0);
|
|
338
360
|
const helperPlanCache = /* @__PURE__ */ new Map();
|
|
339
361
|
const getHelperPlan = (packageName) => {
|
|
340
362
|
let plan = helperPlanCache.get(packageName);
|
|
@@ -372,6 +394,7 @@ const intlayerOptimizeBabelPlugin = (babel) => {
|
|
|
372
394
|
}
|
|
373
395
|
}
|
|
374
396
|
for (const callNode of compatCallNodes) compat?.rewriteCall(callNode);
|
|
397
|
+
for (const jsxNode of compatJsxNodes) compat?.rewriteJsxSite(jsxNode);
|
|
375
398
|
for (const callNode of nativeCallNodes) {
|
|
376
399
|
const callee = callNode.callee;
|
|
377
400
|
const originalImportedName = callerMap.get(callee.name);
|
|
@@ -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 { PluginObject, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport type { CallerDescriptor } from '@intlayer/config/callers';\nimport { normalizePath } from '@intlayer/config/utils';\nimport { createCompatOptimizePass } from './compat/optimizePass';\nimport {\n createDictionaryImportRegistry,\n type DictionaryImportRegistry,\n type ImportMode,\n} from './dictionaryImports';\nimport { getNormalizedFilesListSet } from './normalizedFilesList';\nimport { readStaticString } from './staticAstReaders';\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', 'getIntlayerAsync'] as const;\n\n/** Membership sets for the tables above — hit once per import and per call. */\nconst NATIVE_PACKAGE_SET: ReadonlySet<string> = new Set(PACKAGE_LIST);\nconst CALLER_NAME_SET: ReadonlySet<string> = new Set(CALLER_LIST);\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 DYNAMIC_PACKAGE_SET: ReadonlySet<string> = new Set(PACKAGE_LIST_DYNAMIC);\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n // `getIntlayerAsync` always reads a per-locale chunk, in every import mode,\n // so its helper is the same on both sides of the static/dynamic split.\n getIntlayerAsync: 'getDictionaryAsync',\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];\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\n/**\n * Per-file plugin state.\n *\n * Only the two flags that have to survive from `pre` / `Program.enter` into\n * `Program.exit` live here — the caller maps and the import registry are built\n * and consumed inside `exit`, so they stay local to it.\n */\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** Whether the current file *is* a generated dictionaries entry file. */\n _isDictEntry?: boolean;\n /** Whether the current file is covered by the `filesList` allowlist. */\n _isIncluded?: boolean;\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 isCallerName = (name: string): name is CallerName =>\n CALLER_NAME_SET.has(name);\n\nconst isDynamicPackage = (packageName: string): boolean =>\n DYNAMIC_PACKAGE_SET.has(packageName);\n\n/** The name an import specifier brings in, whether written as an identifier or a string. */\nconst importedSpecifierName = (\n babelTypes: typeof BabelTypes,\n specifier: BabelTypes.ImportSpecifier\n): string =>\n babelTypes.isIdentifier(specifier.imported)\n ? specifier.imported.name\n : specifier.imported.value;\n\nconst EMPTY_KEY_SET: ReadonlySet<string> = new Set<string>();\n\n/**\n * `nestingDictionaryKeys` as a set, cached by array reference: Babel reuses one\n * options object for the whole build, so the set is built once instead of once\n * per transformed file.\n */\nconst nestingKeysCache = new WeakMap<readonly string[], ReadonlySet<string>>();\n\nconst getNestingDictionaryKeySet = (\n nestingDictionaryKeys: readonly string[] | undefined\n): ReadonlySet<string> => {\n if (!nestingDictionaryKeys) return EMPTY_KEY_SET;\n\n let keySet = nestingKeysCache.get(nestingDictionaryKeys);\n\n if (!keySet) {\n keySet = new Set(nestingDictionaryKeys);\n nestingKeysCache.set(nestingDictionaryKeys, keySet);\n }\n\n return keySet;\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 * Builds the dictionary import declarations the rewrite accumulated for one\n * file — the compiled JSON (or its `nest()` companion) for static reads, and\n * the generated per-locale loader for dynamic and fetch ones.\n */\nconst buildDictionaryImportDeclarations = (\n babelTypes: typeof BabelTypes,\n state: State,\n imports: DictionaryImportRegistry\n): BabelTypes.ImportDeclaration[] => {\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n nestingDictionaryKeys,\n } = state.opts;\n const fromFile = state.file.opts.filename!;\n const nestingKeys = getNestingDictionaryKeySet(nestingDictionaryKeys);\n\n const importDeclarations: BabelTypes.ImportDeclaration[] = [];\n\n // Static JSON imports — `getIntlayer` always reads a JSON dictionary.\n for (const [key, ident] of imports.staticImports) {\n // A dictionary holding `nest()` references is imported through its\n // companion module, which re-exports it with the nest targets attached.\n const hasNestedDictionaries = nestingKeys.has(key);\n\n const specifier = computeImport(\n fromFile,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static',\n hasNestedDictionaries\n );\n\n const importDeclaration = babelTypes.importDeclaration(\n [babelTypes.importDefaultSpecifier(babelTypes.identifier(ident.name))],\n babelTypes.stringLiteral(specifier)\n );\n\n if (!hasNestedDictionaries) {\n importDeclaration.attributes = [\n babelTypes.importAttribute(\n babelTypes.identifier('type'),\n babelTypes.stringLiteral('json')\n ),\n ];\n }\n\n importDeclarations.push(importDeclaration);\n }\n\n // Per-locale loaders — `useIntlayer` under a dynamic or fetch helper.\n for (const [key, ident] of imports.dynamicImports) {\n const mode: ImportMode = ident.name.endsWith('_fetch')\n ? 'fetch'\n : 'dynamic';\n\n importDeclarations.push(\n babelTypes.importDeclaration(\n [babelTypes.importDefaultSpecifier(babelTypes.identifier(ident.name))],\n babelTypes.stringLiteral(\n computeImport(\n fromFile,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n mode\n )\n )\n )\n );\n }\n\n return importDeclarations;\n};\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()`, `getIntlayer()` and\n * `getIntlayerAsync()` from various Intlayer packages into optimized dictionary\n * access patterns, automatically importing the required dictionary files based\n * 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 / getIntlayerAsync\n * import { getIntlayer, getIntlayerAsync } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * const content = await getIntlayerAsync('app', locale);\n * ```\n *\n * `getIntlayerAsync` is the exception to the mode table below: it always\n * resolves to the per-locale loader (`getDictionaryAsync`), in every import\n * mode, since loading a single locale is what it exists for.\n *\n * **Output (any mode):**\n * ```ts\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { getDictionaryAsync as getIntlayerAsync } from 'intlayer';\n *\n * const content = await getIntlayerAsync(_dicHash_dyn, 'app', locale);\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._isIncluded = true;\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 // If this file *is* the dictionaries entry, short-circuit: export {}\n // Note: unmerged_dictionaries.mjs is used by the visual editor and CMS\n // and must not be replaced with an empty dictionary map.\n if (\n state.opts.replaceDictionaryEntry &&\n filename &&\n filename === dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n programPath.node.body = [\n t.exportDefaultDeclaration(t.objectExpression([])),\n t.exportNamedDeclaration(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier('getDictionaries'),\n t.arrowFunctionExpression([], t.objectExpression([]))\n ),\n ])\n ),\n ];\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 const imports = createDictionaryImportRegistry(t);\n\n // Compat adapters plug in here and nowhere else: with no descriptor\n // injected the pass is `null`, every `compat?.` below is a no-op and\n // the native rewrite runs exactly as if the adapters did not exist.\n const compat = createCompatOptimizePass(\n t,\n state.opts.compatCallers ?? [],\n imports,\n {\n importMode: state.opts.importMode,\n dictionaryModeMap: state.opts.dictionaryModeMap,\n }\n );\n\n // ── Step 1 — imports.\n //\n // An import declaration is only ever a direct child of Program, so\n // the body is scanned instead of walking the whole AST, and the\n // result is complete before any call site is inspected (a file may\n // import below the calls it governs).\n const programBody = programPath.node.body;\n const nativeImportNodes: BabelTypes.ImportDeclaration[] = [];\n const compatImportNodes: BabelTypes.ImportDeclaration[] = [];\n /** Local alias → the native caller it was imported as. */\n const callerMap = new Map<string, CallerName>();\n /** Local alias → the intlayer package it was imported from. */\n const callerPackageMap = new Map<string, string>();\n /** Whether the file imported any native or compat caller at all. */\n let hasValidImport = false;\n\n for (const statement of programBody) {\n if (!t.isImportDeclaration(statement)) continue;\n\n const src = statement.source.value;\n const isNativePackage = NATIVE_PACKAGE_SET.has(src);\n const isCompatPackage = compat?.ownsImportSource(src) ?? false;\n\n if (!isNativePackage && !isCompatPackage) continue;\n\n hasValidImport = true;\n if (isNativePackage) nativeImportNodes.push(statement);\n if (isCompatPackage) compatImportNodes.push(statement);\n\n for (const spec of statement.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = importedSpecifierName(t, spec);\n\n if (isNativePackage && isCallerName(importedName)) {\n callerMap.set(spec.local.name, importedName);\n callerPackageMap.set(spec.local.name, src);\n }\n\n if (isCompatPackage) {\n compat?.noteImport(src, importedName, spec.local.name);\n }\n }\n }\n\n // ── Step 2 — the file's only AST walk, collecting the call sites\n // that either half of the rewrite can act on. Everything after\n // this point works on the collected arrays.\n const nativeCallNodes: BabelTypes.CallExpression[] = [];\n const compatCallNodes: BabelTypes.CallExpression[] = [];\n\n if (callerMap.size > 0 || compat?.hasCallers()) {\n programPath.traverse({\n CallExpression(path) {\n const callee = path.node.callee;\n if (!t.isIdentifier(callee)) return;\n\n if (callerMap.has(callee.name)) {\n nativeCallNodes.push(path.node);\n } else if (compat?.ownsLocalName(callee.name)) {\n compatCallNodes.push(path.node);\n }\n },\n });\n }\n\n // ── Step 3 — analysis.\n //\n // A per-dictionary override reached from this file can promote a\n // whole package import to a dynamic loader, so the helper family is\n // decided per package before anything is rewritten.\n const packagesWithDynamicCall = new Set<string>();\n const packagesWithFetchCall = new Set<string>();\n\n for (const callNode of nativeCallNodes) {\n const callee = callNode.callee as BabelTypes.Identifier;\n if (callerMap.get(callee.name) !== 'useIntlayer') continue;\n\n const callerPackage = callerPackageMap.get(callee.name);\n if (!callerPackage) continue;\n\n const key = readStaticString(t, callNode.arguments[0]);\n if (!key) continue;\n\n const overrideMode = state.opts.dictionaryModeMap?.[key];\n\n if (overrideMode === 'dynamic') {\n packagesWithDynamicCall.add(callerPackage);\n } else if (overrideMode === 'fetch') {\n packagesWithFetchCall.add(callerPackage);\n }\n }\n\n // The compat half decides its own file-level helper family and drops\n // the callers whose call sites it cannot resolve.\n compat?.analyzeCalls(compatCallNodes);\n\n const helperPlanCache = new Map<string, PackageHelperPlan>();\n\n const getHelperPlan = (packageName: string): PackageHelperPlan => {\n let plan = helperPlanCache.get(packageName);\n\n if (plan === undefined) {\n plan = resolveHelperPlan(\n packageName,\n state.opts.importMode,\n state.opts.isServer,\n packagesWithDynamicCall.has(packageName),\n packagesWithFetchCall.has(packageName)\n );\n helperPlanCache.set(packageName, plan);\n }\n\n return plan;\n };\n\n // ── Step 4 — rewrite the imports.\n //\n // Moving a helper to a package's `/server` entry is the only edit\n // that changes the program body; the new declarations are recorded\n // here and applied with the dictionary imports in step 6, so no\n // stored node is invalidated mid-rewrite.\n const serverImportsByAnchor = new Map<\n BabelTypes.ImportDeclaration,\n BabelTypes.ImportDeclaration\n >();\n const emptiedImportNodes = new Set<BabelTypes.ImportDeclaration>();\n\n for (const importNode of compatImportNodes) {\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 so\n // call sites read unchanged.\n compat?.rewriteImportSpecifiers(importNode);\n }\n\n for (const importNode of nativeImportNodes) {\n // Per-import swap, mirrored across bundles — Solid hydration ids\n // rely on the SSR and client helpers consuming one resource slot\n // per call alike (see solid-intlayer/server).\n const helperPlan = getHelperPlan(importNode.source.value);\n const serverSource =\n helperPlan === 'ssrStatic'\n ? SSR_STATIC_IMPORT_SOURCE[importNode.source.value]\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 importNode.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = importedSpecifierName(t, spec);\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 serverImportsByAnchor.set(\n importNode,\n t.importDeclaration(\n serverSpecifiers,\n t.stringLiteral(serverSource)\n )\n );\n\n const serverSpecifierSet = new Set<BabelTypes.Node>(\n serverSpecifiers\n );\n importNode.specifiers = importNode.specifiers.filter(\n (spec) => !serverSpecifierSet.has(spec)\n );\n\n if (importNode.specifiers.length === 0) {\n emptiedImportNodes.add(importNode);\n }\n }\n }\n\n // ── Step 5 — rewrite the call sites.\n for (const callNode of compatCallNodes) {\n compat?.rewriteCall(callNode);\n }\n\n for (const callNode of nativeCallNodes) {\n const callee = callNode.callee as BabelTypes.Identifier;\n const originalImportedName = callerMap.get(callee.name)!;\n\n const key = readStaticString(t, callNode.arguments[0]);\n if (!key) continue;\n\n const callerPackage = callerPackageMap.get(callee.name);\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const isGetIntlayerAsync =\n originalImportedName === 'getIntlayerAsync';\n const dictionaryOverrideMode = 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 (isGetIntlayerAsync) {\n // Loading a single locale is the whole point of the async\n // getter, so it reads a per-locale loader whatever the file's\n // import mode is — the fetch loader when the dictionary is\n // remote, the dynamic one otherwise.\n perCallMode =\n dictionaryOverrideMode === 'fetch' ? 'fetch' : 'dynamic';\n } else 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 const ident = imports.identFor(key, perCallMode);\n\n if (perCallMode === 'static') {\n // Static helper (useDictionary / getDictionary): replace the key\n // argument with the imported dictionary object.\n callNode.arguments[0] = t.identifier(ident.name);\n } else {\n // Dynamic / fetch helper: first argument is the loader, the key\n // stays as the second one.\n callNode.arguments = [\n t.identifier(ident.name),\n ...callNode.arguments,\n ];\n }\n }\n\n // ── Step 6 — apply every body edit in one pass.\n const dictionaryImports = hasValidImport\n ? buildDictionaryImportDeclarations(t, state, imports)\n : [];\n\n const hasImportMoves =\n serverImportsByAnchor.size > 0 || emptiedImportNodes.size > 0;\n\n if (dictionaryImports.length === 0 && !hasImportMoves) return;\n\n const nextBody: BabelTypes.Statement[] = [];\n\n for (const statement of programBody) {\n if (\n t.isImportDeclaration(statement) &&\n emptiedImportNodes.has(statement)\n ) {\n // Every specifier moved to the /server entry; drop the husk.\n const serverImport = serverImportsByAnchor.get(statement);\n if (serverImport) nextBody.push(serverImport);\n continue;\n }\n\n nextBody.push(statement);\n\n if (t.isImportDeclaration(statement)) {\n const serverImport = serverImportsByAnchor.get(statement);\n if (serverImport) nextBody.push(serverImport);\n }\n }\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n let insertPos = 0;\n for (const statement of nextBody) {\n if (\n t.isExpressionStatement(statement) &&\n t.isStringLiteral(statement.expression) &&\n !statement.expression.value.startsWith('import') &&\n !statement.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n nextBody.splice(insertPos, 0, ...dictionaryImports);\n programPath.node.body = nextBody;\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 { PluginObject, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport type { CallerDescriptor } from '@intlayer/config/callers';\nimport { normalizePath } from '@intlayer/config/utils';\nimport {\n createCompatOptimizePass,\n type JsxSiteNode,\n} from './compat/optimizePass';\nimport {\n createDictionaryImportRegistry,\n type DictionaryImportRegistry,\n type ImportMode,\n} from './dictionaryImports';\nimport { getNormalizedFilesListSet } from './normalizedFilesList';\nimport { readStaticString } from './staticAstReaders';\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', 'getIntlayerAsync'] as const;\n\n/** Membership sets for the tables above — hit once per import and per call. */\nconst NATIVE_PACKAGE_SET: ReadonlySet<string> = new Set(PACKAGE_LIST);\nconst CALLER_NAME_SET: ReadonlySet<string> = new Set(CALLER_LIST);\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 DYNAMIC_PACKAGE_SET: ReadonlySet<string> = new Set(PACKAGE_LIST_DYNAMIC);\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n // `getIntlayerAsync` always reads a per-locale chunk, in every import mode,\n // so its helper is the same on both sides of the static/dynamic split.\n getIntlayerAsync: 'getDictionaryAsync',\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];\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\n/**\n * Per-file plugin state.\n *\n * Only the two flags that have to survive from `pre` / `Program.enter` into\n * `Program.exit` live here — the caller maps and the import registry are built\n * and consumed inside `exit`, so they stay local to it.\n */\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** Whether the current file *is* a generated dictionaries entry file. */\n _isDictEntry?: boolean;\n /** Whether the current file is covered by the `filesList` allowlist. */\n _isIncluded?: boolean;\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 isCallerName = (name: string): name is CallerName =>\n CALLER_NAME_SET.has(name);\n\nconst isDynamicPackage = (packageName: string): boolean =>\n DYNAMIC_PACKAGE_SET.has(packageName);\n\n/** The name an import specifier brings in, whether written as an identifier or a string. */\nconst importedSpecifierName = (\n babelTypes: typeof BabelTypes,\n specifier: BabelTypes.ImportSpecifier\n): string =>\n babelTypes.isIdentifier(specifier.imported)\n ? specifier.imported.name\n : specifier.imported.value;\n\nconst EMPTY_KEY_SET: ReadonlySet<string> = new Set<string>();\n\n/**\n * `nestingDictionaryKeys` as a set, cached by array reference: Babel reuses one\n * options object for the whole build, so the set is built once instead of once\n * per transformed file.\n */\nconst nestingKeysCache = new WeakMap<readonly string[], ReadonlySet<string>>();\n\nconst getNestingDictionaryKeySet = (\n nestingDictionaryKeys: readonly string[] | undefined\n): ReadonlySet<string> => {\n if (!nestingDictionaryKeys) return EMPTY_KEY_SET;\n\n let keySet = nestingKeysCache.get(nestingDictionaryKeys);\n\n if (!keySet) {\n keySet = new Set(nestingDictionaryKeys);\n nestingKeysCache.set(nestingDictionaryKeys, keySet);\n }\n\n return keySet;\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 * Builds the dictionary import declarations the rewrite accumulated for one\n * file — the compiled JSON (or its `nest()` companion) for static reads, and\n * the generated per-locale loader for dynamic and fetch ones.\n */\nconst buildDictionaryImportDeclarations = (\n babelTypes: typeof BabelTypes,\n state: State,\n imports: DictionaryImportRegistry\n): BabelTypes.ImportDeclaration[] => {\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n nestingDictionaryKeys,\n } = state.opts;\n const fromFile = state.file.opts.filename!;\n const nestingKeys = getNestingDictionaryKeySet(nestingDictionaryKeys);\n\n const importDeclarations: BabelTypes.ImportDeclaration[] = [];\n\n // Static JSON imports — `getIntlayer` always reads a JSON dictionary.\n for (const [key, ident] of imports.staticImports) {\n // A dictionary holding `nest()` references is imported through its\n // companion module, which re-exports it with the nest targets attached.\n const hasNestedDictionaries = nestingKeys.has(key);\n\n const specifier = computeImport(\n fromFile,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static',\n hasNestedDictionaries\n );\n\n const importDeclaration = babelTypes.importDeclaration(\n [babelTypes.importDefaultSpecifier(babelTypes.identifier(ident.name))],\n babelTypes.stringLiteral(specifier)\n );\n\n if (!hasNestedDictionaries) {\n importDeclaration.attributes = [\n babelTypes.importAttribute(\n babelTypes.identifier('type'),\n babelTypes.stringLiteral('json')\n ),\n ];\n }\n\n importDeclarations.push(importDeclaration);\n }\n\n // Per-locale loaders — `useIntlayer` under a dynamic or fetch helper.\n for (const [key, ident] of imports.dynamicImports) {\n const mode: ImportMode = ident.name.endsWith('_fetch')\n ? 'fetch'\n : 'dynamic';\n\n importDeclarations.push(\n babelTypes.importDeclaration(\n [babelTypes.importDefaultSpecifier(babelTypes.identifier(ident.name))],\n babelTypes.stringLiteral(\n computeImport(\n fromFile,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n mode\n )\n )\n )\n );\n }\n\n return importDeclarations;\n};\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()`, `getIntlayer()` and\n * `getIntlayerAsync()` from various Intlayer packages into optimized dictionary\n * access patterns, automatically importing the required dictionary files based\n * 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 / getIntlayerAsync\n * import { getIntlayer, getIntlayerAsync } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * const content = await getIntlayerAsync('app', locale);\n * ```\n *\n * `getIntlayerAsync` is the exception to the mode table below: it always\n * resolves to the per-locale loader (`getDictionaryAsync`), in every import\n * mode, since loading a single locale is what it exists for.\n *\n * **Output (any mode):**\n * ```ts\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { getDictionaryAsync as getIntlayerAsync } from 'intlayer';\n *\n * const content = await getIntlayerAsync(_dicHash_dyn, 'app', locale);\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._isIncluded = true;\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 // If this file *is* the dictionaries entry, short-circuit: export {}\n // Note: unmerged_dictionaries.mjs is used by the visual editor and CMS\n // and must not be replaced with an empty dictionary map.\n if (\n state.opts.replaceDictionaryEntry &&\n filename &&\n filename === dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n programPath.node.body = [\n t.exportDefaultDeclaration(t.objectExpression([])),\n t.exportNamedDeclaration(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier('getDictionaries'),\n t.arrowFunctionExpression([], t.objectExpression([]))\n ),\n ])\n ),\n ];\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 const imports = createDictionaryImportRegistry(t);\n\n // Compat adapters plug in here and nowhere else: with no descriptor\n // injected the pass is `null`, every `compat?.` below is a no-op and\n // the native rewrite runs exactly as if the adapters did not exist.\n const compat = createCompatOptimizePass(\n t,\n state.opts.compatCallers ?? [],\n imports,\n {\n importMode: state.opts.importMode,\n dictionaryModeMap: state.opts.dictionaryModeMap,\n }\n );\n\n // ── Step 1 — imports.\n //\n // An import declaration is only ever a direct child of Program, so\n // the body is scanned instead of walking the whole AST, and the\n // result is complete before any call site is inspected (a file may\n // import below the calls it governs).\n const programBody = programPath.node.body;\n const nativeImportNodes: BabelTypes.ImportDeclaration[] = [];\n const compatImportNodes: BabelTypes.ImportDeclaration[] = [];\n /** Local alias → the native caller it was imported as. */\n const callerMap = new Map<string, CallerName>();\n /** Local alias → the intlayer package it was imported from. */\n const callerPackageMap = new Map<string, string>();\n /** Whether the file imported any native or compat caller at all. */\n let hasValidImport = false;\n\n for (const statement of programBody) {\n if (!t.isImportDeclaration(statement)) continue;\n\n const src = statement.source.value;\n const isNativePackage = NATIVE_PACKAGE_SET.has(src);\n const isCompatPackage = compat?.ownsImportSource(src) ?? false;\n\n if (!isNativePackage && !isCompatPackage) continue;\n\n hasValidImport = true;\n if (isNativePackage) nativeImportNodes.push(statement);\n if (isCompatPackage) compatImportNodes.push(statement);\n\n for (const spec of statement.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = importedSpecifierName(t, spec);\n\n if (isNativePackage && isCallerName(importedName)) {\n callerMap.set(spec.local.name, importedName);\n callerPackageMap.set(spec.local.name, src);\n }\n\n if (isCompatPackage) {\n compat?.noteImport(src, importedName, spec.local.name);\n }\n }\n }\n\n // ── Step 2 — the file's only AST walk, collecting the call sites\n // that either half of the rewrite can act on. Everything after\n // this point works on the collected arrays.\n const nativeCallNodes: BabelTypes.CallExpression[] = [];\n const compatCallNodes: BabelTypes.CallExpression[] = [];\n /**\n * Compat JSX elements bound by their id attribute (`<Trans id>`),\n * as source JSX or as the `jsx(Trans, …)` call the framework plugin\n * already compiled them into.\n */\n const compatJsxNodes: JsxSiteNode[] = [];\n\n // A root-scope compat caller (`useLingui()`) names its dictionaries\n // through the message ids used elsewhere in the file, so those\n // id-carrying sites are handed to the compat pass from the same walk.\n const collectMessageIds = compat?.needsMessageIdSites() ?? false;\n\n if (callerMap.size > 0 || compat?.hasCallers()) {\n programPath.traverse({\n CallExpression(path) {\n if (collectMessageIds) compat?.collectMessageIdSite(path.node);\n if (compat?.ownsJsxSite(path.node)) {\n compatJsxNodes.push(path.node);\n }\n\n const callee = path.node.callee;\n if (!t.isIdentifier(callee)) return;\n\n if (callerMap.has(callee.name)) {\n nativeCallNodes.push(path.node);\n } else if (compat?.ownsLocalName(callee.name)) {\n compatCallNodes.push(path.node);\n\n // `const { i18n, _, t } = useLingui()` — the destructured\n // names are how bare `t('…')` sites are told apart from\n // unrelated helpers of the same name.\n const declarator = path.parent;\n if (\n t.isVariableDeclarator(declarator) &&\n t.isObjectPattern(declarator.id)\n ) {\n compat.noteDestructuredResult(\n callee.name,\n declarator.id.properties.flatMap((property) =>\n t.isObjectProperty(property) &&\n t.isIdentifier(property.value)\n ? [property.value.name]\n : []\n )\n );\n }\n }\n },\n ...(collectMessageIds\n ? {\n TaggedTemplateExpression(path) {\n compat?.collectMessageIdSite(path.node);\n },\n }\n : {}),\n ...(compat\n ? {\n JSXOpeningElement(path) {\n if (collectMessageIds) {\n compat.collectMessageIdSite(path.node);\n }\n if (compat.ownsJsxSite(path.node)) {\n compatJsxNodes.push(path.node);\n }\n },\n }\n : {}),\n });\n }\n\n // ── Step 3 — analysis.\n //\n // A per-dictionary override reached from this file can promote a\n // whole package import to a dynamic loader, so the helper family is\n // decided per package before anything is rewritten.\n const packagesWithDynamicCall = new Set<string>();\n const packagesWithFetchCall = new Set<string>();\n\n for (const callNode of nativeCallNodes) {\n const callee = callNode.callee as BabelTypes.Identifier;\n if (callerMap.get(callee.name) !== 'useIntlayer') continue;\n\n const callerPackage = callerPackageMap.get(callee.name);\n if (!callerPackage) continue;\n\n const key = readStaticString(t, callNode.arguments[0]);\n if (!key) continue;\n\n const overrideMode = state.opts.dictionaryModeMap?.[key];\n\n if (overrideMode === 'dynamic') {\n packagesWithDynamicCall.add(callerPackage);\n } else if (overrideMode === 'fetch') {\n packagesWithFetchCall.add(callerPackage);\n }\n }\n\n // The compat half decides its own file-level helper family and drops\n // the callers whose call sites it cannot resolve.\n compat?.analyzeCalls(\n compatCallNodes,\n compatJsxNodes,\n (localName) =>\n programPath.scope.getBinding(localName)?.referencePaths.length ??\n 0\n );\n\n const helperPlanCache = new Map<string, PackageHelperPlan>();\n\n const getHelperPlan = (packageName: string): PackageHelperPlan => {\n let plan = helperPlanCache.get(packageName);\n\n if (plan === undefined) {\n plan = resolveHelperPlan(\n packageName,\n state.opts.importMode,\n state.opts.isServer,\n packagesWithDynamicCall.has(packageName),\n packagesWithFetchCall.has(packageName)\n );\n helperPlanCache.set(packageName, plan);\n }\n\n return plan;\n };\n\n // ── Step 4 — rewrite the imports.\n //\n // Moving a helper to a package's `/server` entry is the only edit\n // that changes the program body; the new declarations are recorded\n // here and applied with the dictionary imports in step 6, so no\n // stored node is invalidated mid-rewrite.\n const serverImportsByAnchor = new Map<\n BabelTypes.ImportDeclaration,\n BabelTypes.ImportDeclaration\n >();\n const emptiedImportNodes = new Set<BabelTypes.ImportDeclaration>();\n\n for (const importNode of compatImportNodes) {\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 so\n // call sites read unchanged.\n compat?.rewriteImportSpecifiers(importNode);\n }\n\n for (const importNode of nativeImportNodes) {\n // Per-import swap, mirrored across bundles — Solid hydration ids\n // rely on the SSR and client helpers consuming one resource slot\n // per call alike (see solid-intlayer/server).\n const helperPlan = getHelperPlan(importNode.source.value);\n const serverSource =\n helperPlan === 'ssrStatic'\n ? SSR_STATIC_IMPORT_SOURCE[importNode.source.value]\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 importNode.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = importedSpecifierName(t, spec);\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 serverImportsByAnchor.set(\n importNode,\n t.importDeclaration(\n serverSpecifiers,\n t.stringLiteral(serverSource)\n )\n );\n\n const serverSpecifierSet = new Set<BabelTypes.Node>(\n serverSpecifiers\n );\n importNode.specifiers = importNode.specifiers.filter(\n (spec) => !serverSpecifierSet.has(spec)\n );\n\n if (importNode.specifiers.length === 0) {\n emptiedImportNodes.add(importNode);\n }\n }\n }\n\n // ── Step 5 — rewrite the call sites and bound JSX elements.\n for (const callNode of compatCallNodes) {\n compat?.rewriteCall(callNode);\n }\n\n for (const jsxNode of compatJsxNodes) {\n compat?.rewriteJsxSite(jsxNode);\n }\n\n for (const callNode of nativeCallNodes) {\n const callee = callNode.callee as BabelTypes.Identifier;\n const originalImportedName = callerMap.get(callee.name)!;\n\n const key = readStaticString(t, callNode.arguments[0]);\n if (!key) continue;\n\n const callerPackage = callerPackageMap.get(callee.name);\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const isGetIntlayerAsync =\n originalImportedName === 'getIntlayerAsync';\n const dictionaryOverrideMode = 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 (isGetIntlayerAsync) {\n // Loading a single locale is the whole point of the async\n // getter, so it reads a per-locale loader whatever the file's\n // import mode is — the fetch loader when the dictionary is\n // remote, the dynamic one otherwise.\n perCallMode =\n dictionaryOverrideMode === 'fetch' ? 'fetch' : 'dynamic';\n } else 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 const ident = imports.identFor(key, perCallMode);\n\n if (perCallMode === 'static') {\n // Static helper (useDictionary / getDictionary): replace the key\n // argument with the imported dictionary object.\n callNode.arguments[0] = t.identifier(ident.name);\n } else {\n // Dynamic / fetch helper: first argument is the loader, the key\n // stays as the second one.\n callNode.arguments = [\n t.identifier(ident.name),\n ...callNode.arguments,\n ];\n }\n }\n\n // ── Step 6 — apply every body edit in one pass.\n const dictionaryImports = hasValidImport\n ? buildDictionaryImportDeclarations(t, state, imports)\n : [];\n\n const hasImportMoves =\n serverImportsByAnchor.size > 0 || emptiedImportNodes.size > 0;\n\n if (dictionaryImports.length === 0 && !hasImportMoves) return;\n\n const nextBody: BabelTypes.Statement[] = [];\n\n for (const statement of programBody) {\n if (\n t.isImportDeclaration(statement) &&\n emptiedImportNodes.has(statement)\n ) {\n // Every specifier moved to the /server entry; drop the husk.\n const serverImport = serverImportsByAnchor.get(statement);\n if (serverImport) nextBody.push(serverImport);\n continue;\n }\n\n nextBody.push(statement);\n\n if (t.isImportDeclaration(statement)) {\n const serverImport = serverImportsByAnchor.get(statement);\n if (serverImport) nextBody.push(serverImport);\n }\n }\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n let insertPos = 0;\n for (const statement of nextBody) {\n if (\n t.isExpressionStatement(statement) &&\n t.isStringLiteral(statement.expression) &&\n !statement.expression.value.startsWith('import') &&\n !statement.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n nextBody.splice(insertPos, 0, ...dictionaryImports);\n programPath.node.body = nextBody;\n },\n },\n },\n };\n};\n"],"mappings":"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"}
|