@intlayer/babel 8.9.5 → 8.9.6-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,7 @@ const resolveContentFilePaths = async (filePath, componentKey, configuration, lo
35
35
  if (existingDicts?.[0]?.filePath) {
36
36
  const existingPath = existingDicts[0].filePath;
37
37
  const resolvedAbsolutePath = (0, node_path.resolve)(baseDir, existingPath);
38
+ (0, _intlayer_config_utils.assertPathWithin)(resolvedAbsolutePath, baseDir);
38
39
  return {
39
40
  absolutePath: resolvedAbsolutePath,
40
41
  relativePath: (0, node_path.relative)(baseDir, resolvedAbsolutePath),
@@ -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 {\n getFormatFromExtension,\n resolveRelativePath,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\nimport { parseStringPattern } from '@intlayer/config/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 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],\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;CAEvC,IAAI,WAAW,UAAa,WAAW,MACrC,MAAM,IAAI,MACR,8EAAiD,mBAAmBA,wBAAW,KAAK,CAAC,yBACtF;CAGH,IAAI,WAAW,OAAO,OAAO;CAG7B,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,YAAY;EAC9D,MAAM,QAAQ,SACT,OAAqD,UACtD;EACJ,IAAI,UAAU,OAAO,OAAO;EAC5B,IAAI,UAAU,UAAa,UAAU,MACnC,MAAM,IAAI,MACR,4CAA4C,OAAO,uBACpD;EAEH,OAAO,OAAO,UAAU,YACnB,2DACoB,OAAiB,QAAQ,GAC7C;;CAGP,IAAI,OAAO,WAAW,UACpB,QAAQ,2DACa,QAAQ,QAAQ;CAGvC,IAAI,OAAO,WAAW,YACpB,OAAO;CAGT,MAAM,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;CAEH,IAAI,gBAAgB,IAAI,UAAU;EAChC,MAAM,eAAe,cAAc,GAAG;EACtC,MAAM,8CAA+B,SAAS,aAAa;EAE3D,OAAO;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,uEACJ,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;EACjD;CAGD,IAAI,gBAAgB;EAClB,MAAM,UAAU,UAAU,eAAe,aAAa;EACtD,IAAI,YAAY,OACd,MAAM,IAAI,MACR,2CAA2C,aAAa,IACzD;EAGH,MAAM,iEACJ,MAF4B,QAAQ,QAAQ,EAG5C,UACA,QACD;EACD,OAAO;GACL;GACA,sCAAuB,SAAS,aAAa;GAC7C,aAAa;GACd;;CAIH,MAAM,UAAU,UAAU,cAAc;CACxC,IAAI,YAAY,OACd,MAAM,IAAI,MACR,8EAAiD,mBAAmBA,wBAAW,KAAK,CAAC,yBACtF;CAMH,MAAM,iEAAmC,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;CAE/D,OAAO;EACL;EACA,sCAAuB,SAAS,aAAa;EAC7C;EACD;;;;;AAUH,MAAa,wBAAwB,OACnC,UACA,UACA,kBAKG;CACH,MAAM,gBAAgBC,uEAAqB,UAAU,SAAS;CAQ9D,OAAO;EACL;EACA,GAAG,MARuB,wBAC1B,UACA,eACA,cACD;EAKA"}
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 {\n getFormatFromExtension,\n resolveRelativePath,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\nimport { assertPathWithin, parseStringPattern } from '@intlayer/config/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],\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;CAEvC,IAAI,WAAW,UAAa,WAAW,MACrC,MAAM,IAAI,MACR,8EAAiD,mBAAmBA,wBAAW,KAAK,CAAC,yBACtF;CAGH,IAAI,WAAW,OAAO,OAAO;CAG7B,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,YAAY;EAC9D,MAAM,QAAQ,SACT,OAAqD,UACtD;EACJ,IAAI,UAAU,OAAO,OAAO;EAC5B,IAAI,UAAU,UAAa,UAAU,MACnC,MAAM,IAAI,MACR,4CAA4C,OAAO,uBACpD;EAEH,OAAO,OAAO,UAAU,YACnB,2DACoB,OAAiB,QAAQ,GAC7C;;CAGP,IAAI,OAAO,WAAW,UACpB,QAAQ,2DACa,QAAQ,QAAQ;CAGvC,IAAI,OAAO,WAAW,YACpB,OAAO;CAGT,MAAM,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;CAEH,IAAI,gBAAgB,IAAI,UAAU;EAChC,MAAM,eAAe,cAAc,GAAG;EACtC,MAAM,8CAA+B,SAAS,aAAa;EAE3D,6CAAiB,sBAAsB,QAAQ;EAE/C,OAAO;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,uEACJ,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;EACjD;CAGD,IAAI,gBAAgB;EAClB,MAAM,UAAU,UAAU,eAAe,aAAa;EACtD,IAAI,YAAY,OACd,MAAM,IAAI,MACR,2CAA2C,aAAa,IACzD;EAGH,MAAM,iEACJ,MAF4B,QAAQ,QAAQ,EAG5C,UACA,QACD;EACD,OAAO;GACL;GACA,sCAAuB,SAAS,aAAa;GAC7C,aAAa;GACd;;CAIH,MAAM,UAAU,UAAU,cAAc;CACxC,IAAI,YAAY,OACd,MAAM,IAAI,MACR,8EAAiD,mBAAmBA,wBAAW,KAAK,CAAC,yBACtF;CAMH,MAAM,iEAAmC,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;CAE/D,OAAO;EACL;EACA,sCAAuB,SAAS,aAAa;EAC7C;EACD;;;;;AAUH,MAAa,wBAAwB,OACnC,UACA,UACA,kBAKG;CACH,MAAM,gBAAgBC,uEAAqB,UAAU,SAAS;CAQ9D,OAAO;EACL;EACA,GAAG,MARuB,wBAC1B,UACA,eACA,cACD;EAKA"}
@@ -2,6 +2,7 @@ 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
4
  let node_fs = require("node:fs");
5
+ let _intlayer_config_utils = require("@intlayer/config/utils");
5
6
  let _intlayer_unmerged_dictionaries_entry = require("@intlayer/unmerged-dictionaries-entry");
6
7
 
7
8
  //#region src/extractContent/utils/resolveDictionaryKey.ts
@@ -21,6 +22,7 @@ const resolveDictionaryKey = (initialKey, filePath, configuration, unmergedDicti
21
22
  const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;
22
23
  const dictionaries = dicts[keyToTest];
23
24
  const contentFilePath = (0, node_path.join)(dirName, `${keyToTest}${extension}`);
25
+ (0, _intlayer_config_utils.assertPathWithin)((0, node_path.resolve)(contentFilePath), dirName);
24
26
  const isKeyUsed = usedKeys.has(keyToTest);
25
27
  const hasDictionaries = dictionaries && dictionaries.length > 0;
26
28
  const fileExists = (0, node_fs.existsSync)(contentFilePath);
@@ -1 +1 @@
1
- {"version":3,"file":"resolveDictionaryKey.cjs","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\n\n/**\n * Resolves a unique dictionary key, checking for existing dictionaries and files.\n * Note: this chokidar-specific variant fetches unmergedDictionaries internally\n * from the configuration (unlike the `@intlayer/babel` version which takes it as a parameter).\n */\nexport const resolveDictionaryKey = (\n initialKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n unmergedDictionaries?: Record<string, unknown>,\n usedKeys: Set<string> = new Set()\n): string => {\n const dicts =\n unmergedDictionaries ?? getUnmergedDictionaries(configuration) ?? {};\n\n const { fileExtensions } = configuration.content;\n\n const dirName = dirname(filePath);\n const firstExtension = fileExtensions[0];\n const extension = firstExtension.startsWith('.')\n ? firstExtension\n : `.${firstExtension}`;\n\n let index = 0;\n\n while (index < 100) {\n const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;\n const dictionaries = dicts[keyToTest] as Dictionary[] | undefined;\n const contentFilePath = join(dirName, `${keyToTest}${extension}`);\n const isKeyUsed = usedKeys.has(keyToTest);\n const hasDictionaries = dictionaries && dictionaries.length > 0;\n const fileExists = existsSync(contentFilePath);\n\n if (!isKeyUsed && !hasDictionaries && !fileExists) {\n return keyToTest;\n }\n index++;\n }\n\n return initialKey;\n};\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,wBACX,YACA,UACA,eACA,sBACA,2BAAwB,IAAI,KAAK,KACtB;CACX,MAAM,QACJ,2FAAgD,cAAc,IAAI,EAAE;CAEtE,MAAM,EAAE,mBAAmB,cAAc;CAEzC,MAAM,iCAAkB,SAAS;CACjC,MAAM,iBAAiB,eAAe;CACtC,MAAM,YAAY,eAAe,WAAW,IAAI,GAC5C,iBACA,IAAI;CAER,IAAI,QAAQ;CAEZ,OAAO,QAAQ,KAAK;EAClB,MAAM,YAAY,UAAU,IAAI,aAAa,GAAG,aAAa;EAC7D,MAAM,eAAe,MAAM;EAC3B,MAAM,sCAAuB,SAAS,GAAG,YAAY,YAAY;EACjE,MAAM,YAAY,SAAS,IAAI,UAAU;EACzC,MAAM,kBAAkB,gBAAgB,aAAa,SAAS;EAC9D,MAAM,qCAAwB,gBAAgB;EAE9C,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,YACrC,OAAO;EAET;;CAGF,OAAO"}
1
+ {"version":3,"file":"resolveDictionaryKey.cjs","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { assertPathWithin } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\n\n/**\n * Resolves a unique dictionary key, checking for existing dictionaries and files.\n * Note: this chokidar-specific variant fetches unmergedDictionaries internally\n * from the configuration (unlike the `@intlayer/babel` version which takes it as a parameter).\n */\nexport const resolveDictionaryKey = (\n initialKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n unmergedDictionaries?: Record<string, unknown>,\n usedKeys: Set<string> = new Set()\n): string => {\n const dicts =\n unmergedDictionaries ?? getUnmergedDictionaries(configuration) ?? {};\n\n const { fileExtensions } = configuration.content;\n\n const dirName = dirname(filePath);\n const firstExtension = fileExtensions[0];\n const extension = firstExtension.startsWith('.')\n ? firstExtension\n : `.${firstExtension}`;\n\n let index = 0;\n\n while (index < 100) {\n const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;\n const dictionaries = dicts[keyToTest] as Dictionary[] | undefined;\n const contentFilePath = join(dirName, `${keyToTest}${extension}`);\n\n assertPathWithin(resolve(contentFilePath), dirName);\n\n const isKeyUsed = usedKeys.has(keyToTest);\n const hasDictionaries = dictionaries && dictionaries.length > 0;\n const fileExists = existsSync(contentFilePath);\n\n if (!isKeyUsed && !hasDictionaries && !fileExists) {\n return keyToTest;\n }\n index++;\n }\n\n return initialKey;\n};\n"],"mappings":";;;;;;;;;;;;;AAYA,MAAa,wBACX,YACA,UACA,eACA,sBACA,2BAAwB,IAAI,KAAK,KACtB;CACX,MAAM,QACJ,2FAAgD,cAAc,IAAI,EAAE;CAEtE,MAAM,EAAE,mBAAmB,cAAc;CAEzC,MAAM,iCAAkB,SAAS;CACjC,MAAM,iBAAiB,eAAe;CACtC,MAAM,YAAY,eAAe,WAAW,IAAI,GAC5C,iBACA,IAAI;CAER,IAAI,QAAQ;CAEZ,OAAO,QAAQ,KAAK;EAClB,MAAM,YAAY,UAAU,IAAI,aAAa,GAAG,aAAa;EAC7D,MAAM,eAAe,MAAM;EAC3B,MAAM,sCAAuB,SAAS,GAAG,YAAY,YAAY;EAEjE,oEAAyB,gBAAgB,EAAE,QAAQ;EAEnD,MAAM,YAAY,SAAS,IAAI,UAAU;EACzC,MAAM,kBAAkB,gBAAgB,aAAa,SAAS;EAC9D,MAAM,qCAAwB,gBAAgB;EAE9C,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,YACrC,OAAO;EAET;;CAGF,OAAO"}
@@ -3,7 +3,7 @@ import { basename, dirname, extname, relative, resolve } from "node:path";
3
3
  import { getFormatFromExtension, resolveRelativePath } from "@intlayer/chokidar/utils";
4
4
  import * as ANSIColors from "@intlayer/config/colors";
5
5
  import { colorize } from "@intlayer/config/logger";
6
- import { parseStringPattern } from "@intlayer/config/utils";
6
+ import { assertPathWithin, parseStringPattern } from "@intlayer/config/utils";
7
7
  import { getUnmergedDictionaries } from "@intlayer/unmerged-dictionaries-entry";
8
8
 
9
9
  //#region src/extractContent/utils/extractDictionaryInfo.ts
@@ -32,6 +32,7 @@ const resolveContentFilePaths = async (filePath, componentKey, configuration, lo
32
32
  if (existingDicts?.[0]?.filePath) {
33
33
  const existingPath = existingDicts[0].filePath;
34
34
  const resolvedAbsolutePath = resolve(baseDir, existingPath);
35
+ assertPathWithin(resolvedAbsolutePath, baseDir);
35
36
  return {
36
37
  absolutePath: resolvedAbsolutePath,
37
38
  relativePath: relative(baseDir, resolvedAbsolutePath),
@@ -1 +1 @@
1
- {"version":3,"file":"extractDictionaryInfo.mjs","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"sourcesContent":["import { basename, dirname, extname, relative, resolve } from 'node:path';\nimport {\n getFormatFromExtension,\n resolveRelativePath,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\nimport { parseStringPattern } from '@intlayer/config/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 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],\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":"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"}
1
+ {"version":3,"file":"extractDictionaryInfo.mjs","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"sourcesContent":["import { basename, dirname, extname, relative, resolve } from 'node:path';\nimport {\n getFormatFromExtension,\n resolveRelativePath,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\nimport { assertPathWithin, parseStringPattern } from '@intlayer/config/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],\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;CAEvC,IAAI,WAAW,UAAa,WAAW,MACrC,MAAM,IAAI,MACR,wCAAwC,SAAS,mBAAmB,WAAW,KAAK,CAAC,yBACtF;CAGH,IAAI,WAAW,OAAO,OAAO;CAG7B,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,YAAY;EAC9D,MAAM,QAAQ,SACT,OAAqD,UACtD;EACJ,IAAI,UAAU,OAAO,OAAO;EAC5B,IAAI,UAAU,UAAa,UAAU,MACnC,MAAM,IAAI,MACR,4CAA4C,OAAO,uBACpD;EAEH,OAAO,OAAO,UAAU,YACnB,YACC,mBAAmB,OAAiB,QAAQ,GAC7C;;CAGP,IAAI,OAAO,WAAW,UACpB,QAAQ,YACN,mBAAmB,QAAQ,QAAQ;CAGvC,IAAI,OAAO,WAAW,YACpB,OAAO;CAGT,MAAM,IAAI,MACR,wCAAwC,SAAS,mBAAmB,WAAW,KAAK,CAAC,yBACtF;;;;;;AAaH,MAAa,0BAA0B,OACrC,UACA,cACA,eACA,WACqC;CACrC,MAAM,EAAE,YAAY,cAAc;CAClC,MAAM,EAAE,kBAAkB,cAAc;CAGxC,MAAM,iBADuB,wBAAwB,cAAc,IAAI,EAAE,EAC9B,eACvC,QACC,eAEC,WAAW,aAAa,SAC3B,CACA,QACE,eAEC,WAAW,WAAW,UACtB,WAAW,YAAY,UAAU,eACpC;CAEH,IAAI,gBAAgB,IAAI,UAAU;EAChC,MAAM,eAAe,cAAc,GAAG;EACtC,MAAM,uBAAuB,QAAQ,SAAS,aAAa;EAE3D,iBAAiB,sBAAsB,QAAQ;EAE/C,OAAO;GACL,cAAc;GACd,cAAc,SAAS,SAAS,qBAAqB;GACrD,aAAa;GACd;;CAGH,MAAM,SAAS,cAAc,UAAU;CACvC,MAAM,iBACJ,OAAO,WAAW,YAClB,WAAW,QACX,OAAO,WAAW;CAGpB,MAAM,YAAY,QAChB,SACD;CACD,MAAM,gBAAgB,SAAS,UAAU,UAAU;CACnD,MAAM,oBACJ,cAAc,OAAO,EAAE,CAAC,aAAa,GAAG,cAAc,MAAM,EAAE;CAChE,MAAM,kBAAkB,uBACtB,UACD;CAED,MAAM,eAAgB,UAAU;CAEhC,MAAM,UAAkC;EACtC,KAAK;EACL,kBAAkB,SAAS,SAAS,QAAQ,SAAS,CAAC;EACtD,mBAAmB;EACnB,UAAU;EACV;EACA,oBAAoB;EACpB,QAAQ;EACR,QAAQ;EACR,WAAW,cAAc,QAAQ,eAAe;EACjD;CAGD,IAAI,gBAAgB;EAClB,MAAM,UAAU,UAAU,eAAe,aAAa;EACtD,IAAI,YAAY,OACd,MAAM,IAAI,MACR,2CAA2C,aAAa,IACzD;EAGH,MAAM,eAAe,oBACnB,MAF4B,QAAQ,QAAQ,EAG5C,UACA,QACD;EACD,OAAO;GACL;GACA,cAAc,SAAS,SAAS,aAAa;GAC7C,aAAa;GACd;;CAIH,MAAM,UAAU,UAAU,cAAc;CACxC,IAAI,YAAY,OACd,MAAM,IAAI,MACR,wCAAwC,SAAS,mBAAmB,WAAW,KAAK,CAAC,yBACtF;CAMH,MAAM,eAAe,oBAAoB,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;CAE/D,OAAO;EACL;EACA,cAAc,SAAS,SAAS,aAAa;EAC7C;EACD;;;;;AAUH,MAAa,wBAAwB,OACnC,UACA,UACA,kBAKG;CACH,MAAM,gBAAgB,qBAAqB,UAAU,SAAS;CAQ9D,OAAO;EACL;EACA,GAAG,MARuB,wBAC1B,UACA,eACA,cACD;EAKA"}
@@ -1,5 +1,6 @@
1
- import { dirname, join } from "node:path";
1
+ import { dirname, join, resolve } from "node:path";
2
2
  import { existsSync } from "node:fs";
3
+ import { assertPathWithin } from "@intlayer/config/utils";
3
4
  import { getUnmergedDictionaries } from "@intlayer/unmerged-dictionaries-entry";
4
5
 
5
6
  //#region src/extractContent/utils/resolveDictionaryKey.ts
@@ -19,6 +20,7 @@ const resolveDictionaryKey = (initialKey, filePath, configuration, unmergedDicti
19
20
  const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;
20
21
  const dictionaries = dicts[keyToTest];
21
22
  const contentFilePath = join(dirName, `${keyToTest}${extension}`);
23
+ assertPathWithin(resolve(contentFilePath), dirName);
22
24
  const isKeyUsed = usedKeys.has(keyToTest);
23
25
  const hasDictionaries = dictionaries && dictionaries.length > 0;
24
26
  const fileExists = existsSync(contentFilePath);
@@ -1 +1 @@
1
- {"version":3,"file":"resolveDictionaryKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\n\n/**\n * Resolves a unique dictionary key, checking for existing dictionaries and files.\n * Note: this chokidar-specific variant fetches unmergedDictionaries internally\n * from the configuration (unlike the `@intlayer/babel` version which takes it as a parameter).\n */\nexport const resolveDictionaryKey = (\n initialKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n unmergedDictionaries?: Record<string, unknown>,\n usedKeys: Set<string> = new Set()\n): string => {\n const dicts =\n unmergedDictionaries ?? getUnmergedDictionaries(configuration) ?? {};\n\n const { fileExtensions } = configuration.content;\n\n const dirName = dirname(filePath);\n const firstExtension = fileExtensions[0];\n const extension = firstExtension.startsWith('.')\n ? firstExtension\n : `.${firstExtension}`;\n\n let index = 0;\n\n while (index < 100) {\n const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;\n const dictionaries = dicts[keyToTest] as Dictionary[] | undefined;\n const contentFilePath = join(dirName, `${keyToTest}${extension}`);\n const isKeyUsed = usedKeys.has(keyToTest);\n const hasDictionaries = dictionaries && dictionaries.length > 0;\n const fileExists = existsSync(contentFilePath);\n\n if (!isKeyUsed && !hasDictionaries && !fileExists) {\n return keyToTest;\n }\n index++;\n }\n\n return initialKey;\n};\n"],"mappings":";;;;;;;;;;AAWA,MAAa,wBACX,YACA,UACA,eACA,sBACA,2BAAwB,IAAI,KAAK,KACtB;CACX,MAAM,QACJ,wBAAwB,wBAAwB,cAAc,IAAI,EAAE;CAEtE,MAAM,EAAE,mBAAmB,cAAc;CAEzC,MAAM,UAAU,QAAQ,SAAS;CACjC,MAAM,iBAAiB,eAAe;CACtC,MAAM,YAAY,eAAe,WAAW,IAAI,GAC5C,iBACA,IAAI;CAER,IAAI,QAAQ;CAEZ,OAAO,QAAQ,KAAK;EAClB,MAAM,YAAY,UAAU,IAAI,aAAa,GAAG,aAAa;EAC7D,MAAM,eAAe,MAAM;EAC3B,MAAM,kBAAkB,KAAK,SAAS,GAAG,YAAY,YAAY;EACjE,MAAM,YAAY,SAAS,IAAI,UAAU;EACzC,MAAM,kBAAkB,gBAAgB,aAAa,SAAS;EAC9D,MAAM,aAAa,WAAW,gBAAgB;EAE9C,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,YACrC,OAAO;EAET;;CAGF,OAAO"}
1
+ {"version":3,"file":"resolveDictionaryKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { assertPathWithin } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\n\n/**\n * Resolves a unique dictionary key, checking for existing dictionaries and files.\n * Note: this chokidar-specific variant fetches unmergedDictionaries internally\n * from the configuration (unlike the `@intlayer/babel` version which takes it as a parameter).\n */\nexport const resolveDictionaryKey = (\n initialKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n unmergedDictionaries?: Record<string, unknown>,\n usedKeys: Set<string> = new Set()\n): string => {\n const dicts =\n unmergedDictionaries ?? getUnmergedDictionaries(configuration) ?? {};\n\n const { fileExtensions } = configuration.content;\n\n const dirName = dirname(filePath);\n const firstExtension = fileExtensions[0];\n const extension = firstExtension.startsWith('.')\n ? firstExtension\n : `.${firstExtension}`;\n\n let index = 0;\n\n while (index < 100) {\n const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;\n const dictionaries = dicts[keyToTest] as Dictionary[] | undefined;\n const contentFilePath = join(dirName, `${keyToTest}${extension}`);\n\n assertPathWithin(resolve(contentFilePath), dirName);\n\n const isKeyUsed = usedKeys.has(keyToTest);\n const hasDictionaries = dictionaries && dictionaries.length > 0;\n const fileExists = existsSync(contentFilePath);\n\n if (!isKeyUsed && !hasDictionaries && !fileExists) {\n return keyToTest;\n }\n index++;\n }\n\n return initialKey;\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,wBACX,YACA,UACA,eACA,sBACA,2BAAwB,IAAI,KAAK,KACtB;CACX,MAAM,QACJ,wBAAwB,wBAAwB,cAAc,IAAI,EAAE;CAEtE,MAAM,EAAE,mBAAmB,cAAc;CAEzC,MAAM,UAAU,QAAQ,SAAS;CACjC,MAAM,iBAAiB,eAAe;CACtC,MAAM,YAAY,eAAe,WAAW,IAAI,GAC5C,iBACA,IAAI;CAER,IAAI,QAAQ;CAEZ,OAAO,QAAQ,KAAK;EAClB,MAAM,YAAY,UAAU,IAAI,aAAa,GAAG,aAAa;EAC7D,MAAM,eAAe,MAAM;EAC3B,MAAM,kBAAkB,KAAK,SAAS,GAAG,YAAY,YAAY;EAEjE,iBAAiB,QAAQ,gBAAgB,EAAE,QAAQ;EAEnD,MAAM,YAAY,SAAS,IAAI,UAAU;EACzC,MAAM,kBAAkB,gBAAgB,aAAa,SAAS;EAC9D,MAAM,aAAa,WAAW,gBAAgB;EAE9C,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,YACrC,OAAO;EAET;;CAGF,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"extractDictionaryInfo.d.ts","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"mappings":";;;;;cAmBa,SAAA,GACX,aAAA,EAAe,cAAA,EACf,MAAA,GAAS,MAAA,KACR,uBAAA;AAAA,KA0CS,uBAAA;EACV,YAAA;EACA,YAAA;EACA,WAAA;AAAA;;;;;cAOW,uBAAA,GACX,QAAA,UACA,YAAA,UACA,aAAA,EAAe,cAAA,EACf,MAAA,GAAS,MAAA,KACR,OAAA,CAAQ,uBAAA;AAAA,KA6GC,4BAAA;EACV,aAAA,GAAgB,cAAA;AAAA;;;;cAML,qBAAA,GACX,QAAA,UACA,QAAA,UACA,aAAA,EAAe,cAAA,KACd,OAAA;EAEC,aAAA;AAAA,IACE,uBAAA"}
1
+ {"version":3,"file":"extractDictionaryInfo.d.ts","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"mappings":";;;;;cAmBa,SAAA,GACX,aAAA,EAAe,cAAA,EACf,MAAA,GAAS,MAAA,KACR,uBAAA;AAAA,KA0CS,uBAAA;EACV,YAAA;EACA,YAAA;EACA,WAAA;AAAA;;;;;cAOW,uBAAA,GACX,QAAA,UACA,YAAA,UACA,aAAA,EAAe,cAAA,EACf,MAAA,GAAS,MAAA,KACR,OAAA,CAAQ,uBAAA;AAAA,KA+GC,4BAAA;EACV,aAAA,GAAgB,cAAA;AAAA;;;;cAML,qBAAA,GACX,QAAA,UACA,QAAA,UACA,aAAA,EAAe,cAAA,KACd,OAAA;EAEC,aAAA;AAAA,IACE,uBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveDictionaryKey.d.ts","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"mappings":";;;;;AAWA;;;cAAa,oBAAA,GACX,UAAA,UACA,QAAA,UACA,aAAA,EAAe,cAAA,EACf,oBAAA,GAAuB,MAAA,mBACvB,QAAA,GAAU,GAAA"}
1
+ {"version":3,"file":"resolveDictionaryKey.d.ts","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"mappings":";;;;;AAYA;;;cAAa,oBAAA,GACX,UAAA,UACA,QAAA,UACA,aAAA,EAAe,cAAA,EACf,oBAAA,GAAuB,MAAA,mBACvB,QAAA,GAAU,GAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/babel",
3
- "version": "8.9.5",
3
+ "version": "8.9.6-canary.0",
4
4
  "private": false,
5
5
  "description": "A Babel plugin for Intlayer that transforms declaration files and provides internationalization features during the build process according to the Intlayer configuration.",
6
6
  "keywords": [
@@ -81,31 +81,31 @@
81
81
  "@babel/plugin-syntax-jsx": "7.28.6",
82
82
  "@babel/traverse": "7.29.0",
83
83
  "@babel/types": "7.29.0",
84
- "@intlayer/chokidar": "8.9.5",
85
- "@intlayer/config": "8.9.5",
86
- "@intlayer/core": "8.9.5",
87
- "@intlayer/dictionaries-entry": "8.9.5",
88
- "@intlayer/types": "8.9.5",
89
- "@intlayer/unmerged-dictionaries-entry": "8.9.5",
84
+ "@intlayer/chokidar": "8.9.6-canary.0",
85
+ "@intlayer/config": "8.9.6-canary.0",
86
+ "@intlayer/core": "8.9.6-canary.0",
87
+ "@intlayer/dictionaries-entry": "8.9.6-canary.0",
88
+ "@intlayer/types": "8.9.6-canary.0",
89
+ "@intlayer/unmerged-dictionaries-entry": "8.9.6-canary.0",
90
90
  "@types/babel__core": "7.20.5",
91
91
  "@types/babel__generator": "7.27.0",
92
92
  "@types/babel__traverse": "7.28.0"
93
93
  },
94
94
  "devDependencies": {
95
95
  "@babel/plugin-syntax-jsx": "^7.28.6",
96
- "@types/node": "25.7.0",
96
+ "@types/node": "25.8.0",
97
97
  "@utils/ts-config": "1.0.4",
98
98
  "@utils/ts-config-types": "1.0.4",
99
99
  "@utils/tsdown-config": "1.0.4",
100
- "@vitejs/plugin-react": "6.0.1",
100
+ "@vitejs/plugin-react": "6.0.2",
101
101
  "rimraf": "6.1.3",
102
102
  "tsdown": "0.22.00",
103
103
  "typescript": "6.0.3",
104
104
  "vitest": "4.1.6"
105
105
  },
106
106
  "peerDependencies": {
107
- "@intlayer/svelte-compiler": "8.9.5",
108
- "@intlayer/vue-compiler": "8.9.5"
107
+ "@intlayer/svelte-compiler": "8.9.6-canary.0",
108
+ "@intlayer/vue-compiler": "8.9.6-canary.0"
109
109
  },
110
110
  "peerDependenciesMeta": {
111
111
  "@intlayer/svelte-compiler": {