@intlayer/babel 9.0.0-canary.2 → 9.0.0-canary.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/babel-plugin-intlayer-extract.cjs +3 -2
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +160 -99
- package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-minify.cjs +11 -28
- package/dist/cjs/babel-plugin-intlayer-minify.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs +143 -13
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-purge.cjs +38 -96
- package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs +151 -52
- package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
- package/dist/cjs/babelParser.cjs +62 -0
- package/dist/cjs/babelParser.cjs.map +1 -0
- package/dist/cjs/extractContent/babelProcessor.cjs +144 -71
- package/dist/cjs/extractContent/babelProcessor.cjs.map +1 -1
- package/dist/cjs/extractContent/contentWriter.cjs +10 -14
- package/dist/cjs/extractContent/contentWriter.cjs.map +1 -1
- package/dist/cjs/extractContent/extractContent.cjs +3 -3
- package/dist/cjs/extractContent/extractContent.cjs.map +1 -1
- package/dist/cjs/extractContent/processTsxFile.cjs +4 -7
- package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/constants.cjs +2 -2
- package/dist/cjs/extractContent/utils/constants.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/detectPackageName.cjs +0 -1
- package/dist/cjs/extractContent/utils/detectPackageName.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs +4 -4
- package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs +2 -3
- package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/generateKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/getComponentName.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/getOrGenerateKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs +0 -1
- package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/shouldExtract.cjs +2 -0
- package/dist/cjs/extractContent/utils/shouldExtract.cjs.map +1 -1
- package/dist/cjs/extractScriptBlocks.cjs +0 -1
- package/dist/cjs/extractScriptBlocks.cjs.map +1 -1
- package/dist/cjs/getExtractPluginOptions.cjs +2 -2
- package/dist/cjs/getExtractPluginOptions.cjs.map +1 -1
- package/dist/cjs/getOptimizePluginOptions.cjs +2 -3
- package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
- package/dist/cjs/getPurgePluginOptions.cjs +2 -3
- package/dist/cjs/getPurgePluginOptions.cjs.map +1 -1
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/normalizedFilesList.cjs +30 -0
- package/dist/cjs/normalizedFilesList.cjs.map +1 -0
- package/dist/cjs/transformers.cjs +20 -2
- package/dist/cjs/transformers.cjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs +3 -2
- package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-field-rename.mjs +159 -100
- package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-minify.mjs +12 -29
- package/dist/esm/babel-plugin-intlayer-minify.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +140 -9
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-purge.mjs +40 -97
- package/dist/esm/babel-plugin-intlayer-purge.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs +151 -52
- package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
- package/dist/esm/babelParser.mjs +60 -0
- package/dist/esm/babelParser.mjs.map +1 -0
- package/dist/esm/extractContent/babelProcessor.mjs +144 -71
- package/dist/esm/extractContent/babelProcessor.mjs.map +1 -1
- package/dist/esm/extractContent/contentWriter.mjs +6 -10
- package/dist/esm/extractContent/contentWriter.mjs.map +1 -1
- package/dist/esm/extractContent/extractContent.mjs +1 -1
- package/dist/esm/extractContent/extractContent.mjs.map +1 -1
- package/dist/esm/extractContent/processTsxFile.mjs +3 -6
- package/dist/esm/extractContent/processTsxFile.mjs.map +1 -1
- package/dist/esm/extractContent/utils/constants.mjs +2 -2
- package/dist/esm/extractContent/utils/constants.mjs.map +1 -1
- package/dist/esm/extractContent/utils/detectPackageName.mjs.map +1 -1
- package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs +1 -1
- package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs.map +1 -1
- package/dist/esm/extractContent/utils/extractDictionaryKey.mjs +1 -1
- package/dist/esm/extractContent/utils/extractDictionaryKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/generateKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/getComponentName.mjs.map +1 -1
- package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs.map +1 -1
- package/dist/esm/extractContent/utils/getOrGenerateKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/resolveDictionaryKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/shouldExtract.mjs +2 -0
- package/dist/esm/extractContent/utils/shouldExtract.mjs.map +1 -1
- package/dist/esm/extractScriptBlocks.mjs.map +1 -1
- package/dist/esm/getExtractPluginOptions.mjs +1 -1
- package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
- package/dist/esm/getOptimizePluginOptions.mjs +1 -1
- package/dist/esm/getOptimizePluginOptions.mjs.map +1 -1
- package/dist/esm/getPurgePluginOptions.mjs +1 -1
- package/dist/esm/getPurgePluginOptions.mjs.map +1 -1
- package/dist/esm/index.mjs +3 -3
- package/dist/esm/normalizedFilesList.mjs +29 -0
- package/dist/esm/normalizedFilesList.mjs.map +1 -0
- package/dist/esm/transformers.mjs +20 -2
- package/dist/esm/transformers.mjs.map +1 -1
- package/dist/types/babel-plugin-intlayer-extract.d.ts +2 -3
- package/dist/types/babel-plugin-intlayer-extract.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-field-rename.d.ts +29 -11
- package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-minify.d.ts +2 -3
- package/dist/types/babel-plugin-intlayer-minify.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts +34 -11
- package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-purge.d.ts +2 -3
- package/dist/types/babel-plugin-intlayer-purge.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts +35 -113
- package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
- package/dist/types/babelParser.d.ts +12 -0
- package/dist/types/babelParser.d.ts.map +1 -0
- package/dist/types/extractContent/babelProcessor.d.ts +5 -2
- package/dist/types/extractContent/babelProcessor.d.ts.map +1 -1
- package/dist/types/extractContent/contentWriter.d.ts +0 -1
- package/dist/types/extractContent/contentWriter.d.ts.map +1 -1
- package/dist/types/extractContent/extractContent.d.ts +1 -1
- package/dist/types/extractContent/extractContent.d.ts.map +1 -1
- package/dist/types/extractContent/index.d.ts +1 -1
- package/dist/types/extractContent/processTsxFile.d.ts +1 -1
- package/dist/types/extractContent/processTsxFile.d.ts.map +1 -1
- package/dist/types/extractContent/utils/constants.d.ts +3 -3
- package/dist/types/extractContent/utils/constants.d.ts.map +1 -1
- package/dist/types/extractContent/utils/detectPackageName.d.ts +0 -1
- package/dist/types/extractContent/utils/detectPackageName.d.ts.map +1 -1
- package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts +0 -1
- package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts.map +1 -1
- package/dist/types/extractContent/utils/extractDictionaryKey.d.ts.map +1 -1
- package/dist/types/extractContent/utils/generateKey.d.ts.map +1 -1
- package/dist/types/extractContent/utils/getComponentName.d.ts +0 -1
- package/dist/types/extractContent/utils/getComponentName.d.ts.map +1 -1
- package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts +8 -5
- package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts.map +1 -1
- package/dist/types/extractContent/utils/getOrGenerateKey.d.ts.map +1 -1
- package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts +0 -1
- package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts.map +1 -1
- package/dist/types/extractContent/utils/shouldExtract.d.ts +1 -0
- package/dist/types/extractContent/utils/shouldExtract.d.ts.map +1 -1
- package/dist/types/extractScriptBlocks.d.ts.map +1 -1
- package/dist/types/getExtractPluginOptions.d.ts +0 -1
- package/dist/types/getExtractPluginOptions.d.ts.map +1 -1
- package/dist/types/getOptimizePluginOptions.d.ts +0 -1
- package/dist/types/getOptimizePluginOptions.d.ts.map +1 -1
- package/dist/types/getPurgePluginOptions.d.ts +0 -1
- package/dist/types/getPurgePluginOptions.d.ts.map +1 -1
- package/dist/types/index.d.ts +6 -5
- package/dist/types/normalizedFilesList.d.ts +12 -0
- package/dist/types/normalizedFilesList.d.ts.map +1 -0
- package/dist/types/transformers.d.ts +7 -2
- package/dist/types/transformers.d.ts.map +1 -1
- package/package.json +31 -23
|
@@ -2,12 +2,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
const require_extractContent_utils_detectPackageName = require('./extractContent/utils/detectPackageName.cjs');
|
|
4
4
|
const require_extractContent_extractContent = require('./extractContent/extractContent.cjs');
|
|
5
|
+
const require_normalizedFilesList = require('./normalizedFilesList.cjs');
|
|
6
|
+
let _babel_parser = require("@babel/parser");
|
|
5
7
|
let node_path = require("node:path");
|
|
6
8
|
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
7
9
|
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
8
10
|
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
9
11
|
let _intlayer_config_utils = require("@intlayer/config/utils");
|
|
10
|
-
let _babel_parser = require("@babel/parser");
|
|
11
12
|
|
|
12
13
|
//#region src/babel-plugin-intlayer-extract.ts
|
|
13
14
|
/**
|
|
@@ -35,7 +36,7 @@ const intlayerExtractBabelPlugin = (_babel) => {
|
|
|
35
36
|
if (opts.enabled === false) return;
|
|
36
37
|
const filename = state.file.opts.filename;
|
|
37
38
|
if (!filename) return;
|
|
38
|
-
if (opts.filesList && !opts.filesList
|
|
39
|
+
if (opts.filesList && !require_normalizedFilesList.getNormalizedFilesListSet(opts.filesList).has((0, _intlayer_config_utils.normalizePath)(filename))) return;
|
|
39
40
|
const fileCode = state.file.code ?? "";
|
|
40
41
|
if (!fileCode) return;
|
|
41
42
|
const appLogger = (0, _intlayer_config_logger.getAppLogger)(opts.configuration);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["getNormalizedFilesListSet","detectPackageName","extractContentSync","ANSIColors"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport type { PluginObject, PluginPass } from '@babel/core';\nimport { parse } from '@babel/parser';\nimport type * as BabelTypes from '@babel/types';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport { normalizePath } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport { extractContentSync } from './extractContent/extractContent';\nimport type { PackageName } from './extractContent/utils/constants';\nimport { detectPackageName } from './extractContent/utils/detectPackageName';\nimport { getNormalizedFilesListSet } from './normalizedFilesList';\n\nexport type ExtractResult = {\n dictionaryKey: string;\n filePath: string;\n content: Record<string, string>;\n locale: Locale;\n};\n\nexport type ExtractPluginOptions = {\n packageName?: PackageName;\n filesList: string[];\n enabled: boolean;\n\n shouldExtract?: (text: string) => boolean;\n configuration: IntlayerConfig;\n /**\n * Callback invoked for each extracted dictionary key/content pair.\n * Used by `getExtractPluginOptions` to write dictionaries to disk.\n * May be async — the plugin will fire-and-forget (Babel transforms are sync).\n */\n onExtract?: (result: ExtractResult) => void | Promise<void>;\n /**\n * Defines the output files path.\n */\n output?: FilePathPattern;\n};\n\ntype State = PluginPass & { opts: ExtractPluginOptions };\n\n/**\n * Babel plugin that extracts translatable content from source files and\n * injects Intlayer hooks (`useIntlayer` / `getIntlayer`) automatically.\n *\n * Designed for use with Babel-based build tools such as Next.js and Webpack.\n *\n * @example babel.config.js\n * ```js\n * const { intlayerExtractBabelPlugin, getExtractPluginOptions } = require('@intlayer/babel');\n * module.exports = {\n * presets: ['next/babel'],\n * plugins: [\n * [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const intlayerExtractBabelPlugin = (_babel: {\n types: typeof BabelTypes;\n}): PluginObject<State> => {\n return {\n name: 'babel-plugin-intlayer-extract',\n\n visitor: {\n Program: {\n enter(programPath, state) {\n const opts = state.opts;\n\n // Merge plugin options with the unified compiler config\n const isEnabled = opts.enabled;\n\n if (isEnabled === false) return;\n\n const filename = state.file.opts.filename;\n\n if (!filename) return;\n\n // Compare as POSIX paths (babel filenames use OS separators on Windows).\n if (\n opts.filesList &&\n !getNormalizedFilesListSet(opts.filesList).has(\n normalizePath(filename)\n )\n ) {\n return;\n }\n\n const fileCode: string = state.file.code ?? '';\n if (!fileCode) return;\n\n const appLogger = getAppLogger(opts.configuration);\n const packageName = opts.packageName ?? detectPackageName(filename);\n\n const { saveComponents } = opts.configuration.compiler;\n\n const result = extractContentSync(filename, packageName, {\n configuration: opts.configuration,\n code: fileCode,\n onExtract: (extractResult: {\n key: string;\n content: Record<string, string>;\n }) => {\n if (opts.onExtract) {\n opts.onExtract({\n dictionaryKey: extractResult.key,\n filePath: filename,\n content: extractResult.content,\n locale: opts.configuration.internationalization.defaultLocale,\n });\n }\n },\n declarationOnly: !saveComponents,\n });\n\n if (!result) return;\n\n const { transformedCode: modifiedCode } = result;\n\n if (!modifiedCode) return;\n\n // Replace the Babel AST with the transformed code by re-parsing it.\n // This lets Babel serialise the injected hooks/imports through its\n // own code generator, preserving compatibility with other plugins.\n try {\n const newAst = parse(modifiedCode, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n programPath.node.body = newAst.program.body;\n programPath.node.directives = newAst.program.directives;\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Extracted content from ${colorizePath(relative(opts.configuration.system.baseDir, filename))}`,\n { level: 'debug' }\n );\n } catch (error) {\n appLogger(\n [\n `Failed to parse transformed code for ${colorizePath(relative(opts.configuration.system.baseDir, filename))}:`,\n error,\n ],\n { level: 'error' }\n );\n }\n },\n },\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DA,MAAa,8BAA8B,WAEhB;CACzB,OAAO;EACL,MAAM;EAEN,SAAS,EACP,SAAS,EACP,MAAM,aAAa,OAAO;GACxB,MAAM,OAAO,MAAM;GAKnB,IAFkB,KAAK,YAEL,OAAO;GAEzB,MAAM,WAAW,MAAM,KAAK,KAAK;GAEjC,IAAI,CAAC,UAAU;GAGf,IACE,KAAK,aACL,CAACA,sDAA0B,KAAK,SAAS,CAAC,CAAC,8CAC3B,QAAQ,CACxB,GAEA;GAGF,MAAM,WAAmB,MAAM,KAAK,QAAQ;GAC5C,IAAI,CAAC,UAAU;GAEf,MAAM,sDAAyB,KAAK,aAAa;GACjD,MAAM,cAAc,KAAK,eAAeC,iEAAkB,QAAQ;GAElE,MAAM,EAAE,mBAAmB,KAAK,cAAc;GAE9C,MAAM,SAASC,yDAAmB,UAAU,aAAa;IACvD,eAAe,KAAK;IACpB,MAAM;IACN,YAAY,kBAGN;KACJ,IAAI,KAAK,WACP,KAAK,UAAU;MACb,eAAe,cAAc;MAC7B,UAAU;MACV,SAAS,cAAc;MACvB,QAAQ,KAAK,cAAc,qBAAqB;KAClD,CAAC;IAEL;IACA,iBAAiB,CAAC;GACpB,CAAC;GAED,IAAI,CAAC,QAAQ;GAEb,MAAM,EAAE,iBAAiB,iBAAiB;GAE1C,IAAI,CAAC,cAAc;GAKnB,IAAI;IACF,MAAM,kCAAe,cAAc;KACjC,YAAY;KACZ,SAAS,CAAC,OAAO,YAAY;IAC/B,CAAC;IAED,YAAY,KAAK,OAAO,OAAO,QAAQ;IACvC,YAAY,KAAK,aAAa,OAAO,QAAQ;IAE7C,UACE,yCAAY,aAAaC,wBAAW,SAAS,EAAE,4FAAgD,KAAK,cAAc,OAAO,SAAS,QAAQ,CAAC,KAC3I,EAAE,OAAO,QAAQ,CACnB;GACF,SAAS,OAAO;IACd,UACE,CACE,0GAA8D,KAAK,cAAc,OAAO,SAAS,QAAQ,CAAC,EAAE,IAC5G,KACF,GACA,EAAE,OAAO,QAAQ,CACnB;GACF;EACF,EACF,EACF;CACF;AACF"}
|
|
@@ -7,16 +7,18 @@ const require_babel_plugin_intlayer_usage_analyzer = require('./babel-plugin-int
|
|
|
7
7
|
* targets. These appear inside content-node values (e.g. `{ nodeType:
|
|
8
8
|
* "translation", … }`) and are read by the intlayer runtime.
|
|
9
9
|
*/
|
|
10
|
-
const RESERVED_CONTENT_FIELD_NAMES = new Set(["nodeType"]);
|
|
10
|
+
const RESERVED_CONTENT_FIELD_NAMES = /* @__PURE__ */ new Set(["nodeType"]);
|
|
11
|
+
/** Alphabet used to derive short field aliases (`a`, `b`, …, `aa`, `ab`, …). */
|
|
12
|
+
const SHORT_NAME_ALPHABET = "abcdefghijklmnopqrstuvwxyz";
|
|
11
13
|
/**
|
|
12
14
|
* Converts a zero-based index to a short alphabetic identifier.
|
|
13
15
|
* 0 → 'a', 1 → 'b', …, 25 → 'z', 26 → 'aa', 27 → 'ab', …
|
|
14
16
|
*/
|
|
15
17
|
const generateShortFieldName = (index) => {
|
|
16
|
-
|
|
18
|
+
if (!Number.isInteger(index) || index < 0) throw new RangeError(`generateShortFieldName expects a non-negative integer index, received: ${index}`);
|
|
17
19
|
const remainder = index % 26;
|
|
18
20
|
const quotient = Math.floor(index / 26);
|
|
19
|
-
return quotient === 0 &&
|
|
21
|
+
return quotient === 0 && SHORT_NAME_ALPHABET[remainder] ? SHORT_NAME_ALPHABET[remainder] : generateShortFieldName(quotient - 1) + SHORT_NAME_ALPHABET[remainder];
|
|
20
22
|
};
|
|
21
23
|
/**
|
|
22
24
|
* Recursively builds a `NestedRenameMap` from a compiled dictionary content
|
|
@@ -53,10 +55,6 @@ const buildNestedRenameMapFromContent = (contentValue) => {
|
|
|
53
55
|
const firstLocaleValue = Object.values(record.translation)[0];
|
|
54
56
|
return buildNestedRenameMapFromContent(firstLocaleValue);
|
|
55
57
|
}
|
|
56
|
-
if (record.nodeType === "enumeration" && record.enumeration && typeof record.enumeration === "object" && !Array.isArray(record.enumeration)) {
|
|
57
|
-
const values = Object.values(record.enumeration);
|
|
58
|
-
if (values.length > 0) return buildNestedRenameMapFromContent(values[0]);
|
|
59
|
-
}
|
|
60
58
|
return /* @__PURE__ */ new Map();
|
|
61
59
|
}
|
|
62
60
|
if (record.$$typeof || record.type && record.props && Object.hasOwn(record, "ref")) return /* @__PURE__ */ new Map();
|
|
@@ -74,6 +72,27 @@ const buildNestedRenameMapFromContent = (contentValue) => {
|
|
|
74
72
|
return renameMap;
|
|
75
73
|
};
|
|
76
74
|
/**
|
|
75
|
+
* Walks `fieldPath` through a {@link NestedRenameMap} and returns the entry at
|
|
76
|
+
* the final path segment, or `undefined` when any segment is missing (e.g. the
|
|
77
|
+
* path crosses an array or leaf value whose children are not mapped).
|
|
78
|
+
*
|
|
79
|
+
* Used to locate the rename entry of an opaquely-consumed content value so its
|
|
80
|
+
* children map can be cleared before the JSON rename is applied.
|
|
81
|
+
*
|
|
82
|
+
* @param renameMap - The root rename map to walk.
|
|
83
|
+
* @param fieldPath - Original (pre-rename) field names from the content root.
|
|
84
|
+
*/
|
|
85
|
+
const getNestedRenameEntryAtPath = (renameMap, fieldPath) => {
|
|
86
|
+
let currentRenameMap = renameMap;
|
|
87
|
+
let renameEntry;
|
|
88
|
+
for (const fieldName of fieldPath) {
|
|
89
|
+
renameEntry = currentRenameMap.get(fieldName);
|
|
90
|
+
if (!renameEntry) return void 0;
|
|
91
|
+
currentRenameMap = renameEntry.children;
|
|
92
|
+
}
|
|
93
|
+
return renameEntry;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
77
96
|
* Walks a MemberExpression chain starting from `startPath`, renaming each
|
|
78
97
|
* property found in `currentRenameMap` at the corresponding nesting level.
|
|
79
98
|
*
|
|
@@ -113,6 +132,54 @@ const walkRenameChain = (babelTypes, startPath, currentRenameMap) => {
|
|
|
113
132
|
};
|
|
114
133
|
};
|
|
115
134
|
/**
|
|
135
|
+
* Renames the properties of a destructuring `ObjectPattern` using `renameMap`,
|
|
136
|
+
* recursing into nested patterns and following the references of bound local
|
|
137
|
+
* variables.
|
|
138
|
+
*
|
|
139
|
+
* Handled property shapes:
|
|
140
|
+
*
|
|
141
|
+
* { fieldA } → { shortA: fieldA }
|
|
142
|
+
* { fieldA: localVar } → { shortA: localVar }
|
|
143
|
+
* { fieldA = fallback } → { shortA: fieldA = fallback }
|
|
144
|
+
* { fieldA: { nested } } → { shortA: { shortN: nested } }
|
|
145
|
+
* { ['fieldA']: x } → { ['shortA']: x }
|
|
146
|
+
* { [dynamicKey]: x } → left untouched (dynamic key – not renamable)
|
|
147
|
+
*
|
|
148
|
+
* @param babelTypes - Babel types helper.
|
|
149
|
+
* @param objectPattern - The destructuring pattern to rename.
|
|
150
|
+
* @param scopePath - A path whose scope resolves the pattern's bindings.
|
|
151
|
+
* @param renameMap - Rename table for the current nesting level.
|
|
152
|
+
*/
|
|
153
|
+
const renameObjectPatternProperties = (babelTypes, objectPattern, scopePath, renameMap) => {
|
|
154
|
+
for (const property of objectPattern.properties) {
|
|
155
|
+
if (!babelTypes.isObjectProperty(property)) continue;
|
|
156
|
+
if (property.computed && !babelTypes.isStringLiteral(property.key)) continue;
|
|
157
|
+
const keyName = babelTypes.isIdentifier(property.key) ? property.key.name : babelTypes.isStringLiteral(property.key) ? property.key.value : null;
|
|
158
|
+
if (!keyName) continue;
|
|
159
|
+
const renameEntry = renameMap.get(keyName);
|
|
160
|
+
if (!renameEntry) continue;
|
|
161
|
+
if (property.computed) property.key.value = renameEntry.shortName;
|
|
162
|
+
else {
|
|
163
|
+
if (property.shorthand) property.shorthand = false;
|
|
164
|
+
property.key = babelTypes.identifier(renameEntry.shortName);
|
|
165
|
+
}
|
|
166
|
+
if (renameEntry.children.size === 0) continue;
|
|
167
|
+
const bindingTarget = babelTypes.isAssignmentPattern(property.value) ? property.value.left : property.value;
|
|
168
|
+
if (babelTypes.isObjectPattern(bindingTarget)) {
|
|
169
|
+
renameObjectPatternProperties(babelTypes, bindingTarget, scopePath, renameEntry.children);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (babelTypes.isIdentifier(bindingTarget)) {
|
|
173
|
+
const localVarBinding = scopePath.scope.getBinding(bindingTarget.name);
|
|
174
|
+
if (!localVarBinding) continue;
|
|
175
|
+
for (const nestedRefPath of localVarBinding.referencePaths) {
|
|
176
|
+
const { finalPath, finalRenameMap } = walkRenameChain(babelTypes, nestedRefPath, renameEntry.children);
|
|
177
|
+
walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
116
183
|
* Walks an object-destructuring assignment whose right-hand side is `refPath`,
|
|
117
184
|
* renaming each destructured key that is found in `renameMap`.
|
|
118
185
|
*
|
|
@@ -123,37 +190,41 @@ const walkRenameChain = (babelTypes, startPath, currentRenameMap) => {
|
|
|
123
190
|
* const { modal, validationErrors } = webhooksSection;
|
|
124
191
|
* → const { a: modal, b: validationErrors } = webhooksSection;
|
|
125
192
|
*
|
|
126
|
-
* After renaming each key
|
|
127
|
-
* newly-bound local
|
|
128
|
-
* member-access chains like
|
|
129
|
-
*
|
|
193
|
+
* After renaming each key, {@link renameObjectPatternProperties} recursively
|
|
194
|
+
* walks references to the newly-bound local variables, calling both
|
|
195
|
+
* `walkRenameChain` (for subsequent member-access chains like
|
|
196
|
+
* `validationErrors.invalidUrl`) and this function again (for further levels
|
|
197
|
+
* of secondary destructuring).
|
|
130
198
|
*/
|
|
131
199
|
const walkObjectDestructuring = (babelTypes, refPath, renameMap) => {
|
|
132
200
|
if (renameMap.size === 0) return;
|
|
133
201
|
const parentNode = refPath.parent;
|
|
134
202
|
if (!babelTypes.isVariableDeclarator(parentNode) || !babelTypes.isObjectPattern(parentNode.id) || parentNode.init !== refPath.node) return;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
203
|
+
renameObjectPatternProperties(babelTypes, parentNode.id, refPath, renameMap);
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Collects the local aliases under which `useIntlayer` / `getIntlayer` are
|
|
207
|
+
* imported in the given program (e.g. `import { useIntlayer as useI } …`
|
|
208
|
+
* yields `useI` → `useIntlayer`).
|
|
209
|
+
*
|
|
210
|
+
* Import declarations can only appear at the top level of a module, so the
|
|
211
|
+
* program body is scanned directly instead of traversing the whole AST.
|
|
212
|
+
*/
|
|
213
|
+
const collectIntlayerCallerLocalNames = (babelTypes, programNode) => {
|
|
214
|
+
const intlayerCallerLocalNameMap = /* @__PURE__ */ new Map();
|
|
215
|
+
for (const statement of programNode.body) {
|
|
216
|
+
if (!babelTypes.isImportDeclaration(statement)) continue;
|
|
217
|
+
for (const importSpecifier of statement.specifiers) {
|
|
218
|
+
if (!babelTypes.isImportSpecifier(importSpecifier)) continue;
|
|
219
|
+
const importedName = babelTypes.isIdentifier(importSpecifier.imported) ? importSpecifier.imported.name : importSpecifier.imported.value;
|
|
220
|
+
if (require_babel_plugin_intlayer_usage_analyzer.INTLAYER_CALLER_NAMES.includes(importedName)) intlayerCallerLocalNameMap.set(importSpecifier.local.name, importedName);
|
|
150
221
|
}
|
|
151
222
|
}
|
|
223
|
+
return intlayerCallerLocalNameMap;
|
|
152
224
|
};
|
|
153
225
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* `pruneContext.dictionaryKeyToFieldRenameMap`.
|
|
226
|
+
* Rewrites dictionary content field accesses in the given program to the
|
|
227
|
+
* short aliases defined in `pruneContext.dictionaryKeyToFieldRenameMap`.
|
|
157
228
|
*
|
|
158
229
|
* Handled patterns (mirrors the usage analyser):
|
|
159
230
|
*
|
|
@@ -171,6 +242,63 @@ const walkObjectDestructuring = (babelTypes, refPath, renameMap) => {
|
|
|
171
242
|
* → const { shortA: fieldA } = useIntlayer('key');
|
|
172
243
|
* const { shortN: nested } = fieldA;
|
|
173
244
|
*
|
|
245
|
+
* Exposed as a standalone function so that both
|
|
246
|
+
* {@link makeFieldRenameBabelPlugin} and `intlayerMinifyBabelPlugin` can
|
|
247
|
+
* invoke it from their own `Program.exit` visitors.
|
|
248
|
+
*/
|
|
249
|
+
const renameIntlayerFieldAccesses = (babelTypes, programPath, pruneContext) => {
|
|
250
|
+
if (pruneContext.dictionaryKeyToFieldRenameMap.size === 0) return;
|
|
251
|
+
const intlayerCallerLocalNameMap = collectIntlayerCallerLocalNames(babelTypes, programPath.node);
|
|
252
|
+
if (intlayerCallerLocalNameMap.size === 0) return;
|
|
253
|
+
programPath.traverse({ CallExpression: (callExpressionPath) => {
|
|
254
|
+
const calleeNode = callExpressionPath.node.callee;
|
|
255
|
+
let localCallerName;
|
|
256
|
+
if (babelTypes.isIdentifier(calleeNode)) localCallerName = calleeNode.name;
|
|
257
|
+
else if (babelTypes.isMemberExpression(calleeNode) && babelTypes.isIdentifier(calleeNode.property)) localCallerName = calleeNode.property.name;
|
|
258
|
+
if (!localCallerName || !intlayerCallerLocalNameMap.has(localCallerName)) return;
|
|
259
|
+
const callArguments = callExpressionPath.node.arguments;
|
|
260
|
+
if (callArguments.length === 0) return;
|
|
261
|
+
const firstArgument = callArguments[0];
|
|
262
|
+
let dictionaryKey;
|
|
263
|
+
if (babelTypes.isStringLiteral(firstArgument)) dictionaryKey = firstArgument.value;
|
|
264
|
+
else if (babelTypes.isTemplateLiteral(firstArgument) && firstArgument.expressions.length === 0 && firstArgument.quasis.length === 1 && firstArgument.quasis[0]) dictionaryKey = firstArgument.quasis[0].value.cooked ?? firstArgument.quasis[0].value.raw;
|
|
265
|
+
if (!dictionaryKey) return;
|
|
266
|
+
if (pruneContext.dictionariesWithEdgeCases.has(dictionaryKey)) return;
|
|
267
|
+
const fieldRenameMap = pruneContext.dictionaryKeyToFieldRenameMap.get(dictionaryKey);
|
|
268
|
+
if (!fieldRenameMap || fieldRenameMap.size === 0) return;
|
|
269
|
+
const parentNode = callExpressionPath.parent;
|
|
270
|
+
if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isObjectPattern(parentNode.id)) {
|
|
271
|
+
walkObjectDestructuring(babelTypes, callExpressionPath, fieldRenameMap);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if ((babelTypes.isMemberExpression(parentNode) || babelTypes.isOptionalMemberExpression(parentNode)) && parentNode.object === callExpressionPath.node) {
|
|
275
|
+
const { finalPath, finalRenameMap } = walkRenameChain(babelTypes, callExpressionPath, fieldRenameMap);
|
|
276
|
+
walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isIdentifier(parentNode.id)) {
|
|
280
|
+
const variableBinding = callExpressionPath.scope.getBinding(parentNode.id.name);
|
|
281
|
+
if (!variableBinding) return;
|
|
282
|
+
for (const variableReferencePath of variableBinding.referencePaths) {
|
|
283
|
+
const { finalPath, finalRenameMap } = walkRenameChain(babelTypes, variableReferencePath, fieldRenameMap);
|
|
284
|
+
walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);
|
|
285
|
+
const refParent = variableReferencePath.parent;
|
|
286
|
+
if ((babelTypes.isCallExpression(refParent) || babelTypes.isOptionalCallExpression(refParent)) && refParent.callee === variableReferencePath.node) {
|
|
287
|
+
const callPath = variableReferencePath.parentPath;
|
|
288
|
+
if (callPath) {
|
|
289
|
+
const { finalPath: signalFinalPath, finalRenameMap: signalFinalRenameMap } = walkRenameChain(babelTypes, callPath, fieldRenameMap);
|
|
290
|
+
walkObjectDestructuring(babelTypes, signalFinalPath, signalFinalRenameMap);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
} });
|
|
296
|
+
};
|
|
297
|
+
/**
|
|
298
|
+
* Creates a Babel plugin that rewrites dictionary content field accesses in
|
|
299
|
+
* source files to their short aliases via
|
|
300
|
+
* {@link renameIntlayerFieldAccesses}.
|
|
301
|
+
*
|
|
174
302
|
* This plugin must run in a separate `transformAsync` pass **before**
|
|
175
303
|
* `intlayerOptimizeBabelPlugin`, because the latter replaces `useIntlayer`
|
|
176
304
|
* with `useDictionary`, erasing the dictionary-key information needed here.
|
|
@@ -178,81 +306,14 @@ const walkObjectDestructuring = (babelTypes, refPath, renameMap) => {
|
|
|
178
306
|
const makeFieldRenameBabelPlugin = (pruneContext) => ({ types: babelTypes }) => ({
|
|
179
307
|
name: "intlayer-field-rename",
|
|
180
308
|
visitor: { Program: { exit: (programPath) => {
|
|
181
|
-
|
|
182
|
-
const intlayerCallerLocalNameMap = /* @__PURE__ */ new Map();
|
|
183
|
-
programPath.traverse({ ImportDeclaration: (importDeclarationPath) => {
|
|
184
|
-
for (const importSpecifier of importDeclarationPath.node.specifiers) {
|
|
185
|
-
if (!babelTypes.isImportSpecifier(importSpecifier)) continue;
|
|
186
|
-
const importedName = babelTypes.isIdentifier(importSpecifier.imported) ? importSpecifier.imported.name : importSpecifier.imported.value;
|
|
187
|
-
if (require_babel_plugin_intlayer_usage_analyzer.INTLAYER_CALLER_NAMES.includes(importedName)) intlayerCallerLocalNameMap.set(importSpecifier.local.name, importedName);
|
|
188
|
-
}
|
|
189
|
-
} });
|
|
190
|
-
if (intlayerCallerLocalNameMap.size === 0) return;
|
|
191
|
-
programPath.traverse({ CallExpression: (callExpressionPath) => {
|
|
192
|
-
const calleeNode = callExpressionPath.node.callee;
|
|
193
|
-
let localCallerName;
|
|
194
|
-
if (babelTypes.isIdentifier(calleeNode)) localCallerName = calleeNode.name;
|
|
195
|
-
else if (babelTypes.isMemberExpression(calleeNode) && babelTypes.isIdentifier(calleeNode.property)) localCallerName = calleeNode.property.name;
|
|
196
|
-
if (!localCallerName || !intlayerCallerLocalNameMap.has(localCallerName)) return;
|
|
197
|
-
const callArguments = callExpressionPath.node.arguments;
|
|
198
|
-
if (callArguments.length === 0) return;
|
|
199
|
-
const firstArgument = callArguments[0];
|
|
200
|
-
let dictionaryKey;
|
|
201
|
-
if (babelTypes.isStringLiteral(firstArgument)) dictionaryKey = firstArgument.value;
|
|
202
|
-
else if (babelTypes.isTemplateLiteral(firstArgument) && firstArgument.expressions.length === 0 && firstArgument.quasis.length === 1 && firstArgument.quasis[0]) dictionaryKey = firstArgument.quasis[0].value.cooked ?? firstArgument.quasis[0].value.raw;
|
|
203
|
-
if (!dictionaryKey) return;
|
|
204
|
-
const fieldRenameMap = pruneContext.dictionaryKeyToFieldRenameMap.get(dictionaryKey);
|
|
205
|
-
if (!fieldRenameMap || fieldRenameMap.size === 0) return;
|
|
206
|
-
const parentNode = callExpressionPath.parent;
|
|
207
|
-
if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isObjectPattern(parentNode.id)) {
|
|
208
|
-
for (const property of parentNode.id.properties) {
|
|
209
|
-
if (!babelTypes.isObjectProperty(property)) continue;
|
|
210
|
-
const keyName = babelTypes.isIdentifier(property.key) ? property.key.name : babelTypes.isStringLiteral(property.key) ? property.key.value : null;
|
|
211
|
-
if (!keyName) continue;
|
|
212
|
-
const renameEntry = fieldRenameMap.get(keyName);
|
|
213
|
-
if (!renameEntry) continue;
|
|
214
|
-
if (property.shorthand) {
|
|
215
|
-
property.shorthand = false;
|
|
216
|
-
property.key = babelTypes.identifier(renameEntry.shortName);
|
|
217
|
-
} else property.key = babelTypes.identifier(renameEntry.shortName);
|
|
218
|
-
if (renameEntry.children.size > 0 && babelTypes.isIdentifier(property.value)) {
|
|
219
|
-
const localVarBinding = callExpressionPath.scope.getBinding(property.value.name);
|
|
220
|
-
if (localVarBinding) for (const refPath of localVarBinding.referencePaths) {
|
|
221
|
-
const { finalPath, finalRenameMap } = walkRenameChain(babelTypes, refPath, renameEntry.children);
|
|
222
|
-
walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
if ((babelTypes.isMemberExpression(parentNode) || babelTypes.isOptionalMemberExpression(parentNode)) && parentNode.object === callExpressionPath.node) {
|
|
229
|
-
const { finalPath, finalRenameMap } = walkRenameChain(babelTypes, callExpressionPath, fieldRenameMap);
|
|
230
|
-
walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (babelTypes.isVariableDeclarator(parentNode) && babelTypes.isIdentifier(parentNode.id)) {
|
|
234
|
-
const variableName = parentNode.id.name;
|
|
235
|
-
const variableBinding = callExpressionPath.scope.getBinding(variableName);
|
|
236
|
-
if (!variableBinding) return;
|
|
237
|
-
for (const variableReferencePath of variableBinding.referencePaths) {
|
|
238
|
-
const { finalPath, finalRenameMap } = walkRenameChain(babelTypes, variableReferencePath, fieldRenameMap);
|
|
239
|
-
walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);
|
|
240
|
-
const refParent = variableReferencePath.parent;
|
|
241
|
-
if ((babelTypes.isCallExpression(refParent) || babelTypes.isOptionalCallExpression(refParent)) && refParent.callee === variableReferencePath.node) {
|
|
242
|
-
const callPath = variableReferencePath.parentPath;
|
|
243
|
-
if (callPath) {
|
|
244
|
-
const { finalPath: signalFinalPath, finalRenameMap: signalFinalRenameMap } = walkRenameChain(babelTypes, callPath, fieldRenameMap);
|
|
245
|
-
walkObjectDestructuring(babelTypes, signalFinalPath, signalFinalRenameMap);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
} });
|
|
309
|
+
renameIntlayerFieldAccesses(babelTypes, programPath, pruneContext);
|
|
251
310
|
} } }
|
|
252
311
|
});
|
|
253
312
|
|
|
254
313
|
//#endregion
|
|
255
314
|
exports.buildNestedRenameMapFromContent = buildNestedRenameMapFromContent;
|
|
256
315
|
exports.generateShortFieldName = generateShortFieldName;
|
|
316
|
+
exports.getNestedRenameEntryAtPath = getNestedRenameEntryAtPath;
|
|
257
317
|
exports.makeFieldRenameBabelPlugin = makeFieldRenameBabelPlugin;
|
|
318
|
+
exports.renameIntlayerFieldAccesses = renameIntlayerFieldAccesses;
|
|
258
319
|
//# sourceMappingURL=babel-plugin-intlayer-field-rename.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-field-rename.cjs","names":["INTLAYER_CALLER_NAMES"],"sources":["../../src/babel-plugin-intlayer-field-rename.ts"],"sourcesContent":["import type { NodePath, PluginObj } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n INTLAYER_CALLER_NAMES,\n type IntlayerCallerName,\n type NestedRenameMap,\n type PruneContext,\n} from './babel-plugin-intlayer-usage-analyzer';\n\n// ── Field-name helpers ────────────────────────────────────────────────────────\n\n/**\n * Intlayer internal property names that must never be used as short-name\n * targets. These appear inside content-node values (e.g. `{ nodeType:\n * \"translation\", … }`) and are read by the intlayer runtime.\n */\nconst RESERVED_CONTENT_FIELD_NAMES = new Set(['nodeType']);\n\n/**\n * Converts a zero-based index to a short alphabetic identifier.\n * 0 → 'a', 1 → 'b', …, 25 → 'z', 26 → 'aa', 27 → 'ab', …\n */\nexport const generateShortFieldName = (index: number): string => {\n const ALPHABET = 'abcdefghijklmnopqrstuvwxyz';\n const remainder = index % ALPHABET.length;\n const quotient = Math.floor(index / ALPHABET.length);\n\n return quotient === 0 && ALPHABET[remainder]\n ? ALPHABET[remainder]\n : generateShortFieldName(quotient - 1) + ALPHABET[remainder];\n};\n\n/**\n * Recursively builds a `NestedRenameMap` from a compiled dictionary content\n * value by traversing the intlayer node structure.\n *\n * Rules:\n * - If the value has `nodeType: 'translation'`, user-defined fields live\n * inside `translation[locale]`. Recurse into the first locale's value.\n * - All other intlayer runtime nodes (enumeration, condition, gender, …) are\n * treated as leaves — their internal keys must never be renamed.\n * - Arrays produce an empty children map. Array elements are not traversed\n * because consumers may access them via `.map()` / `.filter()` callbacks,\n * which the source-code rename walk cannot enter. Renaming element fields\n * in the JSON without the matching source-code rename would produce\n * mismatched key names and runtime crashes.\n * The `[0]` pass-through in `walkRenameChain` is preserved so that direct\n * indexed access (`field[0].sub`) silently terminates at the empty children\n * map without breaking anything.\n * - Plain objects are user-defined records: ALL non-reserved keys are renamed\n * with short alphabetic aliases (a, b, c, …) and each value is recursed into.\n * - Primitives produce an empty map (no further renaming).\n *\n * The rename map is built from ALL user-defined fields (not just consumed ones).\n * Both the JSON rename and the source-code rename use the same map, so the\n * short names are always consistent regardless of which fields are pruned.\n *\n * @param contentValue - The dictionary content value to analyse.\n */\nexport const buildNestedRenameMapFromContent = (\n contentValue: unknown\n): NestedRenameMap => {\n if (\n !contentValue ||\n typeof contentValue !== 'object' ||\n Array.isArray(contentValue)\n ) {\n return new Map();\n }\n\n const record = contentValue as Record<string, unknown>;\n\n // Any object with `nodeType: string` is an intlayer runtime node.\n if (typeof record.nodeType === 'string') {\n // Translation node: user-defined fields live inside translation[locale].\n if (\n record.nodeType === 'translation' &&\n record.translation &&\n typeof record.translation === 'object' &&\n !Array.isArray(record.translation)\n ) {\n const firstLocaleValue = Object.values(\n record.translation as Record<string, unknown>\n )[0];\n return buildNestedRenameMapFromContent(firstLocaleValue);\n }\n\n // Enumeration node: user-defined keys live inside enumeration.\n if (\n record.nodeType === 'enumeration' &&\n record.enumeration &&\n typeof record.enumeration === 'object' &&\n !Array.isArray(record.enumeration)\n ) {\n const values = Object.values(\n record.enumeration as Record<string, unknown>\n );\n if (values.length > 0) {\n return buildNestedRenameMapFromContent(values[0]);\n }\n }\n\n // All other intlayer nodes (pluralization, conditions, etc.) resolve to a\n // single value at runtime – return an empty map so they are treated\n // as leaves unless they contain nested user records.\n return new Map();\n }\n\n // Exclude React elements from being treated as user-defined records.\n // JSX elements in the compiled JSON have a $$typeof property (usually Symbol(react.element)).\n if (\n record.$$typeof ||\n (record.type && record.props && Object.hasOwn(record, 'ref'))\n ) {\n return new Map();\n }\n\n // User-defined record: rename ALL non-reserved keys with stable alphabetic\n // aliases sorted alphabetically so the mapping is deterministic.\n const sortedKeys = Object.keys(record)\n .filter((key) => !RESERVED_CONTENT_FIELD_NAMES.has(key))\n .sort();\n\n const renameMap: NestedRenameMap = new Map();\n\n for (let i = 0; i < sortedKeys.length; i++) {\n const key = sortedKeys[i];\n\n if (!key) continue;\n\n const children = buildNestedRenameMapFromContent(record[key]);\n\n renameMap.set(key, { shortName: generateShortFieldName(i), children });\n }\n\n return renameMap;\n};\n\n// ── Field-rename Babel plugin ─────────────────────────────────────────────────\n\n/**\n * Walks a MemberExpression chain starting from `startPath`, renaming each\n * property found in `currentRenameMap` at the corresponding nesting level.\n *\n * Numeric computed accesses (array indices such as `[0]`, `[1]`) are treated\n * as transparent pass-throughs: the rename map is kept unchanged and the walk\n * continues past the index. This means `content.field[0].sub` is handled\n * correctly — `field` and `sub` are both renamed while `[0]` is left intact.\n */\nconst walkRenameChain = (\n babelTypes: typeof BabelTypes,\n startPath: NodePath<BabelTypes.Node>,\n currentRenameMap: NestedRenameMap\n): {\n finalPath: NodePath<BabelTypes.Node>;\n finalRenameMap: NestedRenameMap;\n} => {\n let refPath: NodePath<BabelTypes.Node> = startPath;\n let renameMap = currentRenameMap;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const parentPath = refPath.parentPath;\n if (!parentPath) break;\n\n const parentNode = parentPath.node;\n\n if (\n (!babelTypes.isMemberExpression(parentNode) &&\n !babelTypes.isOptionalMemberExpression(parentNode)) ||\n (parentNode as BabelTypes.MemberExpression).object !== refPath.node\n ) {\n break;\n }\n\n const memberNode = parentNode as BabelTypes.MemberExpression;\n\n // Numeric index access ([0], [1], …): advance past the array accessor\n // without touching the rename map. The next iteration will attempt to\n // rename the property that follows the index.\n if (\n memberNode.computed &&\n babelTypes.isNumericLiteral(memberNode.property)\n ) {\n refPath = parentPath;\n continue;\n }\n\n // Nothing left to rename at this level — stop.\n if (renameMap.size === 0) break;\n\n let fieldName: string | undefined;\n\n if (!memberNode.computed && babelTypes.isIdentifier(memberNode.property)) {\n fieldName = memberNode.property.name;\n } else if (\n memberNode.computed &&\n babelTypes.isStringLiteral(memberNode.property)\n ) {\n fieldName = memberNode.property.value;\n } else {\n break; // dynamic computed key – stop\n }\n\n const renameEntry = renameMap.get(fieldName);\n if (!renameEntry) break; // not in map – stop\n\n // Apply the rename\n if (!memberNode.computed && babelTypes.isIdentifier(memberNode.property)) {\n memberNode.property.name = renameEntry.shortName;\n } else if (\n memberNode.computed &&\n babelTypes.isStringLiteral(memberNode.property)\n ) {\n memberNode.property.value = renameEntry.shortName;\n }\n\n refPath = parentPath;\n renameMap = renameEntry.children;\n }\n\n return { finalPath: refPath, finalRenameMap: renameMap };\n};\n\n/**\n * Walks an object-destructuring assignment whose right-hand side is `refPath`,\n * renaming each destructured key that is found in `renameMap`.\n *\n * Handles the \"secondary destructuring\" pattern that `walkRenameChain` cannot\n * reach because the reference is not a MemberExpression:\n *\n * const { webhooksSection } = useIntlayer('build-settings');\n * const { modal, validationErrors } = webhooksSection;\n * → const { a: modal, b: validationErrors } = webhooksSection;\n *\n * After renaming each key the function recursively walks references to the\n * newly-bound local variable, calling both `walkRenameChain` (for subsequent\n * member-access chains like `validationErrors.invalidUrl`) and itself (for\n * further levels of secondary destructuring).\n */\nconst walkObjectDestructuring = (\n babelTypes: typeof BabelTypes,\n refPath: NodePath<BabelTypes.Node>,\n renameMap: NestedRenameMap\n): void => {\n if (renameMap.size === 0) return;\n\n const parentNode = refPath.parent;\n\n // Only handle: const { a, b } = refVar\n if (\n !babelTypes.isVariableDeclarator(parentNode) ||\n !babelTypes.isObjectPattern(parentNode.id) ||\n parentNode.init !== refPath.node\n ) {\n return;\n }\n\n for (const property of (parentNode.id as BabelTypes.ObjectPattern)\n .properties) {\n if (!babelTypes.isObjectProperty(property)) continue;\n\n const keyName = babelTypes.isIdentifier(property.key)\n ? property.key.name\n : babelTypes.isStringLiteral(property.key)\n ? property.key.value\n : null;\n if (!keyName) continue;\n\n const renameEntry = renameMap.get(keyName);\n if (!renameEntry) continue;\n\n // { fieldA } → { shortA: fieldA }\n // { fieldA: localVar } → { shortA: localVar }\n if (property.shorthand) {\n property.shorthand = false;\n }\n property.key = babelTypes.identifier(renameEntry.shortName);\n\n // Recursively walk references to the local variable bound by this key.\n if (\n renameEntry.children.size > 0 &&\n babelTypes.isIdentifier(property.value)\n ) {\n const localVarName = (property.value as BabelTypes.Identifier).name;\n const localVarBinding = refPath.scope.getBinding(localVarName);\n if (localVarBinding) {\n for (const nestedRefPath of localVarBinding.referencePaths) {\n const { finalPath, finalRenameMap } = walkRenameChain(\n babelTypes,\n nestedRefPath,\n renameEntry.children\n );\n walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);\n }\n }\n }\n }\n};\n\n/**\n * Creates a Babel plugin that rewrites dictionary content field accesses in\n * source files to their short aliases defined in\n * `pruneContext.dictionaryKeyToFieldRenameMap`.\n *\n * Handled patterns (mirrors the usage analyser):\n *\n * const { fieldA, fieldB } = useIntlayer('key')\n * → const { shortA: fieldA, shortB: fieldB } = useIntlayer('key')\n *\n * useIntlayer('key').fieldA\n * → useIntlayer('key').shortA\n *\n * const result = useIntlayer('key'); result.fieldA\n * → const result = useIntlayer('key'); result.shortA\n *\n * const { fieldA } = useIntlayer('key');\n * const { nested } = fieldA; // secondary destructuring\n * → const { shortA: fieldA } = useIntlayer('key');\n * const { shortN: nested } = fieldA;\n *\n * This plugin must run in a separate `transformAsync` pass **before**\n * `intlayerOptimizeBabelPlugin`, because the latter replaces `useIntlayer`\n * with `useDictionary`, erasing the dictionary-key information needed here.\n */\nexport const makeFieldRenameBabelPlugin =\n (pruneContext: PruneContext) =>\n ({ types: babelTypes }: { types: typeof BabelTypes }): PluginObj => ({\n name: 'intlayer-field-rename',\n visitor: {\n Program: {\n exit: (programPath) => {\n if (pruneContext.dictionaryKeyToFieldRenameMap.size === 0) return;\n\n // Collect local aliases for useIntlayer / getIntlayer\n const intlayerCallerLocalNameMap = new Map<string, string>();\n\n programPath.traverse({\n ImportDeclaration: (importDeclarationPath) => {\n for (const importSpecifier of importDeclarationPath.node\n .specifiers) {\n if (!babelTypes.isImportSpecifier(importSpecifier)) continue;\n\n const importedName = babelTypes.isIdentifier(\n importSpecifier.imported\n )\n ? importSpecifier.imported.name\n : (importSpecifier.imported as BabelTypes.StringLiteral)\n .value;\n\n if (\n INTLAYER_CALLER_NAMES.includes(\n importedName as IntlayerCallerName\n )\n ) {\n intlayerCallerLocalNameMap.set(\n importSpecifier.local.name,\n importedName\n );\n }\n }\n },\n });\n\n if (intlayerCallerLocalNameMap.size === 0) return;\n\n // Visit all useIntlayer / getIntlayer call-sites and rename field accesses\n programPath.traverse({\n CallExpression: (callExpressionPath) => {\n const calleeNode = callExpressionPath.node.callee;\n let localCallerName: string | undefined;\n\n if (babelTypes.isIdentifier(calleeNode)) {\n localCallerName = calleeNode.name;\n } else if (\n babelTypes.isMemberExpression(calleeNode) &&\n babelTypes.isIdentifier(calleeNode.property)\n ) {\n localCallerName = calleeNode.property.name;\n }\n\n if (\n !localCallerName ||\n !intlayerCallerLocalNameMap.has(localCallerName)\n )\n return;\n\n const callArguments = callExpressionPath.node.arguments;\n if (callArguments.length === 0) return;\n\n const firstArgument = callArguments[0];\n let dictionaryKey: string | undefined;\n\n if (babelTypes.isStringLiteral(firstArgument)) {\n dictionaryKey = firstArgument.value;\n } else if (\n babelTypes.isTemplateLiteral(firstArgument) &&\n firstArgument.expressions.length === 0 &&\n firstArgument.quasis.length === 1 &&\n firstArgument.quasis[0]\n ) {\n dictionaryKey =\n firstArgument.quasis[0].value.cooked ??\n firstArgument.quasis[0].value.raw;\n }\n\n if (!dictionaryKey) return;\n\n const fieldRenameMap =\n pruneContext.dictionaryKeyToFieldRenameMap.get(dictionaryKey);\n if (!fieldRenameMap || fieldRenameMap.size === 0) return;\n\n const parentNode = callExpressionPath.parent;\n\n // ── Case 1: const { fieldA, fieldB } = useIntlayer('key') ────────\n if (\n babelTypes.isVariableDeclarator(parentNode) &&\n babelTypes.isObjectPattern(parentNode.id)\n ) {\n for (const property of parentNode.id.properties) {\n if (!babelTypes.isObjectProperty(property)) continue;\n\n const keyName = babelTypes.isIdentifier(property.key)\n ? property.key.name\n : babelTypes.isStringLiteral(property.key)\n ? property.key.value\n : null;\n if (!keyName) continue;\n\n const renameEntry = fieldRenameMap.get(keyName);\n if (!renameEntry) continue;\n\n // { fieldA } → { shortA: fieldA }\n // { fieldA: localVar } → { shortA: localVar }\n if (property.shorthand) {\n property.shorthand = false;\n property.key = babelTypes.identifier(renameEntry.shortName);\n } else {\n property.key = babelTypes.identifier(renameEntry.shortName);\n }\n\n // Walk nested member accesses and secondary destructurings\n // on the local variable.\n if (\n renameEntry.children.size > 0 &&\n babelTypes.isIdentifier(property.value)\n ) {\n const localVarBinding = callExpressionPath.scope.getBinding(\n (property.value as BabelTypes.Identifier).name\n );\n if (localVarBinding) {\n for (const refPath of localVarBinding.referencePaths) {\n const { finalPath, finalRenameMap } = walkRenameChain(\n babelTypes,\n refPath,\n renameEntry.children\n );\n walkObjectDestructuring(\n babelTypes,\n finalPath,\n finalRenameMap\n );\n }\n }\n }\n }\n return;\n }\n\n // ── Case 2: useIntlayer('key').fieldA.nested ─────────────────────\n if (\n (babelTypes.isMemberExpression(parentNode) ||\n babelTypes.isOptionalMemberExpression(parentNode)) &&\n (parentNode as BabelTypes.MemberExpression).object ===\n callExpressionPath.node\n ) {\n const { finalPath, finalRenameMap } = walkRenameChain(\n babelTypes,\n callExpressionPath,\n fieldRenameMap\n );\n walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);\n return;\n }\n\n // ── Case 3: const result = useIntlayer('key'); result.fieldA ─────\n if (\n babelTypes.isVariableDeclarator(parentNode) &&\n babelTypes.isIdentifier(parentNode.id)\n ) {\n const variableName = parentNode.id.name;\n const variableBinding =\n callExpressionPath.scope.getBinding(variableName);\n if (!variableBinding) return;\n\n for (const variableReferencePath of variableBinding.referencePaths) {\n // Direct access: result.fieldA or const { fieldA } = result\n const { finalPath, finalRenameMap } = walkRenameChain(\n babelTypes,\n variableReferencePath,\n fieldRenameMap\n );\n walkObjectDestructuring(\n babelTypes,\n finalPath,\n finalRenameMap\n );\n\n // Signal accessor: result().fieldA or const { fieldA } = result()\n // walkRenameChain stops at a CallExpression parent, so we need to\n // start a new walk from the call-expression node itself.\n const refParent = variableReferencePath.parent;\n if (\n (babelTypes.isCallExpression(refParent) ||\n babelTypes.isOptionalCallExpression(refParent)) &&\n (refParent as BabelTypes.CallExpression).callee ===\n variableReferencePath.node\n ) {\n const callPath = variableReferencePath.parentPath;\n if (callPath) {\n const {\n finalPath: signalFinalPath,\n finalRenameMap: signalFinalRenameMap,\n } = walkRenameChain(babelTypes, callPath, fieldRenameMap);\n walkObjectDestructuring(\n babelTypes,\n signalFinalPath,\n signalFinalRenameMap\n );\n }\n }\n }\n }\n },\n });\n },\n },\n },\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-field-rename.cjs","names":["INTLAYER_CALLER_NAMES"],"sources":["../../src/babel-plugin-intlayer-field-rename.ts"],"sourcesContent":["import type { NodePath, PluginObject } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n INTLAYER_CALLER_NAMES,\n type IntlayerCallerName,\n type NestedRenameEntry,\n type NestedRenameMap,\n type PruneContext,\n} from './babel-plugin-intlayer-usage-analyzer';\n\n// ── Field-name helpers ────────────────────────────────────────────────────────\n\n/**\n * Intlayer internal property names that must never be used as short-name\n * targets. These appear inside content-node values (e.g. `{ nodeType:\n * \"translation\", … }`) and are read by the intlayer runtime.\n */\nconst RESERVED_CONTENT_FIELD_NAMES = new Set(['nodeType']);\n\n/** Alphabet used to derive short field aliases (`a`, `b`, …, `aa`, `ab`, …). */\nconst SHORT_NAME_ALPHABET = 'abcdefghijklmnopqrstuvwxyz';\n\n/**\n * Converts a zero-based index to a short alphabetic identifier.\n * 0 → 'a', 1 → 'b', …, 25 → 'z', 26 → 'aa', 27 → 'ab', …\n */\nexport const generateShortFieldName = (index: number): string => {\n if (!Number.isInteger(index) || index < 0) {\n throw new RangeError(\n `generateShortFieldName expects a non-negative integer index, received: ${index}`\n );\n }\n\n const remainder = index % SHORT_NAME_ALPHABET.length;\n const quotient = Math.floor(index / SHORT_NAME_ALPHABET.length);\n\n return quotient === 0 && SHORT_NAME_ALPHABET[remainder]\n ? SHORT_NAME_ALPHABET[remainder]\n : generateShortFieldName(quotient - 1) + SHORT_NAME_ALPHABET[remainder];\n};\n\n/**\n * Recursively builds a `NestedRenameMap` from a compiled dictionary content\n * value by traversing the intlayer node structure.\n *\n * Rules:\n * - If the value has `nodeType: 'translation'`, user-defined fields live\n * inside `translation[locale]`. Recurse into the first locale's value.\n * - All other intlayer runtime nodes (enumeration, condition, gender, …) are\n * treated as leaves — their internal keys must never be renamed.\n * - Arrays produce an empty children map. Array elements are not traversed\n * because consumers may access them via `.map()` / `.filter()` callbacks,\n * which the source-code rename walk cannot enter. Renaming element fields\n * in the JSON without the matching source-code rename would produce\n * mismatched key names and runtime crashes.\n * The `[0]` pass-through in `walkRenameChain` is preserved so that direct\n * indexed access (`field[0].sub`) silently terminates at the empty children\n * map without breaking anything.\n * - Plain objects are user-defined records: ALL non-reserved keys are renamed\n * with short alphabetic aliases (a, b, c, …) and each value is recursed into.\n * - Primitives produce an empty map (no further renaming).\n *\n * The rename map is built from ALL user-defined fields (not just consumed ones).\n * Both the JSON rename and the source-code rename use the same map, so the\n * short names are always consistent regardless of which fields are pruned.\n *\n * @param contentValue - The dictionary content value to analyse.\n */\nexport const buildNestedRenameMapFromContent = (\n contentValue: unknown\n): NestedRenameMap => {\n if (\n !contentValue ||\n typeof contentValue !== 'object' ||\n Array.isArray(contentValue)\n ) {\n return new Map();\n }\n\n const record = contentValue as Record<string, unknown>;\n\n // Any object with `nodeType: string` is an intlayer runtime node.\n if (typeof record.nodeType === 'string') {\n // Translation node: user-defined fields live inside translation[locale].\n if (\n record.nodeType === 'translation' &&\n record.translation &&\n typeof record.translation === 'object' &&\n !Array.isArray(record.translation)\n ) {\n const firstLocaleValue = Object.values(\n record.translation as Record<string, unknown>\n )[0];\n return buildNestedRenameMapFromContent(firstLocaleValue);\n }\n\n // All other intlayer nodes (enumeration, pluralization, conditions, …)\n // resolve to a single value at runtime through a call the source-code\n // rename walk cannot traverse (e.g. `content.myEnum(count)`), and the\n // JSON renamers only descend into translation nodes. Treat them as\n // leaves so the source and JSON sides always stay consistent.\n return new Map();\n }\n\n // Exclude React elements from being treated as user-defined records.\n // JSX elements in the compiled JSON have a $$typeof property (usually Symbol(react.element)).\n if (\n record.$$typeof ||\n (record.type && record.props && Object.hasOwn(record, 'ref'))\n ) {\n return new Map();\n }\n\n // User-defined record: rename ALL non-reserved keys with stable alphabetic\n // aliases sorted alphabetically so the mapping is deterministic.\n const sortedKeys = Object.keys(record)\n .filter((key) => !RESERVED_CONTENT_FIELD_NAMES.has(key))\n .sort();\n\n const renameMap: NestedRenameMap = new Map();\n\n for (let i = 0; i < sortedKeys.length; i++) {\n const key = sortedKeys[i];\n\n if (!key) continue;\n\n const children = buildNestedRenameMapFromContent(record[key]);\n\n renameMap.set(key, { shortName: generateShortFieldName(i), children });\n }\n\n return renameMap;\n};\n\n/**\n * Walks `fieldPath` through a {@link NestedRenameMap} and returns the entry at\n * the final path segment, or `undefined` when any segment is missing (e.g. the\n * path crosses an array or leaf value whose children are not mapped).\n *\n * Used to locate the rename entry of an opaquely-consumed content value so its\n * children map can be cleared before the JSON rename is applied.\n *\n * @param renameMap - The root rename map to walk.\n * @param fieldPath - Original (pre-rename) field names from the content root.\n */\nexport const getNestedRenameEntryAtPath = (\n renameMap: NestedRenameMap,\n fieldPath: readonly string[]\n): NestedRenameEntry | undefined => {\n let currentRenameMap = renameMap;\n let renameEntry: NestedRenameEntry | undefined;\n\n for (const fieldName of fieldPath) {\n renameEntry = currentRenameMap.get(fieldName);\n if (!renameEntry) return undefined;\n currentRenameMap = renameEntry.children;\n }\n\n return renameEntry;\n};\n\n// ── Field-rename Babel plugin ─────────────────────────────────────────────────\n\n/**\n * Walks a MemberExpression chain starting from `startPath`, renaming each\n * property found in `currentRenameMap` at the corresponding nesting level.\n *\n * Numeric computed accesses (array indices such as `[0]`, `[1]`) are treated\n * as transparent pass-throughs: the rename map is kept unchanged and the walk\n * continues past the index. This means `content.field[0].sub` is handled\n * correctly — `field` and `sub` are both renamed while `[0]` is left intact.\n */\nconst walkRenameChain = (\n babelTypes: typeof BabelTypes,\n startPath: NodePath<BabelTypes.Node>,\n currentRenameMap: NestedRenameMap\n): {\n finalPath: NodePath<BabelTypes.Node>;\n finalRenameMap: NestedRenameMap;\n} => {\n let refPath: NodePath<BabelTypes.Node> = startPath;\n let renameMap = currentRenameMap;\n\n while (true) {\n const parentPath = refPath.parentPath;\n if (!parentPath) break;\n\n const parentNode = parentPath.node;\n\n if (\n (!babelTypes.isMemberExpression(parentNode) &&\n !babelTypes.isOptionalMemberExpression(parentNode)) ||\n (parentNode as BabelTypes.MemberExpression).object !== refPath.node\n ) {\n break;\n }\n\n const memberNode = parentNode as BabelTypes.MemberExpression;\n\n // Numeric index access ([0], [1], …): advance past the array accessor\n // without touching the rename map. The next iteration will attempt to\n // rename the property that follows the index.\n if (\n memberNode.computed &&\n babelTypes.isNumericLiteral(memberNode.property)\n ) {\n refPath = parentPath;\n continue;\n }\n\n // Nothing left to rename at this level — stop.\n if (renameMap.size === 0) break;\n\n let fieldName: string | undefined;\n\n if (!memberNode.computed && babelTypes.isIdentifier(memberNode.property)) {\n fieldName = memberNode.property.name;\n } else if (\n memberNode.computed &&\n babelTypes.isStringLiteral(memberNode.property)\n ) {\n fieldName = memberNode.property.value;\n } else {\n break; // dynamic computed key – stop\n }\n\n const renameEntry = renameMap.get(fieldName);\n if (!renameEntry) break; // not in map – stop\n\n // Apply the rename\n if (!memberNode.computed && babelTypes.isIdentifier(memberNode.property)) {\n memberNode.property.name = renameEntry.shortName;\n } else if (\n memberNode.computed &&\n babelTypes.isStringLiteral(memberNode.property)\n ) {\n memberNode.property.value = renameEntry.shortName;\n }\n\n refPath = parentPath;\n renameMap = renameEntry.children;\n }\n\n return { finalPath: refPath, finalRenameMap: renameMap };\n};\n\n/**\n * Renames the properties of a destructuring `ObjectPattern` using `renameMap`,\n * recursing into nested patterns and following the references of bound local\n * variables.\n *\n * Handled property shapes:\n *\n * { fieldA } → { shortA: fieldA }\n * { fieldA: localVar } → { shortA: localVar }\n * { fieldA = fallback } → { shortA: fieldA = fallback }\n * { fieldA: { nested } } → { shortA: { shortN: nested } }\n * { ['fieldA']: x } → { ['shortA']: x }\n * { [dynamicKey]: x } → left untouched (dynamic key – not renamable)\n *\n * @param babelTypes - Babel types helper.\n * @param objectPattern - The destructuring pattern to rename.\n * @param scopePath - A path whose scope resolves the pattern's bindings.\n * @param renameMap - Rename table for the current nesting level.\n */\nconst renameObjectPatternProperties = (\n babelTypes: typeof BabelTypes,\n objectPattern: BabelTypes.ObjectPattern,\n scopePath: NodePath<BabelTypes.Node>,\n renameMap: NestedRenameMap\n): void => {\n for (const property of objectPattern.properties) {\n if (!babelTypes.isObjectProperty(property)) continue;\n\n // Computed keys: a static string key ({ ['title']: x }) is renamable in\n // place; any other computed key is dynamic and must be left untouched —\n // replacing it with an identifier would create a variable reference.\n if (property.computed && !babelTypes.isStringLiteral(property.key)) {\n continue;\n }\n\n const keyName = babelTypes.isIdentifier(property.key)\n ? property.key.name\n : babelTypes.isStringLiteral(property.key)\n ? property.key.value\n : null;\n if (!keyName) continue;\n\n const renameEntry = renameMap.get(keyName);\n if (!renameEntry) continue;\n\n if (property.computed) {\n // { ['fieldA']: x } → { ['shortA']: x }\n (property.key as BabelTypes.StringLiteral).value = renameEntry.shortName;\n } else {\n // { fieldA } → { shortA: fieldA }\n // { fieldA: localVar } → { shortA: localVar }\n if (property.shorthand) {\n property.shorthand = false;\n }\n property.key = babelTypes.identifier(renameEntry.shortName);\n }\n\n if (renameEntry.children.size === 0) continue;\n\n // A default value ({ fieldA = fallback }) wraps the actual binding target.\n const bindingTarget = babelTypes.isAssignmentPattern(property.value)\n ? property.value.left\n : property.value;\n\n // Nested pattern: const { fieldA: { nested } } = … — rename its keys\n // with this entry's children map.\n if (babelTypes.isObjectPattern(bindingTarget)) {\n renameObjectPatternProperties(\n babelTypes,\n bindingTarget,\n scopePath,\n renameEntry.children\n );\n continue;\n }\n\n // Identifier binding: recursively walk references to the local variable.\n if (babelTypes.isIdentifier(bindingTarget)) {\n const localVarBinding = scopePath.scope.getBinding(bindingTarget.name);\n if (!localVarBinding) continue;\n\n for (const nestedRefPath of localVarBinding.referencePaths) {\n const { finalPath, finalRenameMap } = walkRenameChain(\n babelTypes,\n nestedRefPath,\n renameEntry.children\n );\n walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);\n }\n }\n }\n};\n\n/**\n * Walks an object-destructuring assignment whose right-hand side is `refPath`,\n * renaming each destructured key that is found in `renameMap`.\n *\n * Handles the \"secondary destructuring\" pattern that `walkRenameChain` cannot\n * reach because the reference is not a MemberExpression:\n *\n * const { webhooksSection } = useIntlayer('build-settings');\n * const { modal, validationErrors } = webhooksSection;\n * → const { a: modal, b: validationErrors } = webhooksSection;\n *\n * After renaming each key, {@link renameObjectPatternProperties} recursively\n * walks references to the newly-bound local variables, calling both\n * `walkRenameChain` (for subsequent member-access chains like\n * `validationErrors.invalidUrl`) and this function again (for further levels\n * of secondary destructuring).\n */\nconst walkObjectDestructuring = (\n babelTypes: typeof BabelTypes,\n refPath: NodePath<BabelTypes.Node>,\n renameMap: NestedRenameMap\n): void => {\n if (renameMap.size === 0) return;\n\n const parentNode = refPath.parent;\n\n // Only handle: const { a, b } = refVar\n if (\n !babelTypes.isVariableDeclarator(parentNode) ||\n !babelTypes.isObjectPattern(parentNode.id) ||\n parentNode.init !== refPath.node\n ) {\n return;\n }\n\n renameObjectPatternProperties(babelTypes, parentNode.id, refPath, renameMap);\n};\n\n/**\n * Collects the local aliases under which `useIntlayer` / `getIntlayer` are\n * imported in the given program (e.g. `import { useIntlayer as useI } …`\n * yields `useI` → `useIntlayer`).\n *\n * Import declarations can only appear at the top level of a module, so the\n * program body is scanned directly instead of traversing the whole AST.\n */\nconst collectIntlayerCallerLocalNames = (\n babelTypes: typeof BabelTypes,\n programNode: BabelTypes.Program\n): Map<string, string> => {\n const intlayerCallerLocalNameMap = new Map<string, string>();\n\n for (const statement of programNode.body) {\n if (!babelTypes.isImportDeclaration(statement)) continue;\n\n for (const importSpecifier of statement.specifiers) {\n if (!babelTypes.isImportSpecifier(importSpecifier)) continue;\n\n const importedName = babelTypes.isIdentifier(importSpecifier.imported)\n ? importSpecifier.imported.name\n : importSpecifier.imported.value;\n\n if (INTLAYER_CALLER_NAMES.includes(importedName as IntlayerCallerName)) {\n intlayerCallerLocalNameMap.set(\n importSpecifier.local.name,\n importedName\n );\n }\n }\n }\n\n return intlayerCallerLocalNameMap;\n};\n\n/**\n * Rewrites dictionary content field accesses in the given program to the\n * short aliases defined in `pruneContext.dictionaryKeyToFieldRenameMap`.\n *\n * Handled patterns (mirrors the usage analyser):\n *\n * const { fieldA, fieldB } = useIntlayer('key')\n * → const { shortA: fieldA, shortB: fieldB } = useIntlayer('key')\n *\n * useIntlayer('key').fieldA\n * → useIntlayer('key').shortA\n *\n * const result = useIntlayer('key'); result.fieldA\n * → const result = useIntlayer('key'); result.shortA\n *\n * const { fieldA } = useIntlayer('key');\n * const { nested } = fieldA; // secondary destructuring\n * → const { shortA: fieldA } = useIntlayer('key');\n * const { shortN: nested } = fieldA;\n *\n * Exposed as a standalone function so that both\n * {@link makeFieldRenameBabelPlugin} and `intlayerMinifyBabelPlugin` can\n * invoke it from their own `Program.exit` visitors.\n */\nexport const renameIntlayerFieldAccesses = (\n babelTypes: typeof BabelTypes,\n programPath: NodePath<BabelTypes.Program>,\n pruneContext: PruneContext\n): void => {\n if (pruneContext.dictionaryKeyToFieldRenameMap.size === 0) return;\n\n const intlayerCallerLocalNameMap = collectIntlayerCallerLocalNames(\n babelTypes,\n programPath.node\n );\n if (intlayerCallerLocalNameMap.size === 0) return;\n\n // Visit all useIntlayer / getIntlayer call-sites and rename field accesses\n programPath.traverse({\n CallExpression: (callExpressionPath) => {\n const calleeNode = callExpressionPath.node.callee;\n let localCallerName: string | undefined;\n\n if (babelTypes.isIdentifier(calleeNode)) {\n localCallerName = calleeNode.name;\n } else if (\n babelTypes.isMemberExpression(calleeNode) &&\n babelTypes.isIdentifier(calleeNode.property)\n ) {\n localCallerName = calleeNode.property.name;\n }\n\n if (!localCallerName || !intlayerCallerLocalNameMap.has(localCallerName))\n return;\n\n const callArguments = callExpressionPath.node.arguments;\n if (callArguments.length === 0) return;\n\n const firstArgument = callArguments[0];\n let dictionaryKey: string | undefined;\n\n if (babelTypes.isStringLiteral(firstArgument)) {\n dictionaryKey = firstArgument.value;\n } else if (\n babelTypes.isTemplateLiteral(firstArgument) &&\n firstArgument.expressions.length === 0 &&\n firstArgument.quasis.length === 1 &&\n firstArgument.quasis[0]\n ) {\n dictionaryKey =\n firstArgument.quasis[0].value.cooked ??\n firstArgument.quasis[0].value.raw;\n }\n\n if (!dictionaryKey) return;\n\n // Dictionaries flagged as structural edge cases are left completely\n // untouched by the JSON pipeline — keep their source accesses untouched\n // too so both sides stay consistent.\n if (pruneContext.dictionariesWithEdgeCases.has(dictionaryKey)) return;\n\n const fieldRenameMap =\n pruneContext.dictionaryKeyToFieldRenameMap.get(dictionaryKey);\n if (!fieldRenameMap || fieldRenameMap.size === 0) return;\n\n const parentNode = callExpressionPath.parent;\n\n // ── Case 1: const { fieldA, fieldB } = useIntlayer('key') ────────\n if (\n babelTypes.isVariableDeclarator(parentNode) &&\n babelTypes.isObjectPattern(parentNode.id)\n ) {\n walkObjectDestructuring(babelTypes, callExpressionPath, fieldRenameMap);\n return;\n }\n\n // ── Case 2: useIntlayer('key').fieldA.nested ─────────────────────\n if (\n (babelTypes.isMemberExpression(parentNode) ||\n babelTypes.isOptionalMemberExpression(parentNode)) &&\n (parentNode as BabelTypes.MemberExpression).object ===\n callExpressionPath.node\n ) {\n const { finalPath, finalRenameMap } = walkRenameChain(\n babelTypes,\n callExpressionPath,\n fieldRenameMap\n );\n walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);\n return;\n }\n\n // ── Case 3: const result = useIntlayer('key'); result.fieldA ─────\n if (\n babelTypes.isVariableDeclarator(parentNode) &&\n babelTypes.isIdentifier(parentNode.id)\n ) {\n const variableBinding = callExpressionPath.scope.getBinding(\n parentNode.id.name\n );\n if (!variableBinding) return;\n\n for (const variableReferencePath of variableBinding.referencePaths) {\n // Direct access: result.fieldA or const { fieldA } = result\n const { finalPath, finalRenameMap } = walkRenameChain(\n babelTypes,\n variableReferencePath,\n fieldRenameMap\n );\n walkObjectDestructuring(babelTypes, finalPath, finalRenameMap);\n\n // Signal accessor: result().fieldA or const { fieldA } = result()\n // walkRenameChain stops at a CallExpression parent, so we need to\n // start a new walk from the call-expression node itself.\n const refParent = variableReferencePath.parent;\n if (\n (babelTypes.isCallExpression(refParent) ||\n babelTypes.isOptionalCallExpression(refParent)) &&\n (refParent as BabelTypes.CallExpression).callee ===\n variableReferencePath.node\n ) {\n const callPath = variableReferencePath.parentPath;\n if (callPath) {\n const {\n finalPath: signalFinalPath,\n finalRenameMap: signalFinalRenameMap,\n } = walkRenameChain(babelTypes, callPath, fieldRenameMap);\n walkObjectDestructuring(\n babelTypes,\n signalFinalPath,\n signalFinalRenameMap\n );\n }\n }\n }\n }\n },\n });\n};\n\n/**\n * Creates a Babel plugin that rewrites dictionary content field accesses in\n * source files to their short aliases via\n * {@link renameIntlayerFieldAccesses}.\n *\n * This plugin must run in a separate `transformAsync` pass **before**\n * `intlayerOptimizeBabelPlugin`, because the latter replaces `useIntlayer`\n * with `useDictionary`, erasing the dictionary-key information needed here.\n */\nexport const makeFieldRenameBabelPlugin =\n (pruneContext: PruneContext) =>\n ({ types: babelTypes }: { types: typeof BabelTypes }): PluginObject => ({\n name: 'intlayer-field-rename',\n visitor: {\n Program: {\n exit: (programPath) => {\n renameIntlayerFieldAccesses(babelTypes, programPath, pruneContext);\n },\n },\n },\n });\n"],"mappings":"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"}
|
|
@@ -49,34 +49,17 @@ const require_babel_plugin_intlayer_purge = require('./babel-plugin-intlayer-pur
|
|
|
49
49
|
* `useDictionary`, erasing the dictionary-key information needed to look up
|
|
50
50
|
* the rename map.
|
|
51
51
|
*/
|
|
52
|
-
const intlayerMinifyBabelPlugin = (babel) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
pre() {
|
|
64
|
-
const { baseDir, minify, optimize, editorEnabled } = this.opts;
|
|
65
|
-
if (!minify || optimize === false || editorEnabled) return;
|
|
66
|
-
if (resolvedBaseDir === baseDir && fieldRenameExitVisitor !== null) return;
|
|
67
|
-
const pruneContext = require_babel_plugin_intlayer_purge.getSharedPruneContext(baseDir);
|
|
68
|
-
if (!pruneContext || pruneContext.dictionaryKeyToFieldRenameMap.size === 0) return;
|
|
69
|
-
resolvedBaseDir = baseDir;
|
|
70
|
-
const programVisitor = require_babel_plugin_intlayer_field_rename.makeFieldRenameBabelPlugin(pruneContext)(babel).visitor.Program;
|
|
71
|
-
if (programVisitor && typeof programVisitor === "object" && "exit" in programVisitor && typeof programVisitor.exit === "function") fieldRenameExitVisitor = programVisitor.exit;
|
|
72
|
-
},
|
|
73
|
-
visitor: { Program: { exit(programPath, state) {
|
|
74
|
-
if (!fieldRenameExitVisitor) return;
|
|
75
|
-
if (!require_transformers.INTLAYER_USAGE_REGEX.test(state.file.code)) return;
|
|
76
|
-
fieldRenameExitVisitor(programPath);
|
|
77
|
-
} } }
|
|
78
|
-
};
|
|
79
|
-
};
|
|
52
|
+
const intlayerMinifyBabelPlugin = (babel) => ({
|
|
53
|
+
name: "intlayer-minify",
|
|
54
|
+
visitor: { Program: { exit(programPath, state) {
|
|
55
|
+
const { baseDir, minify, optimize, editorEnabled } = state.opts;
|
|
56
|
+
if (!minify || optimize === false || editorEnabled) return;
|
|
57
|
+
if (!require_transformers.INTLAYER_USAGE_REGEX.test(state.file.code)) return;
|
|
58
|
+
const pruneContext = require_babel_plugin_intlayer_purge.getSharedPruneContext(baseDir);
|
|
59
|
+
if (!pruneContext) return;
|
|
60
|
+
require_babel_plugin_intlayer_field_rename.renameIntlayerFieldAccesses(babel.types, programPath, pruneContext);
|
|
61
|
+
} } }
|
|
62
|
+
});
|
|
80
63
|
|
|
81
64
|
//#endregion
|
|
82
65
|
exports.intlayerMinifyBabelPlugin = intlayerMinifyBabelPlugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-minify.cjs","names":["
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-minify.cjs","names":["INTLAYER_USAGE_REGEX","getSharedPruneContext"],"sources":["../../src/babel-plugin-intlayer-minify.ts"],"sourcesContent":["import type { NodePath, PluginObject, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport { renameIntlayerFieldAccesses } from './babel-plugin-intlayer-field-rename';\nimport { getSharedPruneContext } from './babel-plugin-intlayer-purge';\nimport type { PruneContext } from './babel-plugin-intlayer-usage-analyzer';\nimport { INTLAYER_USAGE_REGEX } from './transformers';\n\n// ── Plugin options ────────────────────────────────────────────────────────────\n\n/**\n * Pre-resolved options accepted by {@link intlayerMinifyBabelPlugin}.\n *\n * All values are resolved at babel.config.js load time (via\n * {@link getMinifyPluginOptions}) so the plugin does not read the intlayer\n * configuration file on every file transform.\n */\nexport type MinifyPluginOptions = {\n /**\n * Absolute path to the project root. Used to look up the shared\n * {@link PruneContext} built by {@link intlayerPurgeBabelPlugin}.\n */\n baseDir: string;\n\n /**\n * When `true`, rewrite source-file property accesses to use the short\n * alphabetic aliases assigned during the minification pass\n * (e.g. `content.title` → `content.a`). Mirrors `build.minify`.\n */\n minify: boolean;\n\n /**\n * Build optimisation toggle. When explicitly `false`, the plugin is a\n * no-op. Mirrors `build.optimize`.\n */\n optimize: boolean | undefined;\n\n /**\n * When `true` the plugin is a no-op. Mirrors `editor.enabled`.\n */\n editorEnabled: boolean;\n};\n\n// ── Babel plugin ──────────────────────────────────────────────────────────────\n\n/**\n * Babel plugin that rewrites component source files to use the short\n * alphabetic aliases assigned to dictionary content fields during the\n * minification pass (e.g. `content.title` → `content.a`).\n *\n * This plugin relies on the field-rename map built by\n * {@link intlayerPurgeBabelPlugin} during its `pre()` hook. Both plugins\n * share the same module-level {@link PruneContext} via\n * {@link getSharedPruneContext}, so **`intlayerPurgeBabelPlugin` must be\n * listed before this plugin** in `babel.config.js` so that its `pre()` runs\n * first and the shared context is populated before this plugin's\n * `Program.exit` visitor fires.\n *\n * All option values must be pre-resolved via {@link getMinifyPluginOptions}.\n *\n * @example\n * ```js\n * // babel.config.js\n * const {\n * intlayerPurgeBabelPlugin,\n * intlayerMinifyBabelPlugin,\n * intlayerOptimizeBabelPlugin,\n * getPurgePluginOptions,\n * getMinifyPluginOptions,\n * getOptimizePluginOptions,\n * } = require(\"@intlayer/babel\");\n *\n * module.exports = {\n * presets: [\"next/babel\"],\n * plugins: [\n * [intlayerPurgeBabelPlugin, getPurgePluginOptions()],\n * [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],\n * [intlayerOptimizeBabelPlugin, getOptimizePluginOptions()],\n * ],\n * };\n * ```\n *\n * @remarks\n * - This plugin is a no-op when `minify` is `false`, `optimize` is `false`,\n * or `editorEnabled` is `true`.\n * - Source-code renames must run **before** {@link intlayerOptimizeBabelPlugin}\n * because the optimize pass replaces `useIntlayer` calls with\n * `useDictionary`, erasing the dictionary-key information needed to look up\n * the rename map.\n */\nexport const intlayerMinifyBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObject => ({\n name: 'intlayer-minify',\n\n visitor: {\n Program: {\n exit(programPath: NodePath<BabelTypes.Program>, state: PluginPass): void {\n const { baseDir, minify, optimize, editorEnabled } =\n state.opts as MinifyPluginOptions;\n\n if (!minify || optimize === false || editorEnabled) return;\n if (!INTLAYER_USAGE_REGEX.test(state.file.code)) return;\n\n const pruneContext: PruneContext | null =\n getSharedPruneContext(baseDir);\n if (!pruneContext) return;\n\n renameIntlayerFieldAccesses(babel.types, programPath, pruneContext);\n },\n },\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyFA,MAAa,6BAA6B,WAErB;CACnB,MAAM;CAEN,SAAS,EACP,SAAS,EACP,KAAK,aAA2C,OAAyB;EACvE,MAAM,EAAE,SAAS,QAAQ,UAAU,kBACjC,MAAM;EAER,IAAI,CAAC,UAAU,aAAa,SAAS,eAAe;EACpD,IAAI,CAACA,0CAAqB,KAAK,MAAM,KAAK,IAAI,GAAG;EAEjD,MAAM,eACJC,0DAAsB,OAAO;EAC/B,IAAI,CAAC,cAAc;EAEnB,uEAA4B,MAAM,OAAO,aAAa,YAAY;CACpE,EACF,EACF;AACF"}
|