{"version":3,"file":"getSplittedContent.mjs","names":[],"sources":["../../../src/deepTransformPlugins/getSplittedContent.ts"],"sourcesContent":["import type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { DeclaredLocales } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\ntype SplittedContentOutput<T = ContentNode> = Record<DeclaredLocales, T> & {\n  common: T;\n};\n\ntype SplitResult = Record<string, ContentNode | undefined> & {\n  common?: ContentNode;\n};\n\nconst isObject = (value: unknown): value is Record<string, any> =>\n  typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst hasNodeType = (value: unknown): value is { nodeType: string } =>\n  isObject(value) && typeof (value as any).nodeType === 'string';\n\nconst mergeValues = (\n  a: ContentNode | undefined,\n  b: ContentNode | undefined\n): ContentNode | undefined => {\n  if (a === undefined) return b;\n  if (b === undefined) return a;\n\n  if (Array.isArray(a) && Array.isArray(b)) {\n    // Concatenate arrays when merging sibling results\n    return [...a, ...b] as unknown as ContentNode;\n  }\n\n  if (isObject(a) && isObject(b) && !hasNodeType(a) && !hasNodeType(b)) {\n    const result: Record<string, any> = { ...a };\n    for (const key of Object.keys(b)) {\n      result[key] = mergeValues(\n        result[key] as unknown as ContentNode | undefined,\n        (b as Record<string, any>)[key] as unknown as ContentNode | undefined\n      );\n    }\n    return result as ContentNode;\n  }\n\n  // For primitives or differing structures, prefer b (more recent)\n  return b;\n};\n\nconst mergeSplitResults = (\n  base: SplitResult,\n  addition: SplitResult\n): SplitResult => {\n  const result: SplitResult = { ...base };\n\n  // Merge common\n  result.common = mergeValues(base.common, addition.common);\n\n  // Merge each locale key present in either side\n  const localeKeys = new Set<string>([\n    ...Object.keys(base).filter((k) => k !== 'common'),\n    ...Object.keys(addition).filter((k) => k !== 'common'),\n  ]);\n\n  for (const key of localeKeys) {\n    // @ts-ignore: dynamic keys for locales\n    result[key] = mergeValues(\n      base[key] as ContentNode | undefined,\n      addition[key] as ContentNode | undefined\n    );\n  }\n\n  return result;\n};\n\nconst splitNode = (node: ContentNode): SplitResult => {\n  // Translation node: allocate entirely to per-locale buckets\n  if (isObject(node) && (node as any)?.nodeType === NodeTypes.TRANSLATION) {\n    const translations = (node as any)[NodeTypes.TRANSLATION] as Record<\n      string,\n      ContentNode\n    >;\n\n    const result: SplitResult = {};\n    for (const locale of Object.keys(translations)) {\n      const child = translations[locale];\n      const childSplit = splitNode(child);\n\n      // The content under a translation belongs to the locale, not common\n      // Merge common portion of the child (if any) into the locale as well\n      const mergedForLocale = mergeValues(childSplit.common, undefined);\n\n      // Compose locale content: prefer the fully rebuilt child by resolving deeper translations recursively\n      // which are already split inside childSplit. We need to recompose a single node for this locale.\n      // Recompose by merging all keys in childSplit except 'common' into a single node, then merge child's common.\n      let recomposed: ContentNode | undefined;\n      for (const key of Object.keys(childSplit)) {\n        if (key === 'common') continue;\n        recomposed = mergeValues(\n          recomposed,\n          childSplit[key] as ContentNode | undefined\n        );\n      }\n      const finalLocaleNode = mergeValues(mergedForLocale, recomposed);\n\n      if (finalLocaleNode !== undefined) {\n        // @ts-ignore dynamic locale key\n        result[locale] = finalLocaleNode;\n      }\n    }\n\n    return result;\n  }\n\n  // Arrays: split each element and merge results index-wise\n  if (Array.isArray(node)) {\n    const commonArray: any[] = [];\n    const perLocaleArrays: Record<string, any[]> = {};\n\n    node.forEach((child) => {\n      const childSplit = splitNode(child as ContentNode);\n\n      if (childSplit.common !== undefined) {\n        commonArray.push(childSplit.common);\n      }\n\n      for (const key of Object.keys(childSplit)) {\n        if (key === 'common') continue;\n        if (!perLocaleArrays[key]) perLocaleArrays[key] = [];\n        const value = childSplit[key];\n        if (value !== undefined) perLocaleArrays[key].push(value);\n      }\n    });\n\n    const result: SplitResult = {};\n    if (commonArray.length > 0)\n      result.common = commonArray as unknown as ContentNode;\n    for (const key of Object.keys(perLocaleArrays)) {\n      // @ts-ignore dynamic locale key\n      result[key] = perLocaleArrays[key] as unknown as ContentNode;\n    }\n    return result;\n  }\n\n  // Objects (non-typed): recursively split properties\n  if (isObject(node) && !hasNodeType(node)) {\n    let accumulated: SplitResult = {};\n\n    for (const key of Object.keys(node)) {\n      const childSplit = splitNode((node as any)[key] as ContentNode);\n\n      // Assign property into common\n      if (childSplit.common !== undefined) {\n        accumulated = mergeSplitResults(accumulated, {\n          common: { [key]: childSplit.common } as unknown as ContentNode,\n        });\n      }\n\n      // Assign property into each locale bucket\n      for (const locale of Object.keys(childSplit)) {\n        if (locale === 'common') continue;\n        accumulated = mergeSplitResults(accumulated, {\n          // @ts-ignore dynamic locale key\n          [locale]: { [key]: childSplit[locale] } as unknown as ContentNode,\n        });\n      }\n    }\n\n    return accumulated;\n  }\n\n  // Primitives or typed nodes (non-translation): entirely common\n  return { common: node } as SplitResult;\n};\n\nexport const getSplittedContent = (\n  content: ContentNode\n): SplittedContentOutput => {\n  const split = splitNode(content);\n\n  // Build final output with only defined sections\n  const output: Record<string, ContentNode> = {};\n  if (split.common !== undefined) {\n    output.common = split.common;\n  }\n  for (const key of Object.keys(split)) {\n    if (key === 'common') continue;\n    const value = split[key] as ContentNode | undefined;\n    if (value !== undefined) {\n      output[key] = value;\n    }\n  }\n\n  return output as unknown as SplittedContentOutput;\n};\n\n/**\n * Splits the `content` field of a Dictionary into \"common\" and per-locale buckets.\n *\n * Given a dictionary like:\n * ```js\n * {\n *   key: \"my-key\",\n *   content: {\n *     commonContent: \"common content\",\n *     multilingualContent: t({\n *       en: \"english content\",\n *       fr: \"french content\",\n *       de: \"german content\",\n *     }),\n *   },\n * }\n * ```\n *\n * It produces:\n * ```js\n * {\n *   common: { commonContent: \"common content\" },\n *   en: { multilingualContent: \"english content\" },\n *   fr: { multilingualContent: \"french content\" },\n *   de: { multilingualContent: \"german content\" },\n * }\n * ```\n *\n * @param dictionary - The input dictionary object with possible multilingual or common content.\n * @returns An object mapping \"common\" and each locale to their corresponding content subtrees.\n */\nexport const getSplittedDictionaryContent = (\n  dictionary: Dictionary\n): SplittedContentOutput<Dictionary['content']> =>\n  getSplittedContent(dictionary.content);\n"],"mappings":"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"}