{"version":3,"file":"mergeDictionaries.cjs","names":["getNodeType","getMultilingualDictionary"],"sources":["../../../src/dictionaryManipulator/mergeDictionaries.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport { colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport type {\n  ContentNode,\n  Dictionary,\n  LocalDictionaryId,\n} from '@intlayer/types/dictionary';\nimport { getMultilingualDictionary } from '../deepTransformPlugins';\nimport { getNodeType } from './getNodeType';\n\n// Extended type that includes arrays for internal merge operations\ntype MergeableContent = ContentNode | ContentNode[];\n\nconst checkTypesMatch = (\n  object1: ContentNode,\n  object2: ContentNode,\n  object2LocalId: LocalDictionaryId | undefined,\n  dictionaryKey: string,\n  path: string[] = []\n): void => {\n  const appLogger = getAppLogger({ log });\n\n  // If either side is missing/undefined, allow merge without error\n  if (\n    object1 === undefined ||\n    object1 === null ||\n    object2 === undefined ||\n    object2 === null\n  )\n    return;\n\n  const type1 = getNodeType(object1);\n  const type2 = getNodeType(object2);\n\n  // Unknown types are treated as flexible; skip strict mismatch reporting\n  if (type1 === 'unknown' || type2 === 'unknown') return;\n\n  if (type1 !== type2) {\n    appLogger(\n      [\n        `Error: Dictionary ${colorizeKey(dictionaryKey)} has a multiple content files with type mismatch at path \"${path.join('.')}\": Cannot merge ${type1} with ${type2} while merging ${object2LocalId}`,\n      ],\n      {\n        level: 'error',\n      }\n    );\n\n    return;\n  }\n};\n\n// Custom merge function that prefers destination (first dictionary) values\nconst customMerge = (\n  destination: ContentNode,\n  source: ContentNode\n): MergeableContent => {\n  // If destination is undefined/null, use source\n  if (destination === undefined || destination === null) {\n    return source;\n  }\n\n  // If source is undefined/null, use destination\n  if (source === undefined || source === null) {\n    return destination;\n  }\n\n  // For primitive values, prefer destination (first dictionary)\n  if (typeof destination !== 'object' || typeof source !== 'object') {\n    return destination;\n  }\n\n  // For arrays, use our custom array merge\n  if (Array.isArray(destination) && Array.isArray(source)) {\n    return arrayMerge(\n      destination as ContentNode[],\n      source as ContentNode[]\n    ) as MergeableContent;\n  }\n\n  // For objects, recursively merge with our custom logic\n  if (typeof destination === 'object' && typeof source === 'object') {\n    const result: Record<string, MergeableContent> = {};\n    const allKeys = new Set([\n      ...Object.keys(destination as unknown as Record<string, ContentNode>),\n      ...Object.keys(source as unknown as Record<string, ContentNode>),\n    ]);\n\n    for (const key of allKeys) {\n      result[key] = customMerge(\n        (destination as unknown as Record<string, ContentNode>)[key],\n        (source as unknown as Record<string, ContentNode>)[key]\n      );\n    }\n\n    return result as unknown as MergeableContent;\n  }\n\n  // Fallback to destination\n  return destination;\n};\n\n// Custom array merge strategy that merges arrays by key when present, otherwise by index\nconst arrayMerge = (\n  destinationArray: ContentNode[],\n  sourceArray: ContentNode[]\n): MergeableContent[] => {\n  // Check if both arrays contain only primitives\n  const destHasOnlyPrimitives = destinationArray.every(\n    (item) => typeof item !== 'object' || item === null\n  );\n  const sourceHasOnlyPrimitives = sourceArray.every(\n    (item) => typeof item !== 'object' || item === null\n  );\n\n  // If both arrays contain only primitives, use the source array (second dictionary)\n  if (destHasOnlyPrimitives && sourceHasOnlyPrimitives) {\n    return sourceArray;\n  }\n\n  // Otherwise, merge by index with object merging logic\n  const result: MergeableContent[] = [];\n  const maxLength = Math.max(destinationArray.length, sourceArray.length);\n\n  for (let i = 0; i < maxLength; i++) {\n    const destItem = destinationArray[i];\n    const sourceItem = sourceArray[i];\n\n    if (destItem === undefined && sourceItem === undefined) {\n    } else if (destItem === undefined) {\n      // Only source exists, add it\n      result.push(sourceItem);\n    } else if (sourceItem === undefined) {\n      // Only destination exists, add it\n      result.push(destItem);\n    } else {\n      // Both exist, merge them\n      if (\n        typeof destItem === 'object' &&\n        typeof sourceItem === 'object' &&\n        destItem !== null &&\n        sourceItem !== null\n      ) {\n        // Check if both objects have a 'key' property for keyed merging\n        if (\n          'key' in destItem &&\n          'key' in sourceItem &&\n          (destItem as Record<string, string>).key ===\n            (sourceItem as Record<string, string>).key\n        ) {\n          // Merge objects with same key, preferring destination (first dictionary) values\n          result.push(customMerge(destItem, sourceItem));\n        } else {\n          // Merge objects by index, preferring destination (first dictionary) values\n          result.push(customMerge(destItem, sourceItem));\n        }\n      } else {\n        // For primitives or non-objects, use destination value (first dictionary)\n        result.push(destItem);\n      }\n    }\n  }\n\n  return result;\n};\n\nexport const mergeDictionaries = (dictionaries: Dictionary[]): Dictionary => {\n  const localIds = Array.from(\n    new Set<LocalDictionaryId>(\n      dictionaries.filter((dict) => dict.localId).map((dict) => dict.localId!)\n    )\n  );\n\n  const dictionariesKeys = dictionaries.map((dict) => dict.key);\n\n  // Check if all dictionaries have the same key\n  if (new Set(dictionariesKeys).size !== 1) {\n    throw new Error('All dictionaries must have the same key');\n  }\n\n  let mergedContent: Dictionary['content'] = dictionaries[0].content;\n\n  for (let i = 1; i < dictionaries.length; i++) {\n    // If the dictionary is a per-locale dictionary, transform it to a partial multilingual dictionary\n    const currentDictionary = getMultilingualDictionary(dictionaries[i]);\n\n    // Check types before merging\n    checkTypesMatch(\n      mergedContent,\n      currentDictionary.content,\n      currentDictionary.localId,\n      currentDictionary.key,\n      []\n    );\n\n    mergedContent = customMerge(\n      mergedContent,\n      currentDictionary.content\n    ) as ContentNode;\n  }\n\n  const mergedDictionary: Dictionary = {\n    key: dictionaries[0].key,\n    content: mergedContent,\n    localIds,\n  };\n\n  return mergedDictionary;\n};\n"],"mappings":";;;;;;;;AAaA,MAAM,mBACJ,SACA,SACA,gBACA,eACA,OAAiB,EAAE,KACV;CACT,MAAM,sDAAyB,EAAE,iCAAK,CAAC;AAGvC,KACE,YAAY,UACZ,YAAY,QACZ,YAAY,UACZ,YAAY,KAEZ;CAEF,MAAM,QAAQA,sDAAY,QAAQ;CAClC,MAAM,QAAQA,sDAAY,QAAQ;AAGlC,KAAI,UAAU,aAAa,UAAU,UAAW;AAEhD,KAAI,UAAU,OAAO;AACnB,YACE,CACE,8DAAiC,cAAc,CAAC,4DAA4D,KAAK,KAAK,IAAI,CAAC,kBAAkB,MAAM,QAAQ,MAAM,iBAAiB,iBACnL,EACD,EACE,OAAO,SACR,CACF;AAED;;;AAKJ,MAAM,eACJ,aACA,WACqB;AAErB,KAAI,gBAAgB,UAAa,gBAAgB,KAC/C,QAAO;AAIT,KAAI,WAAW,UAAa,WAAW,KACrC,QAAO;AAIT,KAAI,OAAO,gBAAgB,YAAY,OAAO,WAAW,SACvD,QAAO;AAIT,KAAI,MAAM,QAAQ,YAAY,IAAI,MAAM,QAAQ,OAAO,CACrD,QAAO,WACL,aACA,OACD;AAIH,KAAI,OAAO,gBAAgB,YAAY,OAAO,WAAW,UAAU;EACjE,MAAM,SAA2C,EAAE;EACnD,MAAM,UAAU,IAAI,IAAI,CACtB,GAAG,OAAO,KAAK,YAAsD,EACrE,GAAG,OAAO,KAAK,OAAiD,CACjE,CAAC;AAEF,OAAK,MAAM,OAAO,QAChB,QAAO,OAAO,YACX,YAAuD,MACvD,OAAkD,KACpD;AAGH,SAAO;;AAIT,QAAO;;AAIT,MAAM,cACJ,kBACA,gBACuB;CAEvB,MAAM,wBAAwB,iBAAiB,OAC5C,SAAS,OAAO,SAAS,YAAY,SAAS,KAChD;CACD,MAAM,0BAA0B,YAAY,OACzC,SAAS,OAAO,SAAS,YAAY,SAAS,KAChD;AAGD,KAAI,yBAAyB,wBAC3B,QAAO;CAIT,MAAM,SAA6B,EAAE;CACrC,MAAM,YAAY,KAAK,IAAI,iBAAiB,QAAQ,YAAY,OAAO;AAEvE,MAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;EAClC,MAAM,WAAW,iBAAiB;EAClC,MAAM,aAAa,YAAY;AAE/B,MAAI,aAAa,UAAa,eAAe,QAAW,YAC7C,aAAa,OAEtB,QAAO,KAAK,WAAW;WACd,eAAe,OAExB,QAAO,KAAK,SAAS;WAInB,OAAO,aAAa,YACpB,OAAO,eAAe,YACtB,aAAa,QACb,eAAe,KAGf,KACE,SAAS,YACT,SAAS,cACR,SAAoC,QAClC,WAAsC,IAGzC,QAAO,KAAK,YAAY,UAAU,WAAW,CAAC;MAG9C,QAAO,KAAK,YAAY,UAAU,WAAW,CAAC;MAIhD,QAAO,KAAK,SAAS;;AAK3B,QAAO;;AAGT,MAAa,qBAAqB,iBAA2C;CAC3E,MAAM,WAAW,MAAM,KACrB,IAAI,IACF,aAAa,QAAQ,SAAS,KAAK,QAAQ,CAAC,KAAK,SAAS,KAAK,QAAS,CACzE,CACF;CAED,MAAM,mBAAmB,aAAa,KAAK,SAAS,KAAK,IAAI;AAG7D,KAAI,IAAI,IAAI,iBAAiB,CAAC,SAAS,EACrC,OAAM,IAAI,MAAM,0CAA0C;CAG5D,IAAI,gBAAuC,aAAa,GAAG;AAE3D,MAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;EAE5C,MAAM,oBAAoBC,iFAA0B,aAAa,GAAG;AAGpE,kBACE,eACA,kBAAkB,SAClB,kBAAkB,SAClB,kBAAkB,KAClB,EAAE,CACH;AAED,kBAAgB,YACd,eACA,kBAAkB,QACnB;;AASH,QAAO;EALL,KAAK,aAAa,GAAG;EACrB,SAAS;EACT;EAGqB"}