{"version":3,"file":"cleanRemovedContentDeclaration.cjs","names":["readDictionariesFromDisk","writeJsonIfChanged","createDictionaryEntryPoint"],"sources":["../../src/cleanRemovedContentDeclaration.ts"],"sourcesContent":["import { readFile, rm } from 'node:fs/promises';\nimport { join, normalize, relative } from 'node:path';\nimport { normalizePath } from '@intlayer/config/client';\nimport {\n  colorizeKey,\n  colorizePath,\n  getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport fg from 'fast-glob';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint';\nimport { readDictionariesFromDisk } from './utils/readDictionariesFromDisk';\nimport { writeJsonIfChanged } from './writeJsonIfChanged';\n\nexport const cleanRemovedContentDeclaration = async (\n  filePath: string,\n  keysToKeep: string[],\n  configuration: IntlayerConfig\n): Promise<{\n  changedDictionariesLocalIds: string[];\n  excludeKeys: string[];\n  hasRebuilt: boolean;\n}> => {\n  const appLogger = getAppLogger(configuration);\n\n  const unmergedDictionaries = readDictionariesFromDisk<\n    Record<string, Dictionary[]>\n  >(configuration.system.unmergedDictionariesDir);\n\n  const baseDir = configuration.system.baseDir;\n\n  const relativeFilePath = relative(baseDir, filePath);\n  const flatUnmergedDictionaries = Object.values(unmergedDictionaries).flat();\n\n  const filteredUnmergedDictionaries = flatUnmergedDictionaries.filter(\n    (dictionary) =>\n      dictionary.filePath === relativeFilePath &&\n      !keysToKeep.includes(dictionary.key)\n  );\n\n  // Deduplicate dictionaries by key\n  const uniqueUnmergedDictionaries = filteredUnmergedDictionaries.filter(\n    (dictionary, index, self) =>\n      index === self.findIndex((t) => t.key === dictionary.key)\n  );\n\n  const changedDictionariesLocalIds: string[] = [];\n  const filesToRemove: string[] = [];\n  const excludeKeys: string[] = [];\n\n  // Identify Unmerged Dictionaries to remove or clean\n  await Promise.all(\n    uniqueUnmergedDictionaries.map(async (dictionary) => {\n      const unmergedFilePath = normalize(\n        join(\n          configuration.system.unmergedDictionariesDir,\n          `${dictionary.key}.json`\n        )\n      );\n\n      try {\n        const jsonContent = await readFile(unmergedFilePath, 'utf8');\n        const parsedContent = JSON.parse(jsonContent);\n\n        if (parsedContent.length === 1) {\n          if (parsedContent[0].filePath === relativeFilePath) {\n            appLogger(\n              `Removing outdated dictionary ${colorizeKey(dictionary.key)}`,\n              { isVerbose: true }\n            );\n            filesToRemove.push(unmergedFilePath);\n            excludeKeys.push(dictionary.key);\n          }\n        } else {\n          const filteredContent = parsedContent.filter(\n            (content: any) => content.filePath !== relativeFilePath\n          );\n          await writeJsonIfChanged(unmergedFilePath, filteredContent);\n          changedDictionariesLocalIds.push(dictionary.localId!);\n        }\n      } catch (error: any) {\n        if (error.code === 'ENOENT') {\n          if (!excludeKeys.includes(dictionary.key)) {\n            excludeKeys.push(dictionary.key);\n          }\n        }\n      }\n    })\n  );\n\n  const dictionaries = readDictionariesFromDisk<Record<string, Dictionary>>(\n    configuration.system.dictionariesDir\n  );\n  const flatDictionaries = Object.values(dictionaries) as Dictionary[];\n\n  const filteredMergedDictionaries = flatDictionaries?.filter(\n    (dictionary) =>\n      !keysToKeep.includes(dictionary.key) &&\n      dictionary.localIds?.length === 1 &&\n      (dictionary.localIds[0] as string).endsWith(\n        `::local::${relativeFilePath}`\n      )\n  );\n\n  const uniqueMergedDictionaries = filteredMergedDictionaries.filter(\n    (dictionary, index, self) =>\n      index === self.findIndex((t) => t.key === dictionary.key)\n  );\n\n  // Identify Merged Dictionaries, Types, and Dynamic Dictionaries to remove\n  await Promise.all(\n    uniqueMergedDictionaries.map(async (dictionary) => {\n      const mergedFilePath = normalize(\n        join(configuration.system.dictionariesDir, `${dictionary.key}.json`)\n      );\n\n      try {\n        const fileContent = await readFile(mergedFilePath, 'utf8');\n        const parsedContent = JSON.parse(fileContent) as Dictionary;\n\n        if (parsedContent.localIds?.length === 1) {\n          if (\n            parsedContent.localIds[0].endsWith(`::local::${relativeFilePath}`)\n          ) {\n            appLogger(\n              `Removing outdated unmerged dictionary ${colorizeKey(dictionary.key)}`,\n              { isVerbose: true }\n            );\n\n            // Mark JSON for removal\n            filesToRemove.push(mergedFilePath);\n\n            // Mark TS Types for removal\n            const typesFilePath = normalize(\n              join(configuration.system.typesDir, `${dictionary.key}.ts`)\n            );\n            filesToRemove.push(typesFilePath);\n\n            // Mark Dynamic Dictionaries for removal\n            // We use glob to catch the loader files (.cjs, .mjs) AND the split locale files (.en.json, etc.)\n            const dynamicFilesGlob = join(\n              configuration.system.dynamicDictionariesDir,\n              `${dictionary.key}.*`\n            );\n            const dynamicFiles = await fg(normalizePath(dynamicFilesGlob), {\n              absolute: true,\n            });\n            filesToRemove.push(...dynamicFiles);\n\n            if (!excludeKeys.includes(dictionary.key)) {\n              excludeKeys.push(dictionary.key);\n            }\n          }\n        } else {\n          const localIds = parsedContent.localIds?.filter(\n            (localeId) => !localeId.endsWith(`::local::${relativeFilePath}`)\n          ) as string[];\n          const newContent = { ...parsedContent, localIds };\n          await writeJsonIfChanged(mergedFilePath, newContent);\n        }\n      } catch (error: any) {\n        if (error.code === 'ENOENT') {\n          if (!excludeKeys.includes(dictionary.key)) {\n            excludeKeys.push(dictionary.key);\n          }\n          const typesFilePath = normalize(\n            join(configuration.system.typesDir, `${dictionary.key}.ts`)\n          );\n          filesToRemove.push(typesFilePath);\n        }\n      }\n    })\n  );\n\n  // Execute Cleanup\n  if (filesToRemove.length > 0 || excludeKeys.length > 0) {\n    // Update entry points (indexes) first so the app doesn't import dead files\n    await createDictionaryEntryPoint(configuration, { excludeKeys });\n\n    // Remove the files synchronously (awaited) immediately after.\n    if (filesToRemove.length > 0) {\n      setTimeout(\n        async () =>\n          await Promise.all(\n            filesToRemove.map(async (path) => {\n              const relativePath = relative(baseDir, path);\n              try {\n                await rm(path, { force: true });\n\n                appLogger(`Deleted artifact: ${colorizePath(relativePath)}`, {\n                  isVerbose: true,\n                });\n              } catch {\n                appLogger(\n                  `Error while removing file ${colorizePath(relativePath)}`,\n                  {\n                    isVerbose: true,\n                  }\n                );\n              }\n            })\n          ),\n        3000\n      );\n    }\n  }\n\n  return {\n    changedDictionariesLocalIds,\n    excludeKeys,\n    hasRebuilt: filesToRemove.length > 0 || excludeKeys.length > 0,\n  };\n};\n"],"mappings":"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"}