@intlayer/babel 9.0.0-canary.11 → 9.0.0-canary.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/babel-plugin-intlayer-extract.cjs +2 -1
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +3 -2
- package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs +141 -11
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-purge.cjs +1 -1
- package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs +47 -16
- package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
- package/dist/cjs/extractContent/babelProcessor.cjs +85 -74
- 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 +3 -6
- package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/constants.cjs +1 -1
- package/dist/cjs/extractContent/utils/constants.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 -2
- package/dist/cjs/extractContent/utils/extractDictionaryKey.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 -2
- package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
- package/dist/cjs/getPurgePluginOptions.cjs +2 -2
- package/dist/cjs/getPurgePluginOptions.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/normalizedFilesList.cjs +31 -0
- package/dist/cjs/normalizedFilesList.cjs.map +1 -0
- package/dist/cjs/transformers.cjs +20 -1
- package/dist/cjs/transformers.cjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs +2 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-field-rename.mjs +3 -2
- package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +138 -8
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-purge.mjs +2 -2
- package/dist/esm/babel-plugin-intlayer-purge.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs +47 -16
- package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
- package/dist/esm/extractContent/babelProcessor.mjs +85 -74
- 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 +2 -5
- package/dist/esm/extractContent/processTsxFile.mjs.map +1 -1
- package/dist/esm/extractContent/utils/constants.mjs +1 -1
- package/dist/esm/extractContent/utils/constants.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/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 +2 -2
- 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.map +1 -1
- package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts +17 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-purge.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts +8 -116
- package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
- package/dist/types/extractContent/babelProcessor.d.ts +3 -1
- package/dist/types/extractContent/babelProcessor.d.ts.map +1 -1
- package/dist/types/extractContent/contentWriter.d.ts.map +1 -1
- package/dist/types/extractContent/index.d.ts +1 -1
- package/dist/types/extractContent/processTsxFile.d.ts.map +1 -1
- package/dist/types/extractContent/utils/constants.d.ts +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/normalizedFilesList.d.ts +12 -0
- package/dist/types/normalizedFilesList.d.ts.map +1 -0
- package/dist/types/transformers.d.ts +7 -1
- package/dist/types/transformers.d.ts.map +1 -1
- package/package.json +17 -17
|
@@ -2,10 +2,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
const require_extractContent_utils_extractDictionaryKey = require('./extractDictionaryKey.cjs');
|
|
4
4
|
let node_path = require("node:path");
|
|
5
|
-
let _intlayer_chokidar_utils = require("@intlayer/chokidar/utils");
|
|
6
5
|
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
7
6
|
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
8
7
|
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
8
|
+
let _intlayer_engine_utils = require("@intlayer/engine/utils");
|
|
9
9
|
let _intlayer_config_utils = require("@intlayer/config/utils");
|
|
10
10
|
let _intlayer_unmerged_dictionaries_entry = require("@intlayer/unmerged-dictionaries-entry");
|
|
11
11
|
|
|
@@ -47,7 +47,7 @@ const resolveContentFilePaths = async (filePath, componentKey, configuration, lo
|
|
|
47
47
|
const extension = (0, node_path.extname)(filePath);
|
|
48
48
|
const componentName = (0, node_path.basename)(filePath, extension);
|
|
49
49
|
const uncapitalizedName = componentName.charAt(0).toLowerCase() + componentName.slice(1);
|
|
50
|
-
const componentFormat = (0,
|
|
50
|
+
const componentFormat = (0, _intlayer_engine_utils.getFormatFromExtension)(extension);
|
|
51
51
|
const targetLocale = locale ?? defaultLocale;
|
|
52
52
|
const context = {
|
|
53
53
|
key: componentKey,
|
|
@@ -63,7 +63,7 @@ const resolveContentFilePaths = async (filePath, componentKey, configuration, lo
|
|
|
63
63
|
if (isObjectOutput) {
|
|
64
64
|
const pattern = getOutput(configuration, targetLocale);
|
|
65
65
|
if (pattern === false) throw new Error(`compiler.output is disabled for locale "${targetLocale}".`);
|
|
66
|
-
const absolutePath = (0,
|
|
66
|
+
const absolutePath = (0, _intlayer_engine_utils.resolveRelativePath)(await pattern(context), filePath, baseDir);
|
|
67
67
|
return {
|
|
68
68
|
absolutePath,
|
|
69
69
|
relativePath: (0, node_path.relative)(baseDir, absolutePath),
|
|
@@ -72,7 +72,7 @@ const resolveContentFilePaths = async (filePath, componentKey, configuration, lo
|
|
|
72
72
|
}
|
|
73
73
|
const pattern = getOutput(configuration);
|
|
74
74
|
if (pattern === false) throw new Error(`No output configuration found. Add a ${(0, _intlayer_config_logger.colorize)("compiler.output", _intlayer_config_colors.BLUE)} in your configuration.`);
|
|
75
|
-
const absolutePath = (0,
|
|
75
|
+
const absolutePath = (0, _intlayer_engine_utils.resolveRelativePath)(await pattern({
|
|
76
76
|
...context,
|
|
77
77
|
locale: defaultLocale
|
|
78
78
|
}), filePath, baseDir);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractDictionaryInfo.cjs","names":["ANSIColors","extractDictionaryKey"],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"sourcesContent":["import { basename, dirname, extname, relative, resolve } from 'node:path';\nimport
|
|
1
|
+
{"version":3,"file":"extractDictionaryInfo.cjs","names":["ANSIColors","extractDictionaryKey"],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"sourcesContent":["import { basename, dirname, extname, relative, resolve } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\nimport { assertPathWithin, parseStringPattern } from '@intlayer/config/utils';\nimport {\n getFormatFromExtension,\n resolveRelativePath,\n} from '@intlayer/engine/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Fill } from '@intlayer/types/dictionary';\nimport type {\n FilePathPattern,\n FilePathPatternContext,\n FilePathPatternFunction,\n} from '@intlayer/types/filePathPattern';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { extractDictionaryKey } from './extractDictionaryKey';\n\nexport const getOutput = (\n configuration: IntlayerConfig,\n locale?: Locale\n): FilePathPatternFunction | false => {\n const output = configuration.compiler?.output as Fill | undefined;\n\n if (output === undefined || output === null) {\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n }\n\n if (output === false) return false;\n\n // Object per-locale record: look up the entry for the given locale\n if (typeof output === 'object' && typeof output !== 'function') {\n const entry = locale\n ? (output as Record<string, boolean | FilePathPattern>)[locale]\n : undefined;\n if (entry === false) return false;\n if (entry === undefined || entry === true) {\n throw new Error(\n `No output pattern configured for locale \"${locale}\" in compiler.output.`\n );\n }\n return typeof entry === 'string'\n ? (context: FilePathPatternContext) =>\n parseStringPattern(entry as string, context)\n : (entry as FilePathPatternFunction);\n }\n\n if (typeof output === 'string') {\n return (context: FilePathPatternContext) =>\n parseStringPattern(output, context);\n }\n\n if (typeof output === 'function') {\n return output as FilePathPatternFunction;\n }\n\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n};\n\nexport type ResolveContentFilePaths = {\n absolutePath: string;\n relativePath: string;\n isPerLocale: boolean;\n};\n\n/**\n * Resolves the paths for the content files associated with a component.\n * Checks for existing dictionaries first.\n */\nexport const resolveContentFilePaths = async (\n filePath: string,\n componentKey: string,\n configuration: IntlayerConfig,\n locale?: Locale\n): Promise<ResolveContentFilePaths> => {\n const { baseDir } = configuration.system;\n const { defaultLocale } = configuration.internationalization;\n\n const unmergedDictionaries = getUnmergedDictionaries(configuration) ?? {};\n const existingDicts = unmergedDictionaries[componentKey]\n ?.filter(\n (dictionary) =>\n // Remove remote dictionaries (Fix: Check for !== instead of ===)\n dictionary.location !== 'remote'\n )\n .filter(\n (dictionary) =>\n // Check for first locale dictionary sorted by priority that include the targeted locale\n dictionary.locale === undefined ||\n dictionary.locale === (locale ?? defaultLocale)\n );\n\n if (existingDicts?.[0]?.filePath) {\n const existingPath = existingDicts[0].filePath;\n const resolvedAbsolutePath = resolve(baseDir, existingPath);\n\n assertPathWithin(resolvedAbsolutePath, baseDir);\n\n return {\n absolutePath: resolvedAbsolutePath,\n relativePath: relative(baseDir, resolvedAbsolutePath),\n isPerLocale: false,\n };\n }\n\n const output = configuration.compiler?.output as Fill | undefined;\n const isObjectOutput =\n typeof output === 'object' &&\n output !== null &&\n typeof output !== 'function';\n\n // Build shared context (used for both object and scalar output paths)\n const extension = extname(\n filePath\n ) as FilePathPatternContext['componentExtension'];\n const componentName = basename(filePath, extension);\n const uncapitalizedName =\n componentName.charAt(0).toLowerCase() + componentName.slice(1);\n const componentFormat = getFormatFromExtension(\n extension!\n ) as FilePathPatternContext['componentFormat'];\n\n const targetLocale = (locale ?? defaultLocale) as Locale;\n\n const context: FilePathPatternContext = {\n key: componentKey,\n componentDirPath: relative(baseDir, dirname(filePath)),\n componentFileName: componentName,\n fileName: uncapitalizedName,\n componentFormat,\n componentExtension: extension,\n format: componentFormat!,\n locale: targetLocale,\n extension: configuration.content.fileExtensions[0] ?? '.ts',\n };\n\n // Object output: each locale has its own pattern → always per-locale\n if (isObjectOutput) {\n const pattern = getOutput(configuration, targetLocale);\n if (pattern === false) {\n throw new Error(\n `compiler.output is disabled for locale \"${targetLocale}\".`\n );\n }\n const rawAbsolutePath = await pattern(context);\n const absolutePath = resolveRelativePath(\n rawAbsolutePath,\n filePath,\n baseDir\n );\n return {\n absolutePath,\n relativePath: relative(baseDir, absolutePath),\n isPerLocale: true,\n };\n }\n\n // Scalar string/function output: detect per-locale via dummy locale probe\n const pattern = getOutput(configuration);\n if (pattern === false) {\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n }\n\n const rawAbsolutePath = await pattern({ ...context, locale: defaultLocale });\n\n // Apply the resolution rules\n const absolutePath = resolveRelativePath(rawAbsolutePath, filePath, baseDir);\n\n const localeIdentifier = '###########locale###########' as Locale;\n\n const rawPerLocalePath = await pattern({\n ...context,\n locale: localeIdentifier,\n });\n const isPerLocale = rawPerLocalePath.includes(localeIdentifier);\n\n return {\n absolutePath,\n relativePath: relative(baseDir, absolutePath),\n isPerLocale,\n };\n};\n\nexport type ExtractDictionaryInfoOptions = {\n configuration?: IntlayerConfig;\n};\n\n/**\n * Extracts the dictionary key and dictionary file path for a given component file.\n */\nexport const extractDictionaryInfo = async (\n filePath: string,\n fileText: string,\n configuration: IntlayerConfig\n): Promise<\n {\n dictionaryKey: string;\n } & ResolveContentFilePaths\n> => {\n const dictionaryKey = extractDictionaryKey(filePath, fileText);\n\n const resolvedPaths = await resolveContentFilePaths(\n filePath,\n dictionaryKey,\n configuration\n );\n\n return {\n dictionaryKey,\n ...resolvedPaths,\n };\n};\n"],"mappings":";;;;;;;;;;;;AAmBA,MAAa,aACX,eACA,WACoC;CACpC,MAAM,SAAS,cAAc,UAAU;AAEvC,KAAI,WAAW,UAAa,WAAW,KACrC,OAAM,IAAI,MACR,8EAAiD,mBAAmBA,wBAAW,KAAK,CAAC,yBACtF;AAGH,KAAI,WAAW,MAAO,QAAO;AAG7B,KAAI,OAAO,WAAW,YAAY,OAAO,WAAW,YAAY;EAC9D,MAAM,QAAQ,SACT,OAAqD,UACtD;AACJ,MAAI,UAAU,MAAO,QAAO;AAC5B,MAAI,UAAU,UAAa,UAAU,KACnC,OAAM,IAAI,MACR,4CAA4C,OAAO,uBACpD;AAEH,SAAO,OAAO,UAAU,YACnB,2DACoB,OAAiB,QAAQ,GAC7C;;AAGP,KAAI,OAAO,WAAW,SACpB,SAAQ,2DACa,QAAQ,QAAQ;AAGvC,KAAI,OAAO,WAAW,WACpB,QAAO;AAGT,OAAM,IAAI,MACR,8EAAiD,mBAAmBA,wBAAW,KAAK,CAAC,yBACtF;;;;;;AAaH,MAAa,0BAA0B,OACrC,UACA,cACA,eACA,WACqC;CACrC,MAAM,EAAE,YAAY,cAAc;CAClC,MAAM,EAAE,kBAAkB,cAAc;CAGxC,MAAM,oFAD+C,cAAc,IAAI,EAAE,EAC9B,eACvC,QACC,eAEC,WAAW,aAAa,SAC3B,CACA,QACE,eAEC,WAAW,WAAW,UACtB,WAAW,YAAY,UAAU,eACpC;AAEH,KAAI,gBAAgB,IAAI,UAAU;EAChC,MAAM,eAAe,cAAc,GAAG;EACtC,MAAM,8CAA+B,SAAS,aAAa;AAE3D,+CAAiB,sBAAsB,QAAQ;AAE/C,SAAO;GACL,cAAc;GACd,sCAAuB,SAAS,qBAAqB;GACrD,aAAa;GACd;;CAGH,MAAM,SAAS,cAAc,UAAU;CACvC,MAAM,iBACJ,OAAO,WAAW,YAClB,WAAW,QACX,OAAO,WAAW;CAGpB,MAAM,mCACJ,SACD;CACD,MAAM,wCAAyB,UAAU,UAAU;CACnD,MAAM,oBACJ,cAAc,OAAO,EAAE,CAAC,aAAa,GAAG,cAAc,MAAM,EAAE;CAChE,MAAM,qEACJ,UACD;CAED,MAAM,eAAgB,UAAU;CAEhC,MAAM,UAAkC;EACtC,KAAK;EACL,0CAA2B,gCAAiB,SAAS,CAAC;EACtD,mBAAmB;EACnB,UAAU;EACV;EACA,oBAAoB;EACpB,QAAQ;EACR,QAAQ;EACR,WAAW,cAAc,QAAQ,eAAe,MAAM;EACvD;AAGD,KAAI,gBAAgB;EAClB,MAAM,UAAU,UAAU,eAAe,aAAa;AACtD,MAAI,YAAY,MACd,OAAM,IAAI,MACR,2CAA2C,aAAa,IACzD;EAGH,MAAM,+DACJ,MAF4B,QAAQ,QAAQ,EAG5C,UACA,QACD;AACD,SAAO;GACL;GACA,sCAAuB,SAAS,aAAa;GAC7C,aAAa;GACd;;CAIH,MAAM,UAAU,UAAU,cAAc;AACxC,KAAI,YAAY,MACd,OAAM,IAAI,MACR,8EAAiD,mBAAmBA,wBAAW,KAAK,CAAC,yBACtF;CAMH,MAAM,+DAAmC,MAHX,QAAQ;EAAE,GAAG;EAAS,QAAQ;EAAe,CAAC,EAGlB,UAAU,QAAQ;CAE5E,MAAM,mBAAmB;CAMzB,MAAM,eAAc,MAJW,QAAQ;EACrC,GAAG;EACH,QAAQ;EACT,CAAC,EACmC,SAAS,iBAAiB;AAE/D,QAAO;EACL;EACA,sCAAuB,SAAS,aAAa;EAC7C;EACD;;;;;AAUH,MAAa,wBAAwB,OACnC,UACA,UACA,kBAKG;CACH,MAAM,gBAAgBC,uEAAqB,UAAU,SAAS;AAQ9D,QAAO;EACL;EACA,GAAG,MARuB,wBAC1B,UACA,eACA,cACD;EAKA"}
|
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
|
|
4
4
|
let _intlayer_config_utils = require("@intlayer/config/utils");
|
|
5
|
-
let
|
|
5
|
+
let _intlayer_engine_cli = require("@intlayer/engine/cli");
|
|
6
6
|
|
|
7
7
|
//#region src/extractContent/utils/extractDictionaryKey.ts
|
|
8
8
|
/**
|
|
@@ -19,7 +19,7 @@ const extractDictionaryKeyFromPath = (filePath, prefix = _intlayer_config_defaul
|
|
|
19
19
|
return `${prefix}${(0, _intlayer_config_utils.camelCaseToKebabCase)(baseName)}`;
|
|
20
20
|
};
|
|
21
21
|
const extractDictionaryKey = (filePath, fileText, prefix = _intlayer_config_defaultValues.COMPILER_DICTIONARY_KEY_PREFIX) => {
|
|
22
|
-
const componentName = (0,
|
|
22
|
+
const componentName = (0, _intlayer_engine_cli.detectExportedComponentName)(fileText);
|
|
23
23
|
if (componentName) return `${prefix}${(0, _intlayer_config_utils.camelCaseToKebabCase)(componentName)}`;
|
|
24
24
|
return extractDictionaryKeyFromPath(filePath, prefix);
|
|
25
25
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractDictionaryKey.cjs","names":["COMPILER_DICTIONARY_KEY_PREFIX"],"sources":["../../../../src/extractContent/utils/extractDictionaryKey.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"extractDictionaryKey.cjs","names":["COMPILER_DICTIONARY_KEY_PREFIX"],"sources":["../../../../src/extractContent/utils/extractDictionaryKey.ts"],"sourcesContent":["import { COMPILER_DICTIONARY_KEY_PREFIX } from '@intlayer/config/defaultValues';\nimport { camelCaseToKebabCase } from '@intlayer/config/utils';\nimport { detectExportedComponentName } from '@intlayer/engine/cli';\n\n/**\n * Extracts a dictionary key from a file path.\n *\n * Example: \"src/components/MyComponent/index.tsx\" -> \"comp-my-component\"\n */\nexport const extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = COMPILER_DICTIONARY_KEY_PREFIX\n): string => {\n const pathParts = filePath.split(/[\\\\/]/);\n const fileNameWithExt = pathParts.pop() || '';\n const lastDotIndex = fileNameWithExt.lastIndexOf('.');\n let baseName =\n lastDotIndex !== -1\n ? fileNameWithExt.slice(0, lastDotIndex)\n : fileNameWithExt;\n\n if (baseName.toLowerCase() === 'index') {\n baseName = pathParts.pop() || baseName;\n }\n\n return `${prefix}${camelCaseToKebabCase(baseName)}`;\n};\n\nexport const extractDictionaryKey = (\n filePath: string,\n fileText: string,\n prefix = COMPILER_DICTIONARY_KEY_PREFIX\n): string => {\n const componentName = detectExportedComponentName(fileText);\n\n if (componentName) {\n return `${prefix}${camelCaseToKebabCase(componentName)}`;\n }\n\n return extractDictionaryKeyFromPath(filePath, prefix);\n};\n"],"mappings":";;;;;;;;;;;;AASA,MAAa,gCACX,UACA,SAASA,kEACE;CACX,MAAM,YAAY,SAAS,MAAM,QAAQ;CACzC,MAAM,kBAAkB,UAAU,KAAK,IAAI;CAC3C,MAAM,eAAe,gBAAgB,YAAY,IAAI;CACrD,IAAI,WACF,iBAAiB,KACb,gBAAgB,MAAM,GAAG,aAAa,GACtC;AAEN,KAAI,SAAS,aAAa,KAAK,QAC7B,YAAW,UAAU,KAAK,IAAI;AAGhC,QAAO,GAAG,0DAA8B,SAAS;;AAGnD,MAAa,wBACX,UACA,UACA,SAASA,kEACE;CACX,MAAM,sEAA4C,SAAS;AAE3D,KAAI,cACF,QAAO,GAAG,0DAA8B,cAAc;AAGxD,QAAO,6BAA6B,UAAU,OAAO"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
const require_extractContent_contentWriter = require('./extractContent/contentWriter.cjs');
|
|
4
|
-
let _intlayer_chokidar_utils = require("@intlayer/chokidar/utils");
|
|
5
4
|
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
6
5
|
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
7
6
|
let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
|
|
8
7
|
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
9
8
|
let _intlayer_config_node = require("@intlayer/config/node");
|
|
9
|
+
let _intlayer_engine_utils = require("@intlayer/engine/utils");
|
|
10
10
|
|
|
11
11
|
//#region src/getExtractPluginOptions.ts
|
|
12
12
|
/**
|
|
@@ -22,7 +22,7 @@ const getExtractPluginOptions = (configuration = (0, _intlayer_config_node.getCo
|
|
|
22
22
|
let enabled = configuration.compiler?.enabled ?? _intlayer_config_defaultValues.COMPILER_ENABLED;
|
|
23
23
|
if (enabled === "build-only") if (compilerMode) enabled = compilerMode === "build";
|
|
24
24
|
else enabled = process.env.NODE_ENV === "production";
|
|
25
|
-
const filesList = (0,
|
|
25
|
+
const filesList = (0, _intlayer_engine_utils.buildComponentFilesList)(configuration);
|
|
26
26
|
return {
|
|
27
27
|
enabled,
|
|
28
28
|
configuration,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getExtractPluginOptions.cjs","names":["ANSIColors","COMPILER_ENABLED","writeContentHelper"],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"getExtractPluginOptions.cjs","names":["ANSIColors","COMPILER_ENABLED","writeContentHelper"],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport { COMPILER_ENABLED } from '@intlayer/config/defaultValues';\nimport { colorize, colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { buildComponentFilesList } from '@intlayer/engine/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { ExtractPluginOptions } from './babel-plugin-intlayer-extract';\nimport { writeContentHelper } from './extractContent/contentWriter';\n\n/**\n * Mode of the compiler\n * - 'dev': Development mode with HMR support\n * - 'build': Production build mode\n */\nexport type CompilerMode = 'dev' | 'build';\n\n/**\n * Get the options for the Intlayer Babel extraction plugin\n * This function loads the Intlayer configuration and sets up the onExtract callback\n * to write dictionaries to the filesystem.\n */\nexport const getExtractPluginOptions = (\n configuration: IntlayerConfig = getConfiguration(),\n isDev: CompilerMode | string | undefined = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n // Accept 'dev'/'serve' (Vite), boolean true, or the string 'true' (env var)\n const isDevBoolean = isDev === 'dev' || isDev === 'serve' || isDev === 'true';\n\n const compilerMode: CompilerMode = isDevBoolean ? 'dev' : 'build';\n\n const logger = getAppLogger(configuration);\n\n if (configuration.compiler?.enabled === 'build-only' && isDevBoolean) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`\n );\n }\n\n let enabled = configuration.compiler?.enabled ?? COMPILER_ENABLED;\n\n if (enabled === 'build-only') {\n if (compilerMode) {\n enabled = compilerMode === 'build';\n } else {\n // Fallback if mode isn't explicitly provided (e.g. pure babel plugin context)\n enabled = process.env.NODE_ENV === 'production';\n }\n }\n\n const filesList = buildComponentFilesList(configuration);\n\n return {\n enabled,\n configuration,\n filesList,\n onExtract: async ({ dictionaryKey, content, filePath }) => {\n try {\n await writeContentHelper(\n content,\n dictionaryKey,\n filePath,\n configuration\n );\n } catch (error) {\n logger(\n [\n `Failed to process extracted content for ${colorizeKey(dictionaryKey)}:`,\n error,\n ],\n { level: 'error' }\n );\n }\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAqBA,MAAa,2BACX,6DAAkD,EAClD,QAA2C,QAAQ,IAAI,4BAC9B;CAEzB,MAAM,eAAe,UAAU,SAAS,UAAU,WAAW,UAAU;CAEvE,MAAM,eAA6B,eAAe,QAAQ;CAE1D,MAAM,mDAAsB,cAAc;AAE1C,KAAI,cAAc,UAAU,YAAY,gBAAgB,aACtD,QACE,yCAAY,aAAaA,wBAAW,UAAU,CAAC,wIAChD;CAGH,IAAI,UAAU,cAAc,UAAU,WAAWC;AAEjD,KAAI,YAAY,aACd,KAAI,aACF,WAAU,iBAAiB;KAG3B,WAAU,QAAQ,IAAI,aAAa;CAIvC,MAAM,gEAAoC,cAAc;AAExD,QAAO;EACL;EACA;EACA;EACA,WAAW,OAAO,EAAE,eAAe,SAAS,eAAe;AACzD,OAAI;AACF,UAAMC,wDACJ,SACA,eACA,UACA,cACD;YACM,OAAO;AACd,WACE,CACE,oFAAuD,cAAc,CAAC,IACtE,MACD,EACD,EAAE,OAAO,SAAS,CACnB;;;EAGN"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
let node_path = require("node:path");
|
|
4
|
-
let _intlayer_chokidar_utils = require("@intlayer/chokidar/utils");
|
|
5
4
|
let _intlayer_config_node = require("@intlayer/config/node");
|
|
5
|
+
let _intlayer_engine_utils = require("@intlayer/engine/utils");
|
|
6
6
|
|
|
7
7
|
//#region src/getOptimizePluginOptions.ts
|
|
8
8
|
/**
|
|
@@ -33,7 +33,7 @@ const getOptimizePluginOptions = (params) => {
|
|
|
33
33
|
const dynamicDictionariesEntryPath = (0, node_path.join)(mainDir, "dynamic_dictionaries.mjs");
|
|
34
34
|
const fetchDictionariesEntryPath = (0, node_path.join)(mainDir, "fetch_dictionaries.mjs");
|
|
35
35
|
const filesList = [
|
|
36
|
-
...(0,
|
|
36
|
+
...(0, _intlayer_engine_utils.buildComponentFilesList)(config),
|
|
37
37
|
dictionariesEntryPath,
|
|
38
38
|
unmergedDictionariesEntryPath
|
|
39
39
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getOptimizePluginOptions.cjs","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"sourcesContent":["import { join } from 'node:path';\nimport {
|
|
1
|
+
{"version":3,"file":"getOptimizePluginOptions.cjs","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"sourcesContent":["import { join } from 'node:path';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { buildComponentFilesList } from '@intlayer/engine/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { OptimizePluginOptions } from './babel-plugin-intlayer-optimize';\n\ntype GetOptimizePluginOptionsParams = {\n /**\n * Configuration options for loading intlayer config\n */\n configOptions?: GetConfigurationOptions;\n /**\n * Pre-loaded dictionaries (optional - will be loaded if not provided)\n */\n dictionaries?: Dictionary[];\n /**\n * Whether the current transform is for an SSR bundle. When using Babel\n * directly (e.g. in `babel.config.js`), forward the bundler's server flag\n * here so SSR-specific static dictionary transforms apply.\n */\n isServer?: boolean;\n /**\n * Override specific options\n */\n overrides?: Partial<OptimizePluginOptions>;\n};\n\n/**\n * Load dictionaries from the dictionaries-entry package\n */\nconst loadDictionaries = (config: IntlayerConfig): Dictionary[] => {\n try {\n // Dynamic require to avoid build-time dependency issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getDictionaries } = require('@intlayer/dictionaries-entry');\n const dictionariesRecord = getDictionaries(config);\n\n return Object.values(dictionariesRecord);\n } catch {\n // If dictionaries-entry is not available, return empty array\n return [];\n }\n};\n\n/**\n * Get the options for the Intlayer Babel optimization plugin\n * This function loads the Intlayer configuration and returns the paths\n * needed for dictionary optimization and import rewriting.\n */\nexport const getOptimizePluginOptions = (\n params?: GetOptimizePluginOptionsParams\n): OptimizePluginOptions => {\n const {\n configOptions,\n dictionaries: providedDictionaries,\n isServer,\n overrides,\n } = params ?? {};\n\n const config = getConfiguration(configOptions);\n const {\n mainDir,\n dictionariesDir,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n } = config.system;\n const importMode = config.build.importMode ?? config.dictionary?.importMode;\n const optimize = config.build.optimize;\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n const dynamicDictionariesEntryPath = join(\n mainDir,\n 'dynamic_dictionaries.mjs'\n );\n const fetchDictionariesEntryPath = join(mainDir, 'fetch_dictionaries.mjs');\n\n const filesListPattern = buildComponentFilesList(config);\n\n const filesList = [\n ...filesListPattern,\n dictionariesEntryPath, // should add dictionariesEntryPath to replace it by an empty object if import made dynamic\n unmergedDictionariesEntryPath, // should add dictionariesEntryPath to replace it by an empty object if import made dynamic\n ];\n\n // Load dictionaries if not provided\n const dictionaries = providedDictionaries ?? loadDictionaries(config);\n\n const dictionaryModeMap: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n > = {};\n\n dictionaries.forEach((dictionary) => {\n dictionaryModeMap[dictionary.key] = dictionary.importMode ?? importMode;\n });\n\n return {\n optimize,\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesDir,\n unmergedDictionariesEntryPath,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n fetchDictionariesEntryPath,\n replaceDictionaryEntry: true,\n importMode,\n dictionaryModeMap,\n filesList,\n isServer,\n ...overrides,\n };\n};\n"],"mappings":";;;;;;;;;;AAkCA,MAAM,oBAAoB,WAAyC;AACjE,KAAI;EAGF,MAAM,EAAE,oBAAoB,QAAQ,+BAA+B;EACnE,MAAM,qBAAqB,gBAAgB,OAAO;AAElD,SAAO,OAAO,OAAO,mBAAmB;SAClC;AAEN,SAAO,EAAE;;;;;;;;AASb,MAAa,4BACX,WAC0B;CAC1B,MAAM,EACJ,eACA,cAAc,sBACd,UACA,cACE,UAAU,EAAE;CAEhB,MAAM,qDAA0B,cAAc;CAC9C,MAAM,EACJ,SACA,iBACA,yBACA,wBACA,yBACE,OAAO;CACX,MAAM,aAAa,OAAO,MAAM,cAAc,OAAO,YAAY;CACjE,MAAM,WAAW,OAAO,MAAM;CAE9B,MAAM,4CAA6B,SAAS,mBAAmB;CAC/D,MAAM,oDACJ,SACA,4BACD;CACD,MAAM,mDACJ,SACA,2BACD;CACD,MAAM,iDAAkC,SAAS,yBAAyB;CAI1E,MAAM,YAAY;EAChB,uDAH+C,OAG5B;EACnB;EACA;EACD;CAGD,MAAM,eAAe,wBAAwB,iBAAiB,OAAO;CAErE,MAAM,oBAGF,EAAE;AAEN,cAAa,SAAS,eAAe;AACnC,oBAAkB,WAAW,OAAO,WAAW,cAAc;GAC7D;AAEF,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,wBAAwB;EACxB;EACA;EACA;EACA;EACA,GAAG;EACJ"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
|
-
let _intlayer_chokidar_utils = require("@intlayer/chokidar/utils");
|
|
4
3
|
let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
|
|
5
4
|
let _intlayer_config_node = require("@intlayer/config/node");
|
|
5
|
+
let _intlayer_engine_utils = require("@intlayer/engine/utils");
|
|
6
6
|
|
|
7
7
|
//#region src/getPurgePluginOptions.ts
|
|
8
8
|
/**
|
|
@@ -49,7 +49,7 @@ const getPurgePluginOptions = (params) => {
|
|
|
49
49
|
const { purge, minify, optimize } = config.build;
|
|
50
50
|
const editorEnabled = config.editor.enabled;
|
|
51
51
|
const importMode = config.build.importMode ?? config.dictionary?.importMode;
|
|
52
|
-
const componentFilesList = (0,
|
|
52
|
+
const componentFilesList = (0, _intlayer_engine_utils.buildComponentFilesList)(config);
|
|
53
53
|
const dictionaries = providedDictionaries ?? loadDictionaries(config);
|
|
54
54
|
const dictionaryKeyToImportModeMap = {};
|
|
55
55
|
for (const dictionary of dictionaries) dictionaryKeyToImportModeMap[dictionary.key] = dictionary.importMode ?? importMode ?? _intlayer_config_defaultValues.IMPORT_MODE;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPurgePluginOptions.cjs","names":["IMPORT_MODE"],"sources":["../../src/getPurgePluginOptions.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"getPurgePluginOptions.cjs","names":["IMPORT_MODE"],"sources":["../../src/getPurgePluginOptions.ts"],"sourcesContent":["import { IMPORT_MODE } from '@intlayer/config/defaultValues';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { buildComponentFilesList } from '@intlayer/engine/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { MinifyPluginOptions } from './babel-plugin-intlayer-minify';\nimport type { PurgePluginOptions } from './babel-plugin-intlayer-purge';\n\n// ── Shared config helpers ─────────────────────────────────────────────────────\n\n/**\n * Attempts to load compiled dictionaries from `@intlayer/dictionaries-entry`.\n * Returns an empty array if the entry point is not available (e.g. dictionaries\n * have not been built yet).\n */\nconst loadDictionaries = (config: IntlayerConfig): Dictionary[] => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getDictionaries } = require('@intlayer/dictionaries-entry');\n const dictionariesRecord = getDictionaries(config) as Record<\n string,\n Dictionary\n >;\n return Object.values(dictionariesRecord);\n } catch {\n return [];\n }\n};\n\n// ── getPurgePluginOptions ─────────────────────────────────────────────────────\n\ntype GetPurgePluginOptionsParams = {\n /**\n * Options forwarded to the intlayer configuration loader.\n * Pass this when `intlayer.config.ts` lives outside the default search path\n * (e.g. in a monorepo workspace root).\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Pre-loaded dictionaries (optional – loaded automatically when omitted).\n * Providing them avoids a second `getDictionaries` call when you already\n * have them at hand.\n */\n dictionaries?: Dictionary[];\n\n /**\n * Override specific resolved option values after the defaults are computed.\n */\n overrides?: Partial<PurgePluginOptions>;\n};\n\n/**\n * Returns fully-resolved options for {@link intlayerPurgeBabelPlugin}.\n *\n * Loads the intlayer configuration once at babel.config.js evaluation time so\n * the plugin itself does not need to re-read the config on every file\n * transform.\n *\n * @example\n * ```js\n * // babel.config.js\n * const {\n * intlayerPurgeBabelPlugin,\n * getPurgePluginOptions,\n * } = require(\"@intlayer/babel\");\n *\n * module.exports = {\n * presets: [\"next/babel\"],\n * plugins: [\n * [intlayerPurgeBabelPlugin, getPurgePluginOptions()],\n * ],\n * };\n * ```\n */\nexport const getPurgePluginOptions = (\n params?: GetPurgePluginOptionsParams\n): PurgePluginOptions => {\n const {\n configOptions,\n dictionaries: providedDictionaries,\n overrides,\n } = params ?? {};\n\n const config = getConfiguration(configOptions);\n\n const { baseDir, dictionariesDir, dynamicDictionariesDir } = config.system;\n const { purge, minify, optimize } = config.build;\n const editorEnabled = config.editor.enabled;\n\n const importMode = config.build.importMode ?? config.dictionary?.importMode;\n\n const componentFilesList = buildComponentFilesList(config);\n\n const dictionaries = providedDictionaries ?? loadDictionaries(config);\n\n const dictionaryKeyToImportModeMap: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n > = {};\n for (const dictionary of dictionaries) {\n dictionaryKeyToImportModeMap[dictionary.key] =\n dictionary.importMode ?? importMode ?? IMPORT_MODE;\n }\n\n return {\n baseDir,\n purge: Boolean(purge),\n minify: Boolean(minify),\n optimize,\n editorEnabled,\n dictionariesDir,\n dynamicDictionariesDir,\n componentFilesList,\n dictionaryKeyToImportModeMap,\n ...overrides,\n };\n};\n\n// ── getMinifyPluginOptions ────────────────────────────────────────────────────\n\ntype GetMinifyPluginOptionsParams = {\n /**\n * Options forwarded to the intlayer configuration loader.\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Override specific resolved option values after the defaults are computed.\n */\n overrides?: Partial<MinifyPluginOptions>;\n};\n\n/**\n * Returns fully-resolved options for {@link intlayerMinifyBabelPlugin}.\n *\n * Loads the intlayer configuration once at babel.config.js evaluation time.\n *\n * @example\n * ```js\n * // babel.config.js\n * const {\n * intlayerMinifyBabelPlugin,\n * getMinifyPluginOptions,\n * } = require(\"@intlayer/babel\");\n *\n * module.exports = {\n * presets: [\"next/babel\"],\n * plugins: [\n * [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const getMinifyPluginOptions = (\n params?: GetMinifyPluginOptionsParams\n): MinifyPluginOptions => {\n const { configOptions, overrides } = params ?? {};\n\n const config = getConfiguration(configOptions);\n\n const { baseDir } = config.system;\n const { minify, optimize } = config.build;\n const editorEnabled = config.editor.enabled;\n\n return {\n baseDir,\n minify: Boolean(minify),\n optimize,\n editorEnabled,\n ...overrides,\n };\n};\n"],"mappings":";;;;;;;;;;;;AAkBA,MAAM,oBAAoB,WAAyC;AACjE,KAAI;EAEF,MAAM,EAAE,oBAAoB,QAAQ,+BAA+B;EACnE,MAAM,qBAAqB,gBAAgB,OAAO;AAIlD,SAAO,OAAO,OAAO,mBAAmB;SAClC;AACN,SAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDb,MAAa,yBACX,WACuB;CACvB,MAAM,EACJ,eACA,cAAc,sBACd,cACE,UAAU,EAAE;CAEhB,MAAM,qDAA0B,cAAc;CAE9C,MAAM,EAAE,SAAS,iBAAiB,2BAA2B,OAAO;CACpE,MAAM,EAAE,OAAO,QAAQ,aAAa,OAAO;CAC3C,MAAM,gBAAgB,OAAO,OAAO;CAEpC,MAAM,aAAa,OAAO,MAAM,cAAc,OAAO,YAAY;CAEjE,MAAM,yEAA6C,OAAO;CAE1D,MAAM,eAAe,wBAAwB,iBAAiB,OAAO;CAErE,MAAM,+BAGF,EAAE;AACN,MAAK,MAAM,cAAc,aACvB,8BAA6B,WAAW,OACtC,WAAW,cAAc,cAAcA;AAG3C,QAAO;EACL;EACA,OAAO,QAAQ,MAAM;EACrB,QAAQ,QAAQ,OAAO;EACvB;EACA;EACA;EACA;EACA;EACA;EACA,GAAG;EACJ;;;;;;;;;;;;;;;;;;;;;;;AAsCH,MAAa,0BACX,WACwB;CACxB,MAAM,EAAE,eAAe,cAAc,UAAU,EAAE;CAEjD,MAAM,qDAA0B,cAAc;CAE9C,MAAM,EAAE,YAAY,OAAO;CAC3B,MAAM,EAAE,QAAQ,aAAa,OAAO;CACpC,MAAM,gBAAgB,OAAO,OAAO;AAEpC,QAAO;EACL;EACA,QAAQ,QAAQ,OAAO;EACvB;EACA;EACA,GAAG;EACJ"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ exports.getOptimizePluginOptions = require_getOptimizePluginOptions.getOptimizeP
|
|
|
46
46
|
exports.getOutput = require_extractContent_utils_extractDictionaryInfo.getOutput;
|
|
47
47
|
exports.getPurgePluginOptions = require_getPurgePluginOptions.getPurgePluginOptions;
|
|
48
48
|
exports.getSharedPruneContext = require_babel_plugin_intlayer_purge.getSharedPruneContext;
|
|
49
|
+
exports.getUsageCheckRegex = require_transformers.getUsageCheckRegex;
|
|
49
50
|
exports.injectScriptBlocks = require_extractScriptBlocks.injectScriptBlocks;
|
|
50
51
|
exports.intlayerExtractBabelPlugin = require_babel_plugin_intlayer_extract.intlayerExtractBabelPlugin;
|
|
51
52
|
exports.intlayerMinifyBabelPlugin = require_babel_plugin_intlayer_minify.intlayerMinifyBabelPlugin;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
let _intlayer_config_utils = require("@intlayer/config/utils");
|
|
4
|
+
|
|
5
|
+
//#region src/normalizedFilesList.ts
|
|
6
|
+
/**
|
|
7
|
+
* Cache of normalized files-list sets, keyed by the files-list array
|
|
8
|
+
* reference. Babel reuses the same plugin options object for every file of a
|
|
9
|
+
* build, so the (potentially large) list is normalized once per build instead
|
|
10
|
+
* of once per transformed file.
|
|
11
|
+
*/
|
|
12
|
+
const normalizedFilesListCache = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
/**
|
|
14
|
+
* Returns a set of POSIX-normalized paths for the given files list, computed
|
|
15
|
+
* once per unique array reference.
|
|
16
|
+
*
|
|
17
|
+
* @param filesList - The plugin's `filesList` option (absolute file paths).
|
|
18
|
+
* @returns A set of the same paths normalized via `normalizePath`.
|
|
19
|
+
*/
|
|
20
|
+
const getNormalizedFilesListSet = (filesList) => {
|
|
21
|
+
let normalizedSet = normalizedFilesListCache.get(filesList);
|
|
22
|
+
if (!normalizedSet) {
|
|
23
|
+
normalizedSet = new Set(filesList.map(_intlayer_config_utils.normalizePath));
|
|
24
|
+
normalizedFilesListCache.set(filesList, normalizedSet);
|
|
25
|
+
}
|
|
26
|
+
return normalizedSet;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
exports.getNormalizedFilesListSet = getNormalizedFilesListSet;
|
|
31
|
+
//# sourceMappingURL=normalizedFilesList.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizedFilesList.cjs","names":["normalizePath"],"sources":["../../src/normalizedFilesList.ts"],"sourcesContent":["import { normalizePath } from '@intlayer/config/utils';\n\n/**\n * Cache of normalized files-list sets, keyed by the files-list array\n * reference. Babel reuses the same plugin options object for every file of a\n * build, so the (potentially large) list is normalized once per build instead\n * of once per transformed file.\n */\nconst normalizedFilesListCache = new WeakMap<readonly string[], Set<string>>();\n\n/**\n * Returns a set of POSIX-normalized paths for the given files list, computed\n * once per unique array reference.\n *\n * @param filesList - The plugin's `filesList` option (absolute file paths).\n * @returns A set of the same paths normalized via `normalizePath`.\n */\nexport const getNormalizedFilesListSet = (\n filesList: readonly string[]\n): Set<string> => {\n let normalizedSet = normalizedFilesListCache.get(filesList);\n\n if (!normalizedSet) {\n normalizedSet = new Set(filesList.map(normalizePath));\n normalizedFilesListCache.set(filesList, normalizedSet);\n }\n\n return normalizedSet;\n};\n"],"mappings":";;;;;;;;;;;AAQA,MAAM,2CAA2B,IAAI,SAAyC;;;;;;;;AAS9E,MAAa,6BACX,cACgB;CAChB,IAAI,gBAAgB,yBAAyB,IAAI,UAAU;AAE3D,KAAI,CAAC,eAAe;AAClB,kBAAgB,IAAI,IAAI,UAAU,IAAIA,qCAAc,CAAC;AACrD,2BAAyB,IAAI,WAAW,cAAc;;AAGxD,QAAO"}
|
|
@@ -58,6 +58,24 @@ const buildUsageCheckRegex = (extraCallerNames) => {
|
|
|
58
58
|
const uniqueNames = [...new Set(callerNames)];
|
|
59
59
|
return new RegExp(`\\b(${uniqueNames.join("|")})\\b`);
|
|
60
60
|
};
|
|
61
|
+
/** Usage-check regex covering only the native callers (no compat callers). */
|
|
62
|
+
const NATIVE_USAGE_CHECK_REGEX = buildUsageCheckRegex();
|
|
63
|
+
/** Cache of usage-check regexes, keyed by the compat-caller array reference. */
|
|
64
|
+
const usageCheckRegexCache = /* @__PURE__ */ new WeakMap();
|
|
65
|
+
/**
|
|
66
|
+
* Returns the usage-check regex for the given compat callers, memoised by the
|
|
67
|
+
* array reference. Plugins pass the same options array for every analysed
|
|
68
|
+
* file, so the regex is built once per build instead of once per file.
|
|
69
|
+
*/
|
|
70
|
+
const getUsageCheckRegex = (compatCallers) => {
|
|
71
|
+
if (!compatCallers || compatCallers.length === 0) return NATIVE_USAGE_CHECK_REGEX;
|
|
72
|
+
let usageCheckRegex = usageCheckRegexCache.get(compatCallers);
|
|
73
|
+
if (!usageCheckRegex) {
|
|
74
|
+
usageCheckRegex = buildUsageCheckRegex(compatCallers.map((caller) => caller.callerName));
|
|
75
|
+
usageCheckRegexCache.set(compatCallers, usageCheckRegex);
|
|
76
|
+
}
|
|
77
|
+
return usageCheckRegex;
|
|
78
|
+
};
|
|
61
79
|
/**
|
|
62
80
|
* Matches source files that are valid targets for usage analysis and Babel
|
|
63
81
|
* transformation. Excludes sourcemap files, declaration files, and other
|
|
@@ -92,7 +110,7 @@ const analyzeScriptContent = async (scriptContent, sourceFilePath, pruneContext,
|
|
|
92
110
|
* `pruneContext.hasUnparsableSourceFiles`).
|
|
93
111
|
*/
|
|
94
112
|
const analyzeFieldUsageInFile = async (sourceFilePath, code, pruneContext, compatCallers) => {
|
|
95
|
-
const usageCheckRegex =
|
|
113
|
+
const usageCheckRegex = getUsageCheckRegex(compatCallers);
|
|
96
114
|
const scriptBlocks = require_extractScriptBlocks.extractScriptBlocks(sourceFilePath, code);
|
|
97
115
|
for (const block of scriptBlocks) {
|
|
98
116
|
if (!usageCheckRegex.test(block.content)) continue;
|
|
@@ -170,6 +188,7 @@ exports.INTLAYER_USAGE_REGEX = INTLAYER_USAGE_REGEX;
|
|
|
170
188
|
exports.SOURCE_FILE_REGEX = SOURCE_FILE_REGEX;
|
|
171
189
|
exports.analyzeFieldUsageInFile = analyzeFieldUsageInFile;
|
|
172
190
|
exports.buildUsageCheckRegex = buildUsageCheckRegex;
|
|
191
|
+
exports.getUsageCheckRegex = getUsageCheckRegex;
|
|
173
192
|
exports.optimizeSourceFile = optimizeSourceFile;
|
|
174
193
|
exports.renameFieldsInCode = renameFieldsInCode;
|
|
175
194
|
exports.renameFieldsInSourceFile = renameFieldsInSourceFile;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformers.cjs","names":["makeUsageAnalyzerBabelPlugin","extractScriptBlocks","makeFieldRenameBabelPlugin","injectScriptBlocks","intlayerOptimizeBabelPlugin"],"sources":["../../src/transformers.ts"],"sourcesContent":["import { type TransformOptions, transformAsync } from '@babel/core';\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 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: NonNullable<TransformOptions['parserOpts']> =\n {\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 * Fast pre-check: matches files that could contain native intlayer calls\n * (`useIntlayer` / `getIntlayer`). Used by the optimize/transform pass, which\n * only rewrites native calls.\n */\nexport const INTLAYER_USAGE_REGEX = /\\b(use|get)Intlayer\\b/;\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 * 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 = [\n 'useIntlayer',\n 'getIntlayer',\n ...(extraCallerNames ?? []),\n ];\n const uniqueNames = [...new Set(callerNames)];\n return new RegExp(`\\\\b(${uniqueNames.join('|')})\\\\b`);\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 extraCallerNames = (compatCallers ?? []).map(\n (caller) => caller.callerName\n );\n const usageCheckRegex = buildUsageCheckRegex(extraCallerNames);\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":";;;;;;;;;;;;;AAmBA,MAAa,uBACX;CACE,YAAY;CACZ,6BAA6B;CAC7B,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;CACF;;;;;;AAOH,MAAa,uBAAuB;;;;;;;;;;;;;;;AAgBpC,MAAa,wBAAwB,qBAAwC;CAC3E,MAAM,cAAc;EAClB;EACA;EACA,GAAI,oBAAoB,EAAE;EAC3B;CACD,MAAM,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC;AAC7C,QAAO,IAAI,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,MAAM;;;;;;;AAQvD,MAAa,oBAAoB;;;;;;;AAUjC,MAAM,uBAAuB,OAC3B,eACA,gBACA,cACA,kBACkB;AAClB,uCAAqB,eAAe;EAClC,UAAU;EACV,SAAS,CAACA,0EAA6B,cAAc,EAAE,eAAe,CAAC,CAAC;EACxE,YAAY;EACZ,KAAK;EACL,MAAM;EACP,CAAC;;;;;;;;;;;;;;AAeJ,MAAa,0BAA0B,OACrC,gBACA,MACA,cACA,kBACkB;CAIlB,MAAM,kBAAkB,sBAHE,iBAAiB,EAAE,EAAE,KAC5C,WAAW,OAAO,WAEwC,CAAC;CAC9D,MAAM,eAAeC,gDAAoB,gBAAgB,KAAK;AAM9D,MAAK,MAAM,SAAS,cAAc;AAChC,MAAI,CAAC,gBAAgB,KAAK,MAAM,QAAQ,CAAE;AAC1C,QAAM,qBACJ,MAAM,SACN,gBACA,cACA,cACD;;;;;;;;;AAUL,MAAa,qBAAqB,OAChC,MACA,gBACA,iBAC2B;AAC3B,KAAI;AAOF,UAAO,sCAN6B,MAAM;GACxC,UAAU;GACV,SAAS,CAACC,sEAA2B,aAAa,CAAC;GACnD,YAAY;GACZ,KAAK;GACN,CAAC,GACa,QAAQ;SACjB;AACN,SAAO;;;;;;;;;;AAWX,MAAa,2BAA2B,OACtC,gBACA,MACA,iBAC2B;AAC3B,KAAI,aAAa,8BAA8B,SAAS,EAAG,QAAO;AAClE,KAAI,CAAC,qBAAqB,KAAK,KAAK,CAAE,QAAO;CAE7C,MAAM,eAAeD,gDAAoB,gBAAgB,KAAK;AAM9D,KAHE,aAAa,SAAS,OACpB,aAAa,IAAI,sBAAsB,KAAK,KAAK,aAAa,SAAS,IAEhE;EAET,MAAM,gBAGD,EAAE;AAEP,OAAK,MAAM,SAAS,cAAc;AAChC,OAAI,CAAC,qBAAqB,KAAK,MAAM,QAAQ,CAAE;GAE/C,MAAM,cAAc,MAAM,mBACxB,MAAM,SACN,gBACA,aACD;AACD,OAAI,eAAe,gBAAgB,MAAM,QACvC,eAAc,KAAK;IAAE;IAAO,iBAAiB;IAAa,CAAC;;AAI/D,MAAI,cAAc,WAAW,EAAG,QAAO;AACvC,SAAOE,+CAAmB,MAAM,cAAc;;AAIhD,QAAO,mBAAmB,MAAM,gBAAgB,aAAa;;;;;;;;;;AAW/D,MAAa,qBAAqB,OAChC,MACA,gBACA,YAIW;CACX,MAAM,SAAS,sCAAqB,MAAM;EACxC,UAAU;EACV,SAAS,CAAC,CAACC,oEAA6B,QAAQ,CAAC;EACjD,YAAY;EACb,CAAC;AAEF,KAAI,CAAC,QAAQ,KAAM,QAAO;AAE1B,QAAO;EAAE,MAAM,OAAO;EAAM,KAAK,OAAO;EAAK"}
|
|
1
|
+
{"version":3,"file":"transformers.cjs","names":["makeUsageAnalyzerBabelPlugin","extractScriptBlocks","makeFieldRenameBabelPlugin","injectScriptBlocks","intlayerOptimizeBabelPlugin"],"sources":["../../src/transformers.ts"],"sourcesContent":["import { type TransformOptions, transformAsync } from '@babel/core';\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 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: NonNullable<TransformOptions['parserOpts']> =\n {\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 * Fast pre-check: matches files that could contain native intlayer calls\n * (`useIntlayer` / `getIntlayer`). Used by the optimize/transform pass, which\n * only rewrites native calls.\n */\nexport const INTLAYER_USAGE_REGEX = /\\b(use|get)Intlayer\\b/;\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 * 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 = [\n 'useIntlayer',\n 'getIntlayer',\n ...(extraCallerNames ?? []),\n ];\n const uniqueNames = [...new Set(callerNames)];\n return new RegExp(`\\\\b(${uniqueNames.join('|')})\\\\b`);\n};\n\n/** Usage-check regex covering only the native callers (no compat callers). */\nconst NATIVE_USAGE_CHECK_REGEX = buildUsageCheckRegex();\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":";;;;;;;;;;;;;AAmBA,MAAa,uBACX;CACE,YAAY;CACZ,6BAA6B;CAC7B,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;CACF;;;;;;AAOH,MAAa,uBAAuB;;;;;;;;;;;;;;;AAgBpC,MAAa,wBAAwB,qBAAwC;CAC3E,MAAM,cAAc;EAClB;EACA;EACA,GAAI,oBAAoB,EAAE;EAC3B;CACD,MAAM,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC;AAC7C,QAAO,IAAI,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,MAAM;;;AAIvD,MAAM,2BAA2B,sBAAsB;;AAGvD,MAAM,uCAAuB,IAAI,SAG9B;;;;;;AAOH,MAAa,sBACX,kBACW;AACX,KAAI,CAAC,iBAAiB,cAAc,WAAW,EAC7C,QAAO;CAGT,IAAI,kBAAkB,qBAAqB,IAAI,cAAc;AAC7D,KAAI,CAAC,iBAAiB;AACpB,oBAAkB,qBAChB,cAAc,KAAK,WAAW,OAAO,WAAW,CACjD;AACD,uBAAqB,IAAI,eAAe,gBAAgB;;AAE1D,QAAO;;;;;;;AAQT,MAAa,oBAAoB;;;;;;;AAUjC,MAAM,uBAAuB,OAC3B,eACA,gBACA,cACA,kBACkB;AAClB,uCAAqB,eAAe;EAClC,UAAU;EACV,SAAS,CAACA,0EAA6B,cAAc,EAAE,eAAe,CAAC,CAAC;EACxE,YAAY;EACZ,KAAK;EACL,MAAM;EACP,CAAC;;;;;;;;;;;;;;AAeJ,MAAa,0BAA0B,OACrC,gBACA,MACA,cACA,kBACkB;CAClB,MAAM,kBAAkB,mBAAmB,cAAc;CACzD,MAAM,eAAeC,gDAAoB,gBAAgB,KAAK;AAM9D,MAAK,MAAM,SAAS,cAAc;AAChC,MAAI,CAAC,gBAAgB,KAAK,MAAM,QAAQ,CAAE;AAC1C,QAAM,qBACJ,MAAM,SACN,gBACA,cACA,cACD;;;;;;;;;AAUL,MAAa,qBAAqB,OAChC,MACA,gBACA,iBAC2B;AAC3B,KAAI;AAOF,UAAO,sCAN6B,MAAM;GACxC,UAAU;GACV,SAAS,CAACC,sEAA2B,aAAa,CAAC;GACnD,YAAY;GACZ,KAAK;GACN,CAAC,GACa,QAAQ;SACjB;AACN,SAAO;;;;;;;;;;AAWX,MAAa,2BAA2B,OACtC,gBACA,MACA,iBAC2B;AAC3B,KAAI,aAAa,8BAA8B,SAAS,EAAG,QAAO;AAClE,KAAI,CAAC,qBAAqB,KAAK,KAAK,CAAE,QAAO;CAE7C,MAAM,eAAeD,gDAAoB,gBAAgB,KAAK;AAM9D,KAHE,aAAa,SAAS,OACpB,aAAa,IAAI,sBAAsB,KAAK,KAAK,aAAa,SAAS,IAEhE;EAET,MAAM,gBAGD,EAAE;AAEP,OAAK,MAAM,SAAS,cAAc;AAChC,OAAI,CAAC,qBAAqB,KAAK,MAAM,QAAQ,CAAE;GAE/C,MAAM,cAAc,MAAM,mBACxB,MAAM,SACN,gBACA,aACD;AACD,OAAI,eAAe,gBAAgB,MAAM,QACvC,eAAc,KAAK;IAAE;IAAO,iBAAiB;IAAa,CAAC;;AAI/D,MAAI,cAAc,WAAW,EAAG,QAAO;AACvC,SAAOE,+CAAmB,MAAM,cAAc;;AAIhD,QAAO,mBAAmB,MAAM,gBAAgB,aAAa;;;;;;;;;;AAW/D,MAAa,qBAAqB,OAChC,MACA,gBACA,YAIW;CACX,MAAM,SAAS,sCAAqB,MAAM;EACxC,UAAU;EACV,SAAS,CAAC,CAACC,oEAA6B,QAAQ,CAAC;EACjD,YAAY;EACb,CAAC;AAEF,KAAI,CAAC,QAAQ,KAAM,QAAO;AAE1B,QAAO;EAAE,MAAM,OAAO;EAAM,KAAK,OAAO;EAAK"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { detectPackageName } from "./extractContent/utils/detectPackageName.mjs";
|
|
2
2
|
import { extractContentSync } from "./extractContent/extractContent.mjs";
|
|
3
|
+
import { getNormalizedFilesListSet } from "./normalizedFilesList.mjs";
|
|
3
4
|
import { relative } from "node:path";
|
|
4
5
|
import * as ANSIColors from "@intlayer/config/colors";
|
|
5
6
|
import { colorize, colorizePath, getAppLogger } from "@intlayer/config/logger";
|
|
@@ -32,7 +33,7 @@ const intlayerExtractBabelPlugin = (_babel) => {
|
|
|
32
33
|
if (opts.enabled === false) return;
|
|
33
34
|
const filename = state.file.opts.filename;
|
|
34
35
|
if (!filename) return;
|
|
35
|
-
if (opts.filesList && !opts.filesList
|
|
36
|
+
if (opts.filesList && !getNormalizedFilesListSet(opts.filesList).has(normalizePath(filename))) return;
|
|
36
37
|
const fileCode = state.file.code ?? "";
|
|
37
38
|
if (!fileCode) return;
|
|
38
39
|
const appLogger = getAppLogger(opts.configuration);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport type { 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';\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 !opts.filesList
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport type { 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;AACzB,QAAO;EACL,MAAM;EAEN,SAAS,EACP,SAAS,EACP,MAAM,aAAa,OAAO;GACxB,MAAM,OAAO,MAAM;AAKnB,OAFkB,KAAK,YAEL,MAAO;GAEzB,MAAM,WAAW,MAAM,KAAK,KAAK;AAEjC,OAAI,CAAC,SAAU;AAGf,OACE,KAAK,aACL,CAAC,0BAA0B,KAAK,UAAU,CAAC,IACzC,cAAc,SAAS,CACxB,CAED;GAGF,MAAM,WAAmB,MAAM,KAAK,QAAQ;AAC5C,OAAI,CAAC,SAAU;GAEf,MAAM,YAAY,aAAa,KAAK,cAAc;GAClD,MAAM,cAAc,KAAK,eAAe,kBAAkB,SAAS;GAEnE,MAAM,EAAE,mBAAmB,KAAK,cAAc;GAE9C,MAAM,SAAS,mBAAmB,UAAU,aAAa;IACvD,eAAe,KAAK;IACpB,MAAM;IACN,YAAY,kBAGN;AACJ,SAAI,KAAK,UACP,MAAK,UAAU;MACb,eAAe,cAAc;MAC7B,UAAU;MACV,SAAS,cAAc;MACvB,QAAQ,KAAK,cAAc,qBAAqB;MACjD,CAAC;;IAGN,iBAAiB,CAAC;IACnB,CAAC;AAEF,OAAI,CAAC,OAAQ;GAEb,MAAM,EAAE,iBAAiB,iBAAiB;AAE1C,OAAI,CAAC,aAAc;AAKnB,OAAI;IACF,MAAM,SAAS,MAAM,cAAc;KACjC,YAAY;KACZ,SAAS,CAAC,OAAO,aAAa;KAC/B,CAAC;AAEF,gBAAY,KAAK,OAAO,OAAO,QAAQ;AACvC,gBAAY,KAAK,aAAa,OAAO,QAAQ;AAE7C,cACE,GAAG,SAAS,aAAa,WAAW,UAAU,CAAC,0BAA0B,aAAa,SAAS,KAAK,cAAc,OAAO,SAAS,SAAS,CAAC,IAC5I,EAAE,OAAO,SAAS,CACnB;YACM,OAAO;AACd,cACE,CACE,wCAAwC,aAAa,SAAS,KAAK,cAAc,OAAO,SAAS,SAAS,CAAC,CAAC,IAC5G,MACD,EACD,EAAE,OAAO,SAAS,CACnB;;KAGN,EACF;EACF"}
|
|
@@ -7,15 +7,16 @@ import { INTLAYER_CALLER_NAMES } from "./babel-plugin-intlayer-usage-analyzer.mj
|
|
|
7
7
|
* "translation", … }`) and are read by the intlayer runtime.
|
|
8
8
|
*/
|
|
9
9
|
const RESERVED_CONTENT_FIELD_NAMES = new Set(["nodeType"]);
|
|
10
|
+
/** Alphabet used to derive short field aliases (`a`, `b`, …, `aa`, `ab`, …). */
|
|
11
|
+
const SHORT_NAME_ALPHABET = "abcdefghijklmnopqrstuvwxyz";
|
|
10
12
|
/**
|
|
11
13
|
* Converts a zero-based index to a short alphabetic identifier.
|
|
12
14
|
* 0 → 'a', 1 → 'b', …, 25 → 'z', 26 → 'aa', 27 → 'ab', …
|
|
13
15
|
*/
|
|
14
16
|
const generateShortFieldName = (index) => {
|
|
15
|
-
const ALPHABET = "abcdefghijklmnopqrstuvwxyz";
|
|
16
17
|
const remainder = index % 26;
|
|
17
18
|
const quotient = Math.floor(index / 26);
|
|
18
|
-
return quotient === 0 &&
|
|
19
|
+
return quotient === 0 && SHORT_NAME_ALPHABET[remainder] ? SHORT_NAME_ALPHABET[remainder] : generateShortFieldName(quotient - 1) + SHORT_NAME_ALPHABET[remainder];
|
|
19
20
|
};
|
|
20
21
|
/**
|
|
21
22
|
* Recursively builds a `NestedRenameMap` from a compiled dictionary content
|