@intlayer/babel 9.4.3 → 9.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +0 -2
  2. package/dist/cjs/analyzeContentUsage.cjs +301 -0
  3. package/dist/cjs/analyzeContentUsage.cjs.map +1 -0
  4. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +5 -4
  5. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
  6. package/dist/cjs/babel-plugin-intlayer-optimize.cjs +173 -282
  7. package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
  8. package/dist/cjs/babel-plugin-intlayer-purge.cjs +4 -3
  9. package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -1
  10. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs +49 -699
  11. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
  12. package/dist/cjs/compat/namespaceResolution.cjs +124 -0
  13. package/dist/cjs/compat/namespaceResolution.cjs.map +1 -0
  14. package/dist/cjs/compat/optimizePass.cjs +144 -0
  15. package/dist/cjs/compat/optimizePass.cjs.map +1 -0
  16. package/dist/cjs/compat/usageAnalysis.cjs +195 -0
  17. package/dist/cjs/compat/usageAnalysis.cjs.map +1 -0
  18. package/dist/cjs/dictionaryImports.cjs +40 -0
  19. package/dist/cjs/dictionaryImports.cjs.map +1 -0
  20. package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs +1 -1
  21. package/dist/cjs/getExtractPluginOptions.cjs +1 -1
  22. package/dist/cjs/getOptimizePluginOptions.cjs +1 -1
  23. package/dist/cjs/getPurgePluginOptions.cjs +1 -1
  24. package/dist/cjs/index.cjs +9 -5
  25. package/dist/cjs/nativeCallers.cjs +41 -0
  26. package/dist/cjs/nativeCallers.cjs.map +1 -0
  27. package/dist/cjs/pruneContext.cjs +79 -0
  28. package/dist/cjs/pruneContext.cjs.map +1 -0
  29. package/dist/cjs/staticAstReaders.cjs +140 -0
  30. package/dist/cjs/staticAstReaders.cjs.map +1 -0
  31. package/dist/cjs/transformers.cjs +2 -1
  32. package/dist/cjs/transformers.cjs.map +1 -1
  33. package/dist/esm/analyzeContentUsage.mjs +300 -0
  34. package/dist/esm/analyzeContentUsage.mjs.map +1 -0
  35. package/dist/esm/babel-plugin-intlayer-field-rename.mjs +3 -2
  36. package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
  37. package/dist/esm/babel-plugin-intlayer-optimize.mjs +173 -282
  38. package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
  39. package/dist/esm/babel-plugin-intlayer-purge.mjs +3 -2
  40. package/dist/esm/babel-plugin-intlayer-purge.mjs.map +1 -1
  41. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs +43 -694
  42. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
  43. package/dist/esm/compat/namespaceResolution.mjs +120 -0
  44. package/dist/esm/compat/namespaceResolution.mjs.map +1 -0
  45. package/dist/esm/compat/optimizePass.mjs +143 -0
  46. package/dist/esm/compat/optimizePass.mjs.map +1 -0
  47. package/dist/esm/compat/usageAnalysis.mjs +193 -0
  48. package/dist/esm/compat/usageAnalysis.mjs.map +1 -0
  49. package/dist/esm/dictionaryImports.mjs +38 -0
  50. package/dist/esm/dictionaryImports.mjs.map +1 -0
  51. package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs +1 -1
  52. package/dist/esm/getExtractPluginOptions.mjs +1 -1
  53. package/dist/esm/getOptimizePluginOptions.mjs +1 -1
  54. package/dist/esm/getPurgePluginOptions.mjs +1 -1
  55. package/dist/esm/index.mjs +5 -2
  56. package/dist/esm/nativeCallers.mjs +38 -0
  57. package/dist/esm/nativeCallers.mjs.map +1 -0
  58. package/dist/esm/pruneContext.mjs +76 -0
  59. package/dist/esm/pruneContext.mjs.map +1 -0
  60. package/dist/esm/staticAstReaders.mjs +129 -0
  61. package/dist/esm/staticAstReaders.mjs.map +1 -0
  62. package/dist/esm/transformers.mjs +2 -1
  63. package/dist/esm/transformers.mjs.map +1 -1
  64. package/dist/types/analyzeContentUsage.d.ts +18 -0
  65. package/dist/types/analyzeContentUsage.d.ts.map +1 -0
  66. package/dist/types/babel-plugin-intlayer-extract.d.ts +3 -4
  67. package/dist/types/babel-plugin-intlayer-extract.d.ts.map +1 -1
  68. package/dist/types/babel-plugin-intlayer-field-rename.d.ts +10 -10
  69. package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
  70. package/dist/types/babel-plugin-intlayer-minify.d.ts +2 -3
  71. package/dist/types/babel-plugin-intlayer-minify.d.ts.map +1 -1
  72. package/dist/types/babel-plugin-intlayer-optimize.d.ts +11 -18
  73. package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
  74. package/dist/types/babel-plugin-intlayer-purge.d.ts +7 -7
  75. package/dist/types/babel-plugin-intlayer-purge.d.ts.map +1 -1
  76. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts +22 -189
  77. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
  78. package/dist/types/babelParser.d.ts +3 -4
  79. package/dist/types/babelParser.d.ts.map +1 -1
  80. package/dist/types/compat/namespaceResolution.d.ts +66 -0
  81. package/dist/types/compat/namespaceResolution.d.ts.map +1 -0
  82. package/dist/types/compat/optimizePass.d.ts +58 -0
  83. package/dist/types/compat/optimizePass.d.ts.map +1 -0
  84. package/dist/types/compat/usageAnalysis.d.ts +75 -0
  85. package/dist/types/compat/usageAnalysis.d.ts.map +1 -0
  86. package/dist/types/dictionaryImports.d.ts +46 -0
  87. package/dist/types/dictionaryImports.d.ts.map +1 -0
  88. package/dist/types/extractContent/babelProcessor.d.ts +4 -5
  89. package/dist/types/extractContent/babelProcessor.d.ts.map +1 -1
  90. package/dist/types/extractContent/contentWriter.d.ts +3 -4
  91. package/dist/types/extractContent/contentWriter.d.ts.map +1 -1
  92. package/dist/types/extractContent/extractContent.d.ts +3 -4
  93. package/dist/types/extractContent/extractContent.d.ts.map +1 -1
  94. package/dist/types/extractContent/processTsxFile.d.ts +2 -3
  95. package/dist/types/extractContent/processTsxFile.d.ts.map +1 -1
  96. package/dist/types/extractContent/utils/constants.d.ts +3 -4
  97. package/dist/types/extractContent/utils/constants.d.ts.map +1 -1
  98. package/dist/types/extractContent/utils/detectPackageName.d.ts +1 -2
  99. package/dist/types/extractContent/utils/detectPackageName.d.ts.map +1 -1
  100. package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts +5 -6
  101. package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts.map +1 -1
  102. package/dist/types/extractContent/utils/extractDictionaryKey.d.ts +2 -3
  103. package/dist/types/extractContent/utils/extractDictionaryKey.d.ts.map +1 -1
  104. package/dist/types/extractContent/utils/generateKey.d.ts +1 -2
  105. package/dist/types/extractContent/utils/generateKey.d.ts.map +1 -1
  106. package/dist/types/extractContent/utils/getComponentName.d.ts +1 -2
  107. package/dist/types/extractContent/utils/getComponentName.d.ts.map +1 -1
  108. package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts +2 -3
  109. package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts.map +1 -1
  110. package/dist/types/extractContent/utils/getOrGenerateKey.d.ts +1 -2
  111. package/dist/types/extractContent/utils/getOrGenerateKey.d.ts.map +1 -1
  112. package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts +1 -2
  113. package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts.map +1 -1
  114. package/dist/types/extractScriptBlocks.d.ts +3 -4
  115. package/dist/types/extractScriptBlocks.d.ts.map +1 -1
  116. package/dist/types/getExtractPluginOptions.d.ts +2 -3
  117. package/dist/types/getExtractPluginOptions.d.ts.map +1 -1
  118. package/dist/types/getOptimizePluginOptions.d.ts +1 -2
  119. package/dist/types/getOptimizePluginOptions.d.ts.map +1 -1
  120. package/dist/types/getPurgePluginOptions.d.ts +2 -3
  121. package/dist/types/getPurgePluginOptions.d.ts.map +1 -1
  122. package/dist/types/index.d.ts +5 -2
  123. package/dist/types/nativeCallers.d.ts +33 -0
  124. package/dist/types/nativeCallers.d.ts.map +1 -0
  125. package/dist/types/normalizedFilesList.d.ts +1 -2
  126. package/dist/types/normalizedFilesList.d.ts.map +1 -1
  127. package/dist/types/pruneContext.d.ts +152 -0
  128. package/dist/types/pruneContext.d.ts.map +1 -0
  129. package/dist/types/staticAstReaders.d.ts +84 -0
  130. package/dist/types/staticAstReaders.d.ts.map +1 -0
  131. package/dist/types/transformers.d.ts +11 -11
  132. package/dist/types/transformers.d.ts.map +1 -1
  133. package/package.json +12 -12
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staticAstReaders.mjs","names":[],"sources":["../../src/staticAstReaders.ts"],"sourcesContent":["import type { NodePath } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\n\n/**\n * Static-value readers shared by every pass that has to decide, at build time,\n * which dictionary a call site reads.\n *\n * They were previously duplicated — with small behavioural drifts — between\n * `babel-plugin-intlayer-optimize` and `babel-plugin-intlayer-usage-analyzer`.\n * Both now read through this module so a call site the analyser can attribute\n * is exactly the one the optimizer can rewrite.\n */\n\n/**\n * Reads a fully-static string from an AST node. Returns `undefined` for\n * dynamic values (identifiers, expressions, template literals with\n * interpolations, …).\n */\nexport const readStaticString = (\n babelTypes: typeof BabelTypes,\n node: BabelTypes.Node | null | undefined\n): string | undefined => {\n if (!node) return undefined;\n if (babelTypes.isStringLiteral(node)) return node.value;\n if (\n babelTypes.isTemplateLiteral(node) &&\n node.expressions.length === 0 &&\n node.quasis.length === 1\n ) {\n return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw;\n }\n return undefined;\n};\n\n/** Returns the first dot-path segment of a key, e.g. `'a.b.c'` → `'a'`. */\nexport const firstPathSegment = (path: string): string =>\n path.split('.')[0] ?? path;\n\n/**\n * Reads the static first dot-path segment from a message-id node.\n *\n * t('counter.label') → 'counter'\n * t(`counter.${x}`) → 'counter' (static prefix before the first dot)\n * t(`${x}.label`) → undefined (dynamic first segment)\n * t(someVariable) → undefined\n */\nexport const readStaticFirstSegment = (\n babelTypes: typeof BabelTypes,\n node: BabelTypes.Node | null | undefined\n): string | undefined => {\n const staticString = readStaticString(babelTypes, node);\n if (staticString !== undefined) return firstPathSegment(staticString);\n\n // Template literal whose first quasi already contains the dot delimiter, e.g.\n // `counter.${index}` → the leading `counter` segment is statically known.\n if (babelTypes.isTemplateLiteral(node) && node.quasis.length > 0) {\n const firstQuasi =\n node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw;\n if (firstQuasi?.includes('.')) {\n return firstPathSegment(firstQuasi);\n }\n }\n return undefined;\n};\n\n/** Whether an object-property key (identifier or string literal) reads as `name`. */\nexport const propertyKeyMatches = (\n babelTypes: typeof BabelTypes,\n property: BabelTypes.ObjectProperty,\n name: string\n): boolean =>\n (babelTypes.isIdentifier(property.key) && property.key.name === name) ||\n (babelTypes.isStringLiteral(property.key) && property.key.value === name);\n\n/**\n * Returns the `ObjectProperty` named `propertyName`, or `undefined` when the\n * object has no such property. Callers that need to mutate the property in\n * place (rewriting or deleting it) use this rather than a value reader.\n */\nexport const findObjectProperty = (\n babelTypes: typeof BabelTypes,\n objectExpression: BabelTypes.ObjectExpression,\n propertyName: string\n): BabelTypes.ObjectProperty | undefined => {\n for (const property of objectExpression.properties) {\n if (!babelTypes.isObjectProperty(property)) continue;\n if (propertyKeyMatches(babelTypes, property, propertyName)) return property;\n }\n return undefined;\n};\n\n/**\n * Marker returned by the reader helpers when the requested property or\n * argument is simply absent — distinct from present-but-dynamic, which the\n * callers must treat conservatively.\n */\nexport const ABSENT_VALUE = '__default__' as const;\n\n/** Either a statically-known value, {@link ABSENT_VALUE}, or `undefined` (dynamic). */\nexport type StaticOrAbsent<T> = T | typeof ABSENT_VALUE | undefined;\n\n/**\n * Reads a static string property from an object expression. Returns\n * {@link ABSENT_VALUE} when the property is absent and `undefined` when\n * present but dynamic.\n */\nexport const readObjectProperty = (\n babelTypes: typeof BabelTypes,\n objectExpression: BabelTypes.ObjectExpression,\n propertyName: string\n): StaticOrAbsent<string> => {\n const property = findObjectProperty(\n babelTypes,\n objectExpression,\n propertyName\n );\n if (!property) return ABSENT_VALUE;\n return readStaticString(babelTypes, property.value); // present but dynamic → undefined\n};\n\n/**\n * Returns the value *node* of a named property, so callers can apply their own\n * reader to it (a full static string, or just its leading path segment).\n * Returns {@link ABSENT_VALUE} when the property is absent.\n */\nexport const readObjectPropertyNode = (\n babelTypes: typeof BabelTypes,\n objectExpression: BabelTypes.ObjectExpression,\n propertyName: string\n): StaticOrAbsent<BabelTypes.Node> => {\n const property = findObjectProperty(\n babelTypes,\n objectExpression,\n propertyName\n );\n if (!property) return ABSENT_VALUE;\n return property.value;\n};\n\n/**\n * Reads a named JSX attribute as a static string and returns it wrapped in a\n * `StringLiteral` node so the result can be fed to the same namespace resolver\n * as a call argument. Handles both `id=\"home.title\"` and `id={'home.title'}`.\n * Returns `undefined` when the attribute is absent or dynamic (`id={expr}`).\n */\nexport const readJsxAttributeString = (\n babelTypes: typeof BabelTypes,\n openingElement: BabelTypes.JSXOpeningElement,\n attributeName: string\n): BabelTypes.StringLiteral | undefined => {\n for (const attribute of openingElement.attributes) {\n if (!babelTypes.isJSXAttribute(attribute)) continue;\n if (\n !babelTypes.isJSXIdentifier(attribute.name) ||\n attribute.name.name !== attributeName\n ) {\n continue;\n }\n\n const value = attribute.value;\n // id=\"home.title\"\n if (babelTypes.isStringLiteral(value)) return value;\n // id={'home.title'} / id={`home.title`}\n if (babelTypes.isJSXExpressionContainer(value)) {\n const staticString = readStaticString(babelTypes, value.expression);\n if (staticString !== undefined) {\n return babelTypes.stringLiteral(staticString);\n }\n }\n return undefined; // attribute present but dynamic\n }\n return undefined; // attribute absent\n};\n\n/**\n * Splits a compat namespace at the first `.` to separate the dictionary key\n * from an optional key prefix, mirroring the SWC plugin's `split_namespace`.\n *\n * `'about'` → `{ dictionaryKey: 'about', keyPrefix: '' }`\n * `'about.counter'` → `{ dictionaryKey: 'about', keyPrefix: 'counter' }`\n */\nexport const splitNamespace = (\n namespace: string\n): { dictionaryKey: string; keyPrefix: string } => {\n const dotPosition = namespace.indexOf('.');\n if (dotPosition === -1) return { dictionaryKey: namespace, keyPrefix: '' };\n return {\n dictionaryKey: namespace.slice(0, dotPosition),\n keyPrefix: namespace.slice(dotPosition + 1),\n };\n};\n\n/**\n * Climbs past an enclosing `await` expression so that\n * `const t = await getTranslations('ns')` — or `await getIntlayerAsync('key')`\n * — is resolved to its variable declarator the same way the synchronous form\n * is.\n */\nexport const unwrapAwait = (\n babelTypes: typeof BabelTypes,\n path: NodePath<BabelTypes.Node>\n): NodePath<BabelTypes.Node> => {\n const parentPath = path.parentPath;\n if (parentPath && babelTypes.isAwaitExpression(parentPath.node)) {\n return parentPath;\n }\n return path;\n};\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAa,oBACX,YACA,SACuB;CACvB,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,WAAW,gBAAgB,IAAI,GAAG,OAAO,KAAK;CAClD,IACE,WAAW,kBAAkB,IAAI,KACjC,KAAK,YAAY,WAAW,KAC5B,KAAK,OAAO,WAAW,GAEvB,OAAO,KAAK,OAAO,EAAE,EAAE,MAAM,UAAU,KAAK,OAAO,EAAE,EAAE,MAAM;AAGjE;;AAGA,MAAa,oBAAoB,SAC/B,KAAK,MAAM,GAAG,CAAC,CAAC,MAAM;;;;;;;;;AAUxB,MAAa,0BACX,YACA,SACuB;CACvB,MAAM,eAAe,iBAAiB,YAAY,IAAI;CACtD,IAAI,iBAAiB,QAAW,OAAO,iBAAiB,YAAY;CAIpE,IAAI,WAAW,kBAAkB,IAAI,KAAK,KAAK,OAAO,SAAS,GAAG;EAChE,MAAM,aACJ,KAAK,OAAO,EAAE,EAAE,MAAM,UAAU,KAAK,OAAO,EAAE,EAAE,MAAM;EACxD,IAAI,YAAY,SAAS,GAAG,GAC1B,OAAO,iBAAiB,UAAU;CAEtC;AAEF;;AAGA,MAAa,sBACX,YACA,UACA,SAEC,WAAW,aAAa,SAAS,GAAG,KAAK,SAAS,IAAI,SAAS,QAC/D,WAAW,gBAAgB,SAAS,GAAG,KAAK,SAAS,IAAI,UAAU;;;;;;AAOtE,MAAa,sBACX,YACA,kBACA,iBAC0C;CAC1C,KAAK,MAAM,YAAY,iBAAiB,YAAY;EAClD,IAAI,CAAC,WAAW,iBAAiB,QAAQ,GAAG;EAC5C,IAAI,mBAAmB,YAAY,UAAU,YAAY,GAAG,OAAO;CACrE;AAEF;;;;;;AAOA,MAAa,eAAe;;;;;;AAU5B,MAAa,sBACX,YACA,kBACA,iBAC2B;CAC3B,MAAM,WAAW,mBACf,YACA,kBACA,YACF;CACA,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,iBAAiB,YAAY,SAAS,KAAK;AACpD;;;;;;AAOA,MAAa,0BACX,YACA,kBACA,iBACoC;CACpC,MAAM,WAAW,mBACf,YACA,kBACA,YACF;CACA,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,SAAS;AAClB;;;;;;;AAQA,MAAa,0BACX,YACA,gBACA,kBACyC;CACzC,KAAK,MAAM,aAAa,eAAe,YAAY;EACjD,IAAI,CAAC,WAAW,eAAe,SAAS,GAAG;EAC3C,IACE,CAAC,WAAW,gBAAgB,UAAU,IAAI,KAC1C,UAAU,KAAK,SAAS,eAExB;EAGF,MAAM,QAAQ,UAAU;EAExB,IAAI,WAAW,gBAAgB,KAAK,GAAG,OAAO;EAE9C,IAAI,WAAW,yBAAyB,KAAK,GAAG;GAC9C,MAAM,eAAe,iBAAiB,YAAY,MAAM,UAAU;GAClE,IAAI,iBAAiB,QACnB,OAAO,WAAW,cAAc,YAAY;EAEhD;EACA;CACF;AAEF;;;;;;;;AASA,MAAa,kBACX,cACiD;CACjD,MAAM,cAAc,UAAU,QAAQ,GAAG;CACzC,IAAI,gBAAgB,IAAI,OAAO;EAAE,eAAe;EAAW,WAAW;CAAG;CACzE,OAAO;EACL,eAAe,UAAU,MAAM,GAAG,WAAW;EAC7C,WAAW,UAAU,MAAM,cAAc,CAAC;CAC5C;AACF;;;;;;;AAQA,MAAa,eACX,YACA,SAC8B;CAC9B,MAAM,aAAa,KAAK;CACxB,IAAI,cAAc,WAAW,kBAAkB,WAAW,IAAI,GAC5D,OAAO;CAET,OAAO;AACT"}
@@ -1,4 +1,5 @@
1
- import { INTLAYER_CALLER_NAMES, makeUsageAnalyzerBabelPlugin } from "./babel-plugin-intlayer-usage-analyzer.mjs";
1
+ import { INTLAYER_CALLER_NAMES } from "./nativeCallers.mjs";
2
+ import { makeUsageAnalyzerBabelPlugin } from "./babel-plugin-intlayer-usage-analyzer.mjs";
2
3
  import { extractScriptBlocks, injectScriptBlocks } from "./extractScriptBlocks.mjs";
3
4
  import { makeFieldRenameBabelPlugin } from "./babel-plugin-intlayer-field-rename.mjs";
4
5
  import { intlayerOptimizeBabelPlugin } from "./babel-plugin-intlayer-optimize.mjs";
@@ -1 +1 @@
1
- {"version":3,"file":"transformers.mjs","names":[],"sources":["../../src/transformers.ts"],"sourcesContent":["import { transformAsync } from '@babel/core';\n// Typed from `@babel/parser` rather than `@babel/core`'s\n// `InputOptions['parserOpts']` (Babel 8's rename of `TransformOptions`): the\n// two describe the same shape, but naming `@babel/core` in an exported type\n// pulls its declaration file into every consumer's type-check, and that file\n// needs `@types/convert-source-map` to resolve.\nimport type { ParserOptions } from '@babel/parser';\nimport { makeFieldRenameBabelPlugin } from './babel-plugin-intlayer-field-rename';\nimport {\n intlayerOptimizeBabelPlugin,\n type OptimizePluginOptions,\n} from './babel-plugin-intlayer-optimize';\nimport {\n type CompatCallerConfig,\n INTLAYER_CALLER_NAMES,\n makeUsageAnalyzerBabelPlugin,\n type PruneContext,\n} from './babel-plugin-intlayer-usage-analyzer';\nimport { extractScriptBlocks, injectScriptBlocks } from './extractScriptBlocks';\n\n// ── Shared Babel parser configuration ─────────────────────────────────────────\n\n/**\n * Babel parser options covering the superset of syntaxes used across all\n * supported frameworks (React / Vue / Svelte / Angular / …).\n */\nexport const BABEL_PARSER_OPTIONS: ParserOptions = {\n sourceType: 'module',\n allowImportExportEverywhere: true,\n plugins: [\n 'typescript',\n 'jsx',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'asyncGenerators',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n};\n\n/**\n * Builds a fast pre-check regex that matches files potentially containing\n * native intlayer calls and/or the given compat namespace caller names.\n *\n * The result is used to skip files that definitely contain none of the\n * relevant function names, avoiding unnecessary Babel parsing.\n *\n * The native names come from {@link INTLAYER_CALLER_NAMES} rather than being\n * spelled out here: a name missing from this regex silently opts every file\n * using it out of the optimize, purge and minify passes, leaving its calls to\n * resolve through the dictionary registry — empty in browser bundles.\n *\n * Compat caller names are NOT hardcoded here — they are provided at runtime by\n * the compat adapter packages that configure the usage-analysis pipeline.\n *\n * @param extraCallerNames - Additional caller function names to match\n * (e.g. `['useTranslation', 'getFixedT']` from `@intlayer/react-i18next`).\n * @returns A `RegExp` matching any of the native or provided caller names.\n */\nexport const buildUsageCheckRegex = (extraCallerNames?: string[]): RegExp => {\n const callerNames = [...INTLAYER_CALLER_NAMES, ...(extraCallerNames ?? [])];\n const uniqueNames = [...new Set(callerNames)];\n return new RegExp(`\\\\b(${uniqueNames.join('|')})\\\\b`);\n};\n\n/**\n * Fast pre-check: matches files that could contain native intlayer calls\n * (`useIntlayer` / `getIntlayer` / `getIntlayerAsync`). Used by the\n * optimize/transform pass, which only rewrites native calls.\n */\nexport const INTLAYER_USAGE_REGEX = buildUsageCheckRegex();\n\n/** Usage-check regex covering only the native callers (no compat callers). */\nconst NATIVE_USAGE_CHECK_REGEX = INTLAYER_USAGE_REGEX;\n\n/** Cache of usage-check regexes, keyed by the compat-caller array reference. */\nconst usageCheckRegexCache = new WeakMap<\n readonly CompatCallerConfig[],\n RegExp\n>();\n\n/**\n * Returns the usage-check regex for the given compat callers, memoised by the\n * array reference. Plugins pass the same options array for every analysed\n * file, so the regex is built once per build instead of once per file.\n */\nexport const getUsageCheckRegex = (\n compatCallers?: readonly CompatCallerConfig[]\n): RegExp => {\n if (!compatCallers || compatCallers.length === 0) {\n return NATIVE_USAGE_CHECK_REGEX;\n }\n\n let usageCheckRegex = usageCheckRegexCache.get(compatCallers);\n if (!usageCheckRegex) {\n usageCheckRegex = buildUsageCheckRegex(\n compatCallers.map((caller) => caller.callerName)\n );\n usageCheckRegexCache.set(compatCallers, usageCheckRegex);\n }\n return usageCheckRegex;\n};\n\n/**\n * Matches source files that are valid targets for usage analysis and Babel\n * transformation. Excludes sourcemap files, declaration files, and other\n * non-source extensions.\n */\nexport const SOURCE_FILE_REGEX = /\\.(tsx?|[mc]?jsx?|vue|svelte|astro)$/;\n\n// ── High-level transformer functions ──────────────────────────────────────────\n\n/**\n * Runs the usage-analysis Babel plugin on a single JS/TS code string.\n *\n * This is analysis-only: the transformed code output is discarded.\n * Throws if Babel cannot parse the content.\n */\nconst analyzeScriptContent = async (\n scriptContent: string,\n sourceFilePath: string,\n pruneContext: PruneContext,\n compatCallers?: CompatCallerConfig[]\n): Promise<void> => {\n await transformAsync(scriptContent, {\n filename: sourceFilePath,\n plugins: [makeUsageAnalyzerBabelPlugin(pruneContext, { compatCallers })],\n parserOpts: BABEL_PARSER_OPTIONS,\n ast: false,\n code: false, // analysis only – no output needed\n });\n};\n\n/**\n * Runs the usage-analysis Babel plugin on a source file, accumulating\n * field-usage data into `pruneContext`.\n *\n * For Vue / Svelte SFC files, script blocks are extracted before analysis so\n * Babel does not attempt to parse the full SFC syntax (templates, styles, …).\n * For plain JS/TS files, the whole file content is analysed directly.\n *\n * This is analysis-only: the transformed code output is discarded.\n * Throws if Babel cannot parse the file (caller should handle and flag\n * `pruneContext.hasUnparsableSourceFiles`).\n */\nexport const analyzeFieldUsageInFile = async (\n sourceFilePath: string,\n code: string,\n pruneContext: PruneContext,\n compatCallers?: CompatCallerConfig[]\n): Promise<void> => {\n const usageCheckRegex = getUsageCheckRegex(compatCallers);\n const scriptBlocks = extractScriptBlocks(sourceFilePath, code);\n\n // For SFC files (Vue / Svelte): scriptBlocks[0].contentStartOffset > 0\n // means we extracted actual <script> tags from the file.\n // For plain JS/TS: extractScriptBlocks returns the whole file as a single\n // block with offset 0, so we fall through to the same path.\n for (const block of scriptBlocks) {\n if (!usageCheckRegex.test(block.content)) continue;\n await analyzeScriptContent(\n block.content,\n sourceFilePath,\n pruneContext,\n compatCallers\n );\n }\n};\n\n/**\n * Applies field-renaming to a single JS/TS code string (not an SFC).\n *\n * Returns the renamed code string, or `null` if nothing changed or if\n * Babel failed to parse the input (caller should fall back to original code).\n */\nexport const renameFieldsInCode = async (\n code: string,\n sourceFilePath: string,\n pruneContext: PruneContext\n): Promise<string | null> => {\n try {\n const result = await transformAsync(code, {\n filename: sourceFilePath,\n plugins: [makeFieldRenameBabelPlugin(pruneContext)],\n parserOpts: BABEL_PARSER_OPTIONS,\n ast: false,\n });\n return result?.code ?? null;\n } catch {\n return null; // parse failure – caller falls back to original code\n }\n};\n\n/**\n * Applies field-renaming to a source file, correctly handling both plain\n * JS/TS files and SFC files (Vue / Svelte) by operating on each script block\n * individually and injecting the results back into the original source.\n *\n * Returns the renamed code string, or `null` if nothing changed.\n */\nexport const renameFieldsInSourceFile = async (\n sourceFilePath: string,\n code: string,\n pruneContext: PruneContext\n): Promise<string | null> => {\n if (pruneContext.dictionaryKeyToFieldRenameMap.size === 0) return null;\n if (!INTLAYER_USAGE_REGEX.test(code)) return null;\n\n const scriptBlocks = extractScriptBlocks(sourceFilePath, code);\n\n const isSFC =\n scriptBlocks.length > 0 &&\n ((scriptBlocks[0]?.contentStartOffset ?? 0) > 0 || scriptBlocks.length > 1);\n\n if (isSFC) {\n // Raw SFC: rename each script block individually and inject back.\n const modifications: Array<{\n block: (typeof scriptBlocks)[number];\n modifiedContent: string;\n }> = [];\n\n for (const block of scriptBlocks) {\n if (!INTLAYER_USAGE_REGEX.test(block.content)) continue;\n\n const renamedCode = await renameFieldsInCode(\n block.content,\n sourceFilePath,\n pruneContext\n );\n if (renamedCode && renamedCode !== block.content) {\n modifications.push({ block, modifiedContent: renamedCode });\n }\n }\n\n if (modifications.length === 0) return null;\n return injectScriptBlocks(code, modifications);\n }\n\n // Plain JS/TS or compiled SFC (no block delimiters) – rename the whole file.\n return renameFieldsInCode(code, sourceFilePath, pruneContext);\n};\n\n/**\n * Runs the intlayer optimize Babel plugin on a source file, transforming\n * `useIntlayer('key')` / `getIntlayer('key')` calls into `useDictionary(_hash)`\n * / `getDictionary(_hash)` and injecting the corresponding dictionary imports.\n *\n * Returns `{ code, map }` on success, or `null` if the transformation produced\n * no output.\n */\nexport const optimizeSourceFile = async (\n code: string,\n sourceFilePath: string,\n options: OptimizePluginOptions\n): Promise<{\n code: string;\n map: string | object | null | undefined;\n} | null> => {\n const result = await transformAsync(code, {\n filename: sourceFilePath,\n plugins: [[intlayerOptimizeBabelPlugin, options]],\n parserOpts: BABEL_PARSER_OPTIONS,\n });\n\n if (!result?.code) return null;\n\n return { code: result.code, map: result.map };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"transformers.mjs","names":[],"sources":["../../src/transformers.ts"],"sourcesContent":["import { transformAsync } from '@babel/core';\n// Typed from `@babel/parser` rather than `@babel/core`'s\n// `InputOptions['parserOpts']` (Babel 8's rename of `TransformOptions`): the\n// two describe the same shape, but naming `@babel/core` in an exported type\n// pulls its declaration file into every consumer's type-check, and that file\n// needs `@types/convert-source-map` to resolve.\nimport type { ParserOptions } from '@babel/parser';\nimport { makeFieldRenameBabelPlugin } from './babel-plugin-intlayer-field-rename';\nimport {\n intlayerOptimizeBabelPlugin,\n type OptimizePluginOptions,\n} from './babel-plugin-intlayer-optimize';\nimport {\n type CompatCallerConfig,\n INTLAYER_CALLER_NAMES,\n makeUsageAnalyzerBabelPlugin,\n type PruneContext,\n} from './babel-plugin-intlayer-usage-analyzer';\nimport { extractScriptBlocks, injectScriptBlocks } from './extractScriptBlocks';\n\n// ── Shared Babel parser configuration ─────────────────────────────────────────\n\n/**\n * Babel parser options covering the superset of syntaxes used across all\n * supported frameworks (React / Vue / Svelte / Angular / …).\n */\nexport const BABEL_PARSER_OPTIONS: ParserOptions = {\n sourceType: 'module',\n allowImportExportEverywhere: true,\n plugins: [\n 'typescript',\n 'jsx',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'asyncGenerators',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n};\n\n/**\n * Builds a fast pre-check regex that matches files potentially containing\n * native intlayer calls and/or the given compat namespace caller names.\n *\n * The result is used to skip files that definitely contain none of the\n * relevant function names, avoiding unnecessary Babel parsing.\n *\n * The native names come from {@link INTLAYER_CALLER_NAMES} rather than being\n * spelled out here: a name missing from this regex silently opts every file\n * using it out of the optimize, purge and minify passes, leaving its calls to\n * resolve through the dictionary registry — empty in browser bundles.\n *\n * Compat caller names are NOT hardcoded here — they are provided at runtime by\n * the compat adapter packages that configure the usage-analysis pipeline.\n *\n * @param extraCallerNames - Additional caller function names to match\n * (e.g. `['useTranslation', 'getFixedT']` from `@intlayer/react-i18next`).\n * @returns A `RegExp` matching any of the native or provided caller names.\n */\nexport const buildUsageCheckRegex = (extraCallerNames?: string[]): RegExp => {\n const callerNames = [...INTLAYER_CALLER_NAMES, ...(extraCallerNames ?? [])];\n const uniqueNames = [...new Set(callerNames)];\n return new RegExp(`\\\\b(${uniqueNames.join('|')})\\\\b`);\n};\n\n/**\n * Fast pre-check: matches files that could contain native intlayer calls\n * (`useIntlayer` / `getIntlayer` / `getIntlayerAsync`). Used by the\n * optimize/transform pass, which only rewrites native calls.\n */\nexport const INTLAYER_USAGE_REGEX = buildUsageCheckRegex();\n\n/** Usage-check regex covering only the native callers (no compat callers). */\nconst NATIVE_USAGE_CHECK_REGEX = INTLAYER_USAGE_REGEX;\n\n/** Cache of usage-check regexes, keyed by the compat-caller array reference. */\nconst usageCheckRegexCache = new WeakMap<\n readonly CompatCallerConfig[],\n RegExp\n>();\n\n/**\n * Returns the usage-check regex for the given compat callers, memoised by the\n * array reference. Plugins pass the same options array for every analysed\n * file, so the regex is built once per build instead of once per file.\n */\nexport const getUsageCheckRegex = (\n compatCallers?: readonly CompatCallerConfig[]\n): RegExp => {\n if (!compatCallers || compatCallers.length === 0) {\n return NATIVE_USAGE_CHECK_REGEX;\n }\n\n let usageCheckRegex = usageCheckRegexCache.get(compatCallers);\n if (!usageCheckRegex) {\n usageCheckRegex = buildUsageCheckRegex(\n compatCallers.map((caller) => caller.callerName)\n );\n usageCheckRegexCache.set(compatCallers, usageCheckRegex);\n }\n return usageCheckRegex;\n};\n\n/**\n * Matches source files that are valid targets for usage analysis and Babel\n * transformation. Excludes sourcemap files, declaration files, and other\n * non-source extensions.\n */\nexport const SOURCE_FILE_REGEX = /\\.(tsx?|[mc]?jsx?|vue|svelte|astro)$/;\n\n// ── High-level transformer functions ──────────────────────────────────────────\n\n/**\n * Runs the usage-analysis Babel plugin on a single JS/TS code string.\n *\n * This is analysis-only: the transformed code output is discarded.\n * Throws if Babel cannot parse the content.\n */\nconst analyzeScriptContent = async (\n scriptContent: string,\n sourceFilePath: string,\n pruneContext: PruneContext,\n compatCallers?: CompatCallerConfig[]\n): Promise<void> => {\n await transformAsync(scriptContent, {\n filename: sourceFilePath,\n plugins: [makeUsageAnalyzerBabelPlugin(pruneContext, { compatCallers })],\n parserOpts: BABEL_PARSER_OPTIONS,\n ast: false,\n code: false, // analysis only – no output needed\n });\n};\n\n/**\n * Runs the usage-analysis Babel plugin on a source file, accumulating\n * field-usage data into `pruneContext`.\n *\n * For Vue / Svelte SFC files, script blocks are extracted before analysis so\n * Babel does not attempt to parse the full SFC syntax (templates, styles, …).\n * For plain JS/TS files, the whole file content is analysed directly.\n *\n * This is analysis-only: the transformed code output is discarded.\n * Throws if Babel cannot parse the file (caller should handle and flag\n * `pruneContext.hasUnparsableSourceFiles`).\n */\nexport const analyzeFieldUsageInFile = async (\n sourceFilePath: string,\n code: string,\n pruneContext: PruneContext,\n compatCallers?: CompatCallerConfig[]\n): Promise<void> => {\n const usageCheckRegex = getUsageCheckRegex(compatCallers);\n const scriptBlocks = extractScriptBlocks(sourceFilePath, code);\n\n // For SFC files (Vue / Svelte): scriptBlocks[0].contentStartOffset > 0\n // means we extracted actual <script> tags from the file.\n // For plain JS/TS: extractScriptBlocks returns the whole file as a single\n // block with offset 0, so we fall through to the same path.\n for (const block of scriptBlocks) {\n if (!usageCheckRegex.test(block.content)) continue;\n await analyzeScriptContent(\n block.content,\n sourceFilePath,\n pruneContext,\n compatCallers\n );\n }\n};\n\n/**\n * Applies field-renaming to a single JS/TS code string (not an SFC).\n *\n * Returns the renamed code string, or `null` if nothing changed or if\n * Babel failed to parse the input (caller should fall back to original code).\n */\nexport const renameFieldsInCode = async (\n code: string,\n sourceFilePath: string,\n pruneContext: PruneContext\n): Promise<string | null> => {\n try {\n const result = await transformAsync(code, {\n filename: sourceFilePath,\n plugins: [makeFieldRenameBabelPlugin(pruneContext)],\n parserOpts: BABEL_PARSER_OPTIONS,\n ast: false,\n });\n return result?.code ?? null;\n } catch {\n return null; // parse failure – caller falls back to original code\n }\n};\n\n/**\n * Applies field-renaming to a source file, correctly handling both plain\n * JS/TS files and SFC files (Vue / Svelte) by operating on each script block\n * individually and injecting the results back into the original source.\n *\n * Returns the renamed code string, or `null` if nothing changed.\n */\nexport const renameFieldsInSourceFile = async (\n sourceFilePath: string,\n code: string,\n pruneContext: PruneContext\n): Promise<string | null> => {\n if (pruneContext.dictionaryKeyToFieldRenameMap.size === 0) return null;\n if (!INTLAYER_USAGE_REGEX.test(code)) return null;\n\n const scriptBlocks = extractScriptBlocks(sourceFilePath, code);\n\n const isSFC =\n scriptBlocks.length > 0 &&\n ((scriptBlocks[0]?.contentStartOffset ?? 0) > 0 || scriptBlocks.length > 1);\n\n if (isSFC) {\n // Raw SFC: rename each script block individually and inject back.\n const modifications: Array<{\n block: (typeof scriptBlocks)[number];\n modifiedContent: string;\n }> = [];\n\n for (const block of scriptBlocks) {\n if (!INTLAYER_USAGE_REGEX.test(block.content)) continue;\n\n const renamedCode = await renameFieldsInCode(\n block.content,\n sourceFilePath,\n pruneContext\n );\n if (renamedCode && renamedCode !== block.content) {\n modifications.push({ block, modifiedContent: renamedCode });\n }\n }\n\n if (modifications.length === 0) return null;\n return injectScriptBlocks(code, modifications);\n }\n\n // Plain JS/TS or compiled SFC (no block delimiters) – rename the whole file.\n return renameFieldsInCode(code, sourceFilePath, pruneContext);\n};\n\n/**\n * Runs the intlayer optimize Babel plugin on a source file, transforming\n * `useIntlayer('key')` / `getIntlayer('key')` calls into `useDictionary(_hash)`\n * / `getDictionary(_hash)` and injecting the corresponding dictionary imports.\n *\n * Returns `{ code, map }` on success, or `null` if the transformation produced\n * no output.\n */\nexport const optimizeSourceFile = async (\n code: string,\n sourceFilePath: string,\n options: OptimizePluginOptions\n): Promise<{\n code: string;\n map: string | object | null | undefined;\n} | null> => {\n const result = await transformAsync(code, {\n filename: sourceFilePath,\n plugins: [[intlayerOptimizeBabelPlugin, options]],\n parserOpts: BABEL_PARSER_OPTIONS,\n });\n\n if (!result?.code) return null;\n\n return { code: result.code, map: result.map };\n};\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { PruneContext } from "./pruneContext.js";
2
+ import { NodePath } from "@babel/core";
3
+ import * as BabelTypes from "@babel/types";
4
+ //#region src/analyzeContentUsage.d.ts
5
+ /**
6
+ * Analyses how the result of a single `useIntlayer('key')` / `getIntlayer('key')`
7
+ * call expression is consumed, then records the field usage into `pruneContext`.
8
+ *
9
+ * Recognised patterns:
10
+ * const { fieldA, fieldB } = useIntlayer('key') → records {fieldA, fieldB}
11
+ * useIntlayer('key').fieldA → records {fieldA}
12
+ * useIntlayer('key')['fieldA'] → records {fieldA}
13
+ * const { ...rest } = useIntlayer('key') → records 'all' (spread)
14
+ * const result = useIntlayer('key') → records 'all' (untracked binding)
15
+ */
16
+ export declare const analyzeCallExpressionUsage: (babelTypes: typeof BabelTypes, pruneContext: PruneContext, callExpressionPath: NodePath<BabelTypes.CallExpression>, dictionaryKey: string, currentSourceFilePath: string, isSfcFile: boolean) => void;
17
+ //#endregion
18
+ //# sourceMappingURL=analyzeContentUsage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzeContentUsage.d.ts","names":[],"sources":["../../src/analyzeContentUsage.ts"],"mappings":";;;;;;;;;;;;;;;qBAqBa,6BAA0B,mBAClB,YAAU,cACf,cAAY,oBACN,SAAS,WAAW,iBAAe,uBAClC,+BACQ"}
@@ -5,13 +5,13 @@ import { Locale } from "@intlayer/types/allLocales";
5
5
  import { IntlayerConfig } from "@intlayer/types/config";
6
6
  import { FilePathPattern } from "@intlayer/types/filePathPattern";
7
7
  //#region src/babel-plugin-intlayer-extract.d.ts
8
- type ExtractResult = {
8
+ export type ExtractResult = {
9
9
  dictionaryKey: string;
10
10
  filePath: string;
11
11
  content: Record<string, string>;
12
12
  locale: Locale;
13
13
  };
14
- type ExtractPluginOptions = {
14
+ export type ExtractPluginOptions = {
15
15
  packageName?: PackageName;
16
16
  filesList: string[];
17
17
  enabled: boolean;
@@ -48,9 +48,8 @@ type State = PluginPass & {
48
48
  * };
49
49
  * ```
50
50
  */
51
- declare const intlayerExtractBabelPlugin: (_babel: {
51
+ export declare const intlayerExtractBabelPlugin: (_babel: {
52
52
  types: typeof BabelTypes;
53
53
  }) => PluginObject<State>;
54
54
  //#endregion
55
- export { ExtractPluginOptions, ExtractResult, intlayerExtractBabelPlugin };
56
55
  //# sourceMappingURL=babel-plugin-intlayer-extract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"mappings":";;;;;;;KAeY;EACV;EACA;EACA,SAAS;EACT,QAAQ;;KAGE;EACV,cAAc;EACd;EACA;EAEA,iBAAiB;EACjB,eAAe;;;;;;EAMf,aAAa,QAAQ,yBAAyB;;;;EAI9C,SAAS;;KAGN,QAAQ;EAAe,MAAM;;;;;;;;;;;;;;;;;;;cAmBrB,6BAA0B;EACrC,cAAc;MACZ,aAAa"}
1
+ {"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"mappings":";;;;;;;YAeY;EACV;EACA;EACA,SAAS;EACT,QAAQ;;YAGE;EACV,cAAc;EACd;EACA;EAEA,iBAAiB;EACjB,eAAe;;;;;;EAMf,aAAa,QAAQ,yBAAyB;;;;EAI9C,SAAS;;KAGN,QAAQ;EAAe,MAAM;;;;;;;;;;;;;;;;;;;qBAmBrB,6BAA0B;EACrC,cAAc;MACZ,aAAa"}
@@ -1,4 +1,5 @@
1
- import { NestedRenameEntry, NestedRenameMap, PruneContext } from "./babel-plugin-intlayer-usage-analyzer.js";
1
+ import { NestedRenameEntry, NestedRenameMap, PruneContext } from "./pruneContext.js";
2
+ import "./babel-plugin-intlayer-usage-analyzer.js";
2
3
  import { NodePath, PluginObject } from "@babel/core";
3
4
  import * as BabelTypes from "@babel/types";
4
5
  //#region src/babel-plugin-intlayer-field-rename.d.ts
@@ -6,7 +7,7 @@ import * as BabelTypes from "@babel/types";
6
7
  * Converts a zero-based index to a short alphabetic identifier.
7
8
  * 0 → 'a', 1 → 'b', …, 25 → 'z', 26 → 'aa', 27 → 'ab', …
8
9
  */
9
- declare const generateShortFieldName: (index: number) => string;
10
+ export declare const generateShortFieldName: (index: number) => string;
10
11
  /**
11
12
  * Recursively builds a `NestedRenameMap` from a compiled dictionary content
12
13
  * value by traversing the intlayer node structure.
@@ -34,7 +35,7 @@ declare const generateShortFieldName: (index: number) => string;
34
35
  *
35
36
  * @param contentValue - The dictionary content value to analyse.
36
37
  */
37
- declare const buildNestedRenameMapFromContent: (contentValue: unknown) => NestedRenameMap;
38
+ export declare const buildNestedRenameMapFromContent: (contentValue: unknown) => NestedRenameMap;
38
39
  /**
39
40
  * Walks `fieldPath` through a {@link NestedRenameMap} and returns the entry at
40
41
  * the final path segment, or `undefined` when any segment is missing (e.g. the
@@ -46,21 +47,21 @@ declare const buildNestedRenameMapFromContent: (contentValue: unknown) => Nested
46
47
  * @param renameMap - The root rename map to walk.
47
48
  * @param fieldPath - Original (pre-rename) field names from the content root.
48
49
  */
49
- declare const getNestedRenameEntryAtPath: (renameMap: NestedRenameMap, fieldPath: readonly string[]) => NestedRenameEntry | undefined;
50
+ export declare const getNestedRenameEntryAtPath: (renameMap: NestedRenameMap, fieldPath: readonly string[]) => NestedRenameEntry | undefined;
50
51
  /**
51
52
  * JSON-serialisable form of a {@link NestedRenameEntry}.
52
53
  *
53
54
  * Mirrors `FieldRenameNode` in the `@intlayer/swc` crate — both sides must stay
54
55
  * in sync.
55
56
  */
56
- type SerializedFieldRenameEntry = {
57
+ export type SerializedFieldRenameEntry = {
57
58
  /** Short alphabetic alias the field is renamed to (`'a'`, `'b'`, …). */
58
59
  shortName: string;
59
60
  /** Rename table of the fields nested inside this one. */
60
61
  children: SerializedFieldRenameMap;
61
62
  };
62
63
  /** JSON-serialisable form of a {@link NestedRenameMap}. */
63
- type SerializedFieldRenameMap = Record<string, SerializedFieldRenameEntry>;
64
+ export type SerializedFieldRenameMap = Record<string, SerializedFieldRenameEntry>;
64
65
  /**
65
66
  * Converts the field-rename tables of a {@link PruneContext} into a plain JSON
66
67
  * object, keyed by dictionary key.
@@ -74,7 +75,7 @@ type SerializedFieldRenameMap = Record<string, SerializedFieldRenameEntry>;
74
75
  * Empty tables are omitted as well, so the result is empty when there is
75
76
  * nothing to rename.
76
77
  */
77
- declare const serializeFieldRenameMap: (pruneContext: PruneContext) => Record<string, SerializedFieldRenameMap>;
78
+ export declare const serializeFieldRenameMap: (pruneContext: PruneContext) => Record<string, SerializedFieldRenameMap>;
78
79
  /**
79
80
  * Rewrites dictionary content field accesses in the given program to the
80
81
  * short aliases defined in `pruneContext.dictionaryKeyToFieldRenameMap`.
@@ -99,7 +100,7 @@ declare const serializeFieldRenameMap: (pruneContext: PruneContext) => Record<st
99
100
  * {@link makeFieldRenameBabelPlugin} and `intlayerMinifyBabelPlugin` can
100
101
  * invoke it from their own `Program.exit` visitors.
101
102
  */
102
- declare const renameIntlayerFieldAccesses: (babelTypes: typeof BabelTypes, programPath: NodePath<BabelTypes.Program>, pruneContext: PruneContext) => void;
103
+ export declare const renameIntlayerFieldAccesses: (babelTypes: typeof BabelTypes, programPath: NodePath<BabelTypes.Program>, pruneContext: PruneContext) => void;
103
104
  /**
104
105
  * Creates a Babel plugin that rewrites dictionary content field accesses in
105
106
  * source files to their short aliases via
@@ -109,9 +110,8 @@ declare const renameIntlayerFieldAccesses: (babelTypes: typeof BabelTypes, progr
109
110
  * `intlayerOptimizeBabelPlugin`, because the latter replaces `useIntlayer`
110
111
  * with `useDictionary`, erasing the dictionary-key information needed here.
111
112
  */
112
- declare const makeFieldRenameBabelPlugin: (pruneContext: PruneContext) => ({ types: babelTypes }: {
113
+ export declare const makeFieldRenameBabelPlugin: (pruneContext: PruneContext) => ({ types: babelTypes }: {
113
114
  types: typeof BabelTypes;
114
115
  }) => PluginObject;
115
116
  //#endregion
116
- export { SerializedFieldRenameEntry, SerializedFieldRenameMap, buildNestedRenameMapFromContent, generateShortFieldName, getNestedRenameEntryAtPath, makeFieldRenameBabelPlugin, renameIntlayerFieldAccesses, serializeFieldRenameMap };
117
117
  //# sourceMappingURL=babel-plugin-intlayer-field-rename.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-field-rename.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-field-rename.ts"],"mappings":";;;;;;;;cA4Ba,yBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0CtB,kCAA+B,0BAEzC;;;;;;;;;;;;cA2EU,6BAA0B,WAC1B,iBAAe,iCAEzB;;;;;;;KAqBS;;EAEV;;EAEA,UAAU;;;KAIA,2BAA2B,eAErC;;;;;;;;;;;;;;cAgCW,0BAAuB,cACpB,iBACb,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;cA4aL,8BAA2B,mBACnB,YAAU,aAChB,SAAS,WAAW,UAAQ,cAC3B;;;;;;;;;;cAsIH,6BAA0B,cACtB,oBAAY,OAAA;EACD,cAAc;MAAe"}
1
+ {"version":3,"file":"babel-plugin-intlayer-field-rename.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-field-rename.ts"],"mappings":";;;;;;;;;qBA2Ba,yBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA0CtB,kCAA+B,0BAEzC;;;;;;;;;;;;qBA2EU,6BAA0B,WAC1B,iBAAe,iCAEzB;;;;;;;YAqBS;;EAEV;;EAEA,UAAU;;;YAIA,2BAA2B,eAErC;;;;;;;;;;;;;;qBAgCW,0BAAuB,cACpB,iBACb,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;qBA4aL,8BAA2B,mBACnB,YAAU,aAChB,SAAS,WAAW,UAAQ,cAC3B;;;;;;;;;;qBAsIH,6BAA0B,cACtB,oBAAY,OAAA;EACD,cAAc;MAAe"}
@@ -8,7 +8,7 @@ import * as BabelTypes from "@babel/types";
8
8
  * {@link getMinifyPluginOptions}) so the plugin does not read the intlayer
9
9
  * configuration file on every file transform.
10
10
  */
11
- type MinifyPluginOptions = {
11
+ export type MinifyPluginOptions = {
12
12
  /**
13
13
  * Absolute path to the project root. Used to look up the shared
14
14
  * {@link PruneContext} built by {@link intlayerPurgeBabelPlugin}.
@@ -75,9 +75,8 @@ type MinifyPluginOptions = {
75
75
  * `useDictionary`, erasing the dictionary-key information needed to look up
76
76
  * the rename map.
77
77
  */
78
- declare const intlayerMinifyBabelPlugin: (babel: {
78
+ export declare const intlayerMinifyBabelPlugin: (babel: {
79
79
  types: typeof BabelTypes;
80
80
  }) => PluginObject;
81
81
  //#endregion
82
- export { MinifyPluginOptions, intlayerMinifyBabelPlugin };
83
82
  //# sourceMappingURL=babel-plugin-intlayer-minify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-minify.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-minify.ts"],"mappings":";;;;;;;;;;KAgBY;;;;;EAKV;;;;;;EAOA;;;;;EAMA;;;;EAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkDW,4BAAyB;EACpC,cAAc;MACZ"}
1
+ {"version":3,"file":"babel-plugin-intlayer-minify.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-minify.ts"],"mappings":";;;;;;;;;;YAgBY;;;;;EAKV;;;;;;EAOA;;;;;EAMA;;;;EAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkDW,4BAAyB;EACpC,cAAc;MACZ"}
@@ -2,11 +2,10 @@ import { PluginObject, PluginPass } from "@babel/core";
2
2
  import * as BabelTypes from "@babel/types";
3
3
  import { CallerDescriptor } from "@intlayer/config/callers";
4
4
  //#region src/babel-plugin-intlayer-optimize.d.ts
5
- declare const CALLER_LIST: readonly ['useIntlayer', 'getIntlayer', 'getIntlayerAsync'];
6
5
  /**
7
6
  * Options for the optimization Babel plugin
8
7
  */
9
- type OptimizePluginOptions = {
8
+ export type OptimizePluginOptions = {
10
9
  /**
11
10
  * If false, the plugin will not apply any transformation.
12
11
  */
@@ -93,23 +92,18 @@ type OptimizePluginOptions = {
93
92
  */
94
93
  compatCallers?: CallerDescriptor[];
95
94
  };
95
+ /**
96
+ * Per-file plugin state.
97
+ *
98
+ * Only the two flags that have to survive from `pre` / `Program.enter` into
99
+ * `Program.exit` live here — the caller maps and the import registry are built
100
+ * and consumed inside `exit`, so they stay local to it.
101
+ */
96
102
  type State = PluginPass & {
97
103
  opts: OptimizePluginOptions;
98
- /** map key → generated ident (per-file) for static imports */
99
- _newStaticImports?: Map<string, BabelTypes.Identifier>;
100
- /** map key → generated ident (per-file) for dynamic imports */
101
- _newDynamicImports?: Map<string, BabelTypes.Identifier>;
102
- /** whether the current file imported *any* intlayer package */
103
- _hasValidImport?: boolean;
104
- /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */
105
- _callerMap?: Map<string, (typeof CALLER_LIST)[number]>;
106
- /** map from local identifier name to the intlayer package it was imported from */
107
- _callerPackageMap?: Map<string, string>;
108
- /** map from local identifier name to the compat caller descriptor it was imported as */
109
- _compatCallerMap?: Map<string, CallerDescriptor>;
110
- /** whether the current file *is* the dictionaries entry file */
104
+ /** Whether the current file *is* a generated dictionaries entry file. */
111
105
  _isDictEntry?: boolean;
112
- /** whether the current file is included in the filesList */
106
+ /** Whether the current file is covered by the `filesList` allowlist. */
113
107
  _isIncluded?: boolean;
114
108
  };
115
109
  /**
@@ -208,9 +202,8 @@ type State = PluginPass & {
208
202
  * const content2 = getIntlayer(_dicHash);
209
203
  * ```
210
204
  */
211
- declare const intlayerOptimizeBabelPlugin: (babel: {
205
+ export declare const intlayerOptimizeBabelPlugin: (babel: {
212
206
  types: typeof BabelTypes;
213
207
  }) => PluginObject<State>;
214
208
  //#endregion
215
- export { OptimizePluginOptions, intlayerOptimizeBabelPlugin };
216
209
  //# sourceMappingURL=babel-plugin-intlayer-optimize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-optimize.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"mappings":";;;;cA8BM;;;;KAwDM;;;;EAIV;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;;;;;;;;;;;;EAeA;;;;EAIA;;;;EAIA,oBAAoB;;;;EAOpB;;;;EAIA;;;;;;;;;;;;;;EAcA,gBAAgB;;KAGb,QAAQ;EACX,MAAM;;EAEN,oBAAoB,YAAY,WAAW;;EAE3C,qBAAqB,YAAY,WAAW;;EAE5C;;EAEA,aAAa,oBAAoB;;EAEjC,oBAAoB;;EAEpB,mBAAmB,YAAY;;EAE/B;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+TW,8BAA2B;EACtC,cAAc;MACZ,aAAa"}
1
+ {"version":3,"file":"babel-plugin-intlayer-optimize.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"mappings":";;;;;;;YA8FY;;;;EAIV;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;EAIA;;;;;;;;;;;;;;;EAeA;;;;EAIA;;;;EAIA,oBAAoB;;;;EAOpB;;;;EAIA;;;;;;;;;;;;;;EAcA,gBAAgB;;;;;;;;;KAUb,QAAQ;EACX,MAAM;;EAEN;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgTW,8BAA2B;EACtC,cAAc;MACZ,aAAa"}
@@ -1,8 +1,9 @@
1
- import { CompatCallerConfig, PruneContext } from "./babel-plugin-intlayer-usage-analyzer.js";
1
+ import { PruneContext } from "./pruneContext.js";
2
+ import { CompatCallerConfig } from "./babel-plugin-intlayer-usage-analyzer.js";
2
3
  import { PluginObject } from "@babel/core";
3
4
  import * as BabelTypes from "@babel/types";
4
- import { IntlayerConfig } from "@intlayer/types/config";
5
5
  import { NestedFieldReferences } from "@intlayer/core/dictionaryManipulator";
6
+ import { IntlayerConfig } from "@intlayer/types/config";
6
7
  //#region src/babel-plugin-intlayer-purge.d.ts
7
8
  /**
8
9
  * Pre-resolved options accepted by {@link intlayerPurgeBabelPlugin}.
@@ -11,7 +12,7 @@ import { NestedFieldReferences } from "@intlayer/core/dictionaryManipulator";
11
12
  * {@link getPurgePluginOptions}) so the plugin itself does not need to read
12
13
  * the configuration file on every file transform.
13
14
  */
14
- type PurgePluginOptions = {
15
+ export type PurgePluginOptions = {
15
16
  /**
16
17
  * Absolute path to the project root. Used as the cache key for the shared
17
18
  * {@link PruneContext} so two Babel transform pipelines for different
@@ -99,7 +100,7 @@ type PurgePluginOptions = {
99
100
  * Used by {@link intlayerMinifyBabelPlugin} to read the rename map without
100
101
  * creating a circular dependency.
101
102
  */
102
- declare const getSharedPruneContext: (baseDir: string) => PruneContext | null;
103
+ export declare const getSharedPruneContext: (baseDir: string) => PruneContext | null;
103
104
  /**
104
105
  * Runs the full purge/minify pipeline for the given options, using a
105
106
  * module-level cache so the work happens at most once per process per
@@ -117,7 +118,7 @@ declare const getSharedPruneContext: (baseDir: string) => PruneContext | null;
117
118
  * in-place. Call it at most once per build, after the dictionaries have been
118
119
  * built.
119
120
  */
120
- declare const runIntlayerPurgePipeline: (options: PurgePluginOptions) => PruneContext;
121
+ export declare const runIntlayerPurgePipeline: (options: PurgePluginOptions) => PruneContext;
121
122
  /**
122
123
  * Babel plugin that analyses all project source files and rewrites compiled
123
124
  * dictionary JSON files in-place to remove unused content fields
@@ -168,9 +169,8 @@ declare const runIntlayerPurgePipeline: (options: PurgePluginOptions) => PruneCo
168
169
  * renaming is skipped, so the `keyPath` the visual editor receives keeps
169
170
  * matching the unmerged dictionaries it edits.
170
171
  */
171
- declare const intlayerPurgeBabelPlugin: (_babel: {
172
+ export declare const intlayerPurgeBabelPlugin: (_babel: {
172
173
  types: typeof BabelTypes;
173
174
  }) => PluginObject;
174
175
  //#endregion
175
- export { PurgePluginOptions, getSharedPruneContext, intlayerPurgeBabelPlugin, runIntlayerPurgePipeline };
176
176
  //# sourceMappingURL=babel-plugin-intlayer-purge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-purge.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-purge.ts"],"mappings":";;;;;;;;;;;;;KA2CY;;;;;;EAMV;;;;;EAMA;;;;;;EAOA;;;;;;EAOA;;;;;;EAOA;;;;;EAMA;;;;;EAMA;;;;;;EAOA;;;;;;;;EASA,6BAA6B,YAAY;;;;;;EAOzC,8BAA8B;;;;;;;;;;;;EAgB9B,gBAAgB;;;;;;;EAQhB,YAAY,KAAK;;;;;;;;;;cAwBN,wBAAqB,oBAAsB;;;;;;;;;;;;;;;;;;cA0rB3C,2BAAwB,SAC1B,uBACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmIU,2BAAwB;EACnC,cAAc;MACZ"}
1
+ {"version":3,"file":"babel-plugin-intlayer-purge.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-purge.ts"],"mappings":";;;;;;;;;;;;;;YA2CY;;;;;;EAMV;;;;;EAMA;;;;;;EAOA;;;;;;EAOA;;;;;;EAOA;;;;;EAMA;;;;;EAMA;;;;;;EAOA;;;;;;;;EASA,6BAA6B,YAAY;;;;;;EAOzC,8BAA8B;;;;;;;;;;;;EAgB9B,gBAAgB;;;;;;;EAQhB,YAAY,KAAK;;;;;;;;;;qBAwBN,wBAAqB,oBAAsB;;;;;;;;;;;;;;;;;;qBA0rB3C,2BAAwB,SAC1B,uBACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAmIU,2BAAwB;EACnC,cAAc;MACZ"}
@@ -1,213 +1,46 @@
1
- import { NodePath, PluginObject } from "@babel/core";
1
+ import { DictionaryFieldUsage, NestedRenameEntry, NestedRenameMap, OpaqueFieldOccurrence, PruneContext, createPruneContext, preserveNestedDictionaryFields } from "./pruneContext.js";
2
+ import { CHAINABLE_RUNTIME_METHOD_NAMES, INTLAYER_CALLER_NAMES, IntlayerCallerName, NATIVE_CALLER_NAME_SET } from "./nativeCallers.js";
3
+ import { unwrapAwait } from "./staticAstReaders.js";
4
+ import { PluginObject } from "@babel/core";
2
5
  import * as BabelTypes from "@babel/types";
3
6
  import { CallerDescriptor, CallerDescriptor as CallerDescriptor$1, CallerResultShape, CallerValueSource } from "@intlayer/config/callers";
4
- import { NestedFieldReferences } from "@intlayer/core/dictionaryManipulator";
5
7
  //#region src/babel-plugin-intlayer-usage-analyzer.d.ts
6
- /**
7
- * Dictionary field usage result for a single dictionary key.
8
- *
9
- * 'all' → could not determine statically which fields are used;
10
- * keep every field (no pruning possible).
11
- * Set<string> → the exact top-level content field names that were accessed.
12
- */
13
- type DictionaryFieldUsage = Set<string> | 'all';
14
- /**
15
- * One node in the nested field-rename tree.
16
- *
17
- * shortName – the compact alias assigned to this field name.
18
- * children – rename table for the next level of user-defined keys inside
19
- * this field's value (empty when the value is a leaf / primitive).
20
- */
21
- type NestedRenameEntry = {
22
- shortName: string;
23
- children: NestedRenameMap;
24
- };
25
- /** A level of the field-rename tree, mapping original field names to entries. */
26
- type NestedRenameMap = Map<string, NestedRenameEntry>;
27
- /**
28
- * One opaque consumption of a dictionary content value: the value at
29
- * `fieldPath` escapes static analysis (passed as-is to a child component or a
30
- * function argument), so its children must keep their original key names in
31
- * the compiled JSON.
32
- */
33
- type OpaqueFieldOccurrence = {
34
- /**
35
- * Original (pre-rename) user-defined field names from the content root to
36
- * the escaping value, e.g. `['sections', 'hero']` for
37
- * `<Card data={content.sections.hero} />`.
38
- */
39
- fieldPath: string[];
40
- /** Source locations (`filePath:line`) where the value escapes. */
41
- locations: string[];
42
- };
43
- /**
44
- * Shared mutable state created once by the vite plugin and passed by reference
45
- * to the usage-analyzer (writer) and the prune/minify plugins (readers).
46
- *
47
- * All mutations happen during the usage-analysis `buildStart` phase; readers
48
- * only access this state during the subsequent `transform` phase.
49
- */
50
- type PruneContext = {
51
- /**
52
- * Maps every dictionary key seen in source files to the set of top-level
53
- * content fields statically accessed, or `'all'` when the access pattern
54
- * could not be determined.
55
- */
56
- dictionaryKeyToFieldUsageMap: Map<string, DictionaryFieldUsage>;
57
- /**
58
- * Dictionary keys for which the prune/minify step must be skipped entirely
59
- * because an edge case was detected during analysis or structure recognition.
60
- */
61
- dictionariesWithEdgeCases: Set<string>;
62
- /**
63
- * True if at least one source file failed to parse during the analysis phase.
64
- * The prune plugin uses this flag conservatively: any dictionary key without
65
- * a usage entry might have been referenced by the unparsable file.
66
- */
67
- hasUnparsableSourceFiles: boolean;
68
- /**
69
- * Maps dictionary keys to the source file paths where the result of
70
- * `useIntlayer` / `getIntlayer` was assigned to a plain variable, making
71
- * static field analysis impossible.
72
- */
73
- dictionaryKeysWithUntrackedBindings: Map<string, string[]>;
74
- /**
75
- * Maps each dictionary key to a nested field-rename tree built after the
76
- * usage analysis phase (only populated when `build.minify` is active and
77
- * the field usage for that dictionary is a finite `Set<string>`).
78
- */
79
- dictionaryKeyToFieldRenameMap: Map<string, NestedRenameMap>;
80
- /**
81
- * Maps each dictionary key to the content field paths whose values are
82
- * consumed "opaquely" (passed as-is to a child component or function
83
- * argument). When an opaque value has nested user-defined structure, its
84
- * children must not be renamed.
85
- *
86
- * The inner map is keyed by the dot-joined field path for de-duplication
87
- * only; the authoritative path is {@link OpaqueFieldOccurrence.fieldPath}.
88
- *
89
- * Structure: dictionaryKey → joinedFieldPath → { fieldPath, locations }
90
- */
91
- dictionaryKeysWithOpaqueFields: Map<string, Map<string, OpaqueFieldOccurrence>>;
92
- /**
93
- * Dictionary keys for which field-key renaming must be skipped even if a
94
- * finite field-usage set was determined.
95
- *
96
- * Populated for dictionaries whose plain-variable bindings were resolved by
97
- * the framework-specific extractor (Vue / Svelte SFCs), because the Babel
98
- * rename plugin cannot update the source-code property accesses for those
99
- * indirect patterns (Vue `.value.field` / Svelte `$store.field`).
100
- *
101
- * Pruning and basic minification still apply; only field-key renaming is
102
- * suppressed.
103
- */
104
- dictionariesSkippingFieldRename: Set<string>;
105
- /**
106
- * Plain variable bindings that require a framework-specific secondary pass.
107
- *
108
- * Populated during the Babel analysis phase for `.vue` and `.svelte` source
109
- * files where direct field access is not visible to Babel scope analysis:
110
- * - Vue: `content.value.fieldName` – the `.value` ref-accessor is hidden
111
- * - Svelte: `$varName.fieldName` – the `$` prefix creates a new identifier
112
- *
113
- * Structure: filePath → [{variableName, dictionaryKey}, …]
114
- */
115
- pendingFrameworkAnalysis: Map<string, {
116
- variableName: string;
117
- dictionaryKey: string;
118
- }[]>;
119
- };
120
- declare const createPruneContext: () => PruneContext;
121
- /**
122
- * Records `nest()` references in a prune context so nest targets stay
123
- * resolvable — and no larger than they need to be — after purge and minify.
124
- *
125
- * A nested node stores the ORIGINAL dot path of the field it reads
126
- * (`nest('common', 'period')` → `'period'`) and `getNesting` resolves it at
127
- * runtime against the compiled JSON. That drives three adjustments:
128
- *
129
- * - Nest targets never take part in field renaming, since the stored path
130
- * would no longer match the renamed keys.
131
- * - A target already consumed by a call site keeps its analysed fields plus
132
- * the nested ones, so neither consumer loses content.
133
- * - A target reached *only* through `nest()` is given a usage entry holding
134
- * exactly the nested fields. Without one, the purge pass leaves the whole
135
- * dictionary untouched; with one, it trims the dictionary down to what the
136
- * nest references actually read. This matters most for `dynamic` / `fetch`
137
- * dictionaries, whose full static snapshot would otherwise be pulled into
138
- * the eager bundle just to satisfy a single nested field.
139
- *
140
- * Seeding is skipped when a source file failed to parse: that file could
141
- * reference the dictionary in a way the analysis never saw, which is the same
142
- * guard the purge pass applies to keys with no usage entry.
143
- *
144
- * @param pruneContext - Shared analysis state to update in place.
145
- * @param nestedDictionaryReferences - Nest-target key → referenced top-level
146
- * fields, as returned by `getNestedDictionaryReferences`.
147
- */
148
- declare const preserveNestedDictionaryFields: (pruneContext: PruneContext, nestedDictionaryReferences: Map<string, NestedFieldReferences>) => void;
149
- /**
150
- * Methods the runtime attaches to a resolved content object rather than fields
151
- * declared in a `.content` file.
152
- *
153
- * `vanilla-intlayer`'s `useIntlayer` / `useDictionary` assign `onChange` onto
154
- * the content they return, so `useIntlayer('app').onChange(cb)` is a
155
- * subscription — not a read of a field named `onChange`. Without this list the
156
- * analyser records `onChange` as the only consumed field and the purge pass
157
- * strips every real field from the compiled dictionary.
158
- *
159
- * The analyser looks *through* these calls: the callback parameter is analysed
160
- * as a fresh content root, and the call result is analysed again because the
161
- * helpers return the content object for chaining.
162
- */
163
- declare const CHAINABLE_RUNTIME_METHOD_NAMES: Set<string>;
164
- /** Canonical intlayer caller names that trigger usage analysis. */
165
- declare const INTLAYER_CALLER_NAMES: readonly ['useIntlayer', 'getIntlayer', 'getIntlayerAsync'];
166
- type IntlayerCallerName = (typeof INTLAYER_CALLER_NAMES)[number];
167
8
  /**
168
9
  * Configuration entry for a single compat namespace caller.
169
10
  *
170
11
  * @deprecated Alias kept for backward compatibility — use the shared
171
12
  * {@link CallerDescriptor} from `@intlayer/config/callers` instead.
172
13
  */
173
- type CompatCallerConfig = CallerDescriptor$1;
174
- /**
175
- * Default registry of compat namespace callers.
176
- *
177
- * Intentionally empty — compat-specific caller configurations belong in their
178
- * respective adapter packages (e.g. `@intlayer/react-i18next/plugin`,
179
- * `@intlayer/vue-i18n/plugin`) and are injected into `makeUsageAnalyzerBabelPlugin`
180
- * via the `compatCallers` option. Centralising them here would couple the
181
- * core `@intlayer/babel` package to every compat adapter, which violates the
182
- * design principle that compat logic lives in compat packages.
183
- */
184
- declare const DEFAULT_COMPAT_CALLERS: CompatCallerConfig[];
14
+ export type CompatCallerConfig = CallerDescriptor$1;
185
15
  /**
186
- * Climbs past an enclosing `await` expression so that
187
- * `const t = await getTranslations('ns')` — or `await getIntlayerAsync('key')`
188
- * — is resolved to its variable declarator the same way the synchronous form
189
- * is.
16
+ * @deprecated Always empty. Compat callers are injected per build through
17
+ * `options.compatCallers`; there is no default registry to fall back to.
190
18
  */
191
- declare const unwrapAwait: (babelTypes: typeof BabelTypes, path: NodePath<BabelTypes.Node>) => NodePath<BabelTypes.Node>;
19
+ export declare const DEFAULT_COMPAT_CALLERS: CallerDescriptor$1[];
192
20
  /**
193
21
  * Creates a Babel plugin that traverses source files and records which
194
- * top-level dictionary fields each `useIntlayer` / `getIntlayer` call-site —
195
- * and each configured compat namespace caller — accesses. Results are
196
- * accumulated into `pruneContext`.
22
+ * top-level dictionary fields each `useIntlayer` / `getIntlayer` call-site
23
+ * accesses. Results are accumulated into `pruneContext`.
24
+ *
25
+ * Compat-adapter callers (`useTranslation`, `useTranslations`, `formatMessage`,
26
+ * …) are *not* known to this plugin. Each compat package's bundler plugin
27
+ * injects its own descriptors through `options.compatCallers`, and the whole
28
+ * compat analysis then runs behind {@link createCompatUsageAnalyzer}. With no
29
+ * descriptors injected — the default — none of that code is reached, so a
30
+ * plain intlayer build behaves exactly as if the adapters did not exist.
197
31
  *
198
32
  * This plugin is analysis-only: it does not transform the code (`code: false`
199
33
  * should be passed to `transformAsync` when using it).
200
34
  *
201
35
  * @param pruneContext - Shared mutable state written by this plugin.
202
- * @param options - Optional overrides. `compatCallers` defaults to
203
- * {@link DEFAULT_COMPAT_CALLERS}; pass `[]` to disable
204
- * compat-adapter analysis entirely.
36
+ * @param options - Optional overrides. `compatCallers` defaults to an
37
+ * empty registry, disabling compat-adapter analysis.
205
38
  */
206
- declare const makeUsageAnalyzerBabelPlugin: (pruneContext: PruneContext, options?: {
207
- compatCallers?: CompatCallerConfig[];
39
+ export declare const makeUsageAnalyzerBabelPlugin: (pruneContext: PruneContext, options?: {
40
+ compatCallers?: readonly CallerDescriptor$1[];
208
41
  }) => ({ types: babelTypes }: {
209
42
  types: typeof BabelTypes;
210
43
  }) => PluginObject;
211
44
  //#endregion
212
- export { CHAINABLE_RUNTIME_METHOD_NAMES, type CallerDescriptor, type CallerResultShape, type CallerValueSource, CompatCallerConfig, DEFAULT_COMPAT_CALLERS, DictionaryFieldUsage, INTLAYER_CALLER_NAMES, IntlayerCallerName, NestedRenameEntry, NestedRenameMap, OpaqueFieldOccurrence, PruneContext, createPruneContext, makeUsageAnalyzerBabelPlugin, preserveNestedDictionaryFields, unwrapAwait };
45
+ export { CHAINABLE_RUNTIME_METHOD_NAMES, type CallerDescriptor, type CallerResultShape, type CallerValueSource, type DictionaryFieldUsage, INTLAYER_CALLER_NAMES, type IntlayerCallerName, NATIVE_CALLER_NAME_SET, type NestedRenameEntry, type NestedRenameMap, type OpaqueFieldOccurrence, type PruneContext, createPruneContext, preserveNestedDictionaryFields, unwrapAwait };
213
46
  //# sourceMappingURL=babel-plugin-intlayer-usage-analyzer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-usage-analyzer.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-usage-analyzer.ts"],"mappings":";;;;;;;;;;;;KAiBY,uBAAuB;;;;;;;;KASvB;EACV;EACA,UAAU;;;KAIA,kBAAkB,YAAY;;;;;;;KAQ9B;;;;;;EAMV;;EAGA;;;;;;;;;KAUU;;;;;;EAMV,8BAA8B,YAAY;;;;;EAM1C,2BAA2B;;;;;;EAO3B;;;;;;EAOA,qCAAqC;;;;;;EAOrC,+BAA+B,YAAY;;;;;;;;;;;;EAa3C,gCAAgC,YAE9B,YAAY;;;;;;;;;;;;;EAed,iCAAiC;;;;;;;;;;;EAYjC,0BAA0B;IAEtB;IAAsB;;;cAIf,0BAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyCzB,iCAA8B,cAC3B,cAAY,4BACE,YAAY;;;;;;;;;;;;;;;cAqD7B,gCAA8B;;cAG9B;KAKD,6BAA6B;;;;;;;KAmB7B,qBAAqB;;;;;;;;;;;cAYpB,wBAAwB;;;;;;;cAWxB,cAAW,mBACH,YAAU,MACvB,SAAS,WAAW,UACzB,SAAS,WAAW;;;;;;;;;;;;;;;cA8rCV,+BAA4B,cAEvB,cAAY;EACd,gBAAgB;SAAsB,OAAA;EAE1B,cAAc;MAAe"}
1
+ {"version":3,"file":"babel-plugin-intlayer-usage-analyzer.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-usage-analyzer.ts"],"mappings":";;;;;;;;;;;;;YAuCY,qBAAqB;;;;;qBAMpB,wBAAwB;;;;;;;;;;;;;;;;;;;;qBAqBxB,+BAA4B,cAEvB,cAAY;EACd,yBAAyB;SAAoB,OAAA;EAEjC,cAAc;MAAe"}