{"version":3,"file":"loadDictionaries.cjs","names":["DictionariesLogger","ANSIColors","filterInvalidDictionaries","formatDictionaries","loadContentDeclarations","loadRemoteDictionaries"],"sources":["../../../src/loadDictionaries/loadDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n  colon,\n  colorize,\n  colorizeKey,\n  getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { formatDictionaries } from '../formatDictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\nimport { loadRemoteDictionaries } from './loadRemoteDictionaries';\nimport { DictionariesLogger } from './log';\n\nexport type DictionariesStatus = {\n  dictionaryKey: string;\n  type: 'local' | 'remote';\n  status:\n    | 'pending' // Key found but not fetched yet\n    | 'fetching' // If dictionary fetch is in progress\n    | 'fetched' // If dictionary fetch succeeded\n    | 'error' // If dictionary fetch failed\n    | 'imported' // If dictionary already fetched and still up to date\n    | 'found' // If dictionary key is found but promise is not resolved yet (ex: fetching distant content)\n    | 'building' // If dictionary is being built\n    | 'built'; // If dictionary is built;\n  error?: string;\n};\n\nlet loadDictionariesStatus: DictionariesStatus[] = [];\nconst logger = new DictionariesLogger();\n\nconst setLoadDictionariesStatus = (statuses: DictionariesStatus[]) => {\n  const updated: DictionariesStatus[] = [...loadDictionariesStatus];\n\n  for (const incoming of statuses) {\n    const index = updated.findIndex(\n      (s) =>\n        s.dictionaryKey === incoming.dictionaryKey && s.type === incoming.type\n    );\n    if (index >= 0) {\n      updated[index] = incoming;\n    } else {\n      updated.push(incoming);\n    }\n  }\n\n  loadDictionariesStatus = updated;\n  logger.update(statuses);\n\n  return updated;\n};\n\ntype StatusRecord = {\n  local?: DictionariesStatus['status'];\n  remote?: DictionariesStatus['status'];\n};\n\nconst iconFor = (status: DictionariesStatus['status']) => {\n  switch (status) {\n    case 'built':\n    case 'imported':\n    case 'fetched':\n      return '✔';\n    case 'error':\n      return '✖';\n    default:\n      return '⏲';\n  }\n};\n\nconst colorFor = (status: DictionariesStatus['status']) => {\n  switch (status) {\n    case 'built':\n    case 'imported':\n    case 'fetched':\n      return ANSIColors.GREEN;\n    case 'error':\n      return ANSIColors.RED;\n    default:\n      return ANSIColors.BLUE;\n  }\n};\n\nconst printSummary = (configuration: IntlayerConfig) => {\n  if (configuration.log.mode !== 'verbose') return;\n\n  const appLogger = getAppLogger(configuration);\n\n  // Aggregate by dictionary key\n  const byKey = new Map<string, StatusRecord>();\n  for (const status of loadDictionariesStatus) {\n    const rec = byKey.get(status.dictionaryKey) ?? {};\n    if (status.type === 'local') rec.local = status.status;\n    if (status.type === 'remote') rec.remote = status.status;\n    byKey.set(status.dictionaryKey, rec);\n  }\n\n  const keys = Array.from(byKey.keys()).sort((a, b) => a.localeCompare(b));\n\n  // Compute the max visible length of the local label to align distant labels\n  let maxLocalLabelLen = 0;\n  for (const key of keys) {\n    const rec = byKey.get(key)!;\n    if (rec.local) {\n      const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n      if (visibleLocal.length > maxLocalLabelLen) {\n        maxLocalLabelLen = visibleLocal.length;\n      }\n    }\n  }\n\n  for (const key of keys) {\n    const rec = byKey.get(key)!;\n    const labels: string[] = [];\n\n    if (rec.local) {\n      const inner = colorize(\n        `${iconFor(rec.local)} ${rec.local}`,\n        colorFor(rec.local)\n      );\n      const coloredLocal =\n        `${ANSIColors.GREY}[` +\n        colorize('local: ', ANSIColors.GREY) +\n        inner +\n        `${ANSIColors.GREY}]${ANSIColors.RESET}`;\n\n      // Pad to align distant label across rows\n      const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n      const pad = Math.max(0, maxLocalLabelLen - visibleLocal.length);\n      labels.push(coloredLocal + ' '.repeat(pad));\n    } else {\n      // If no local label, insert spaces to keep distant aligned\n      labels.push(' '.repeat(maxLocalLabelLen));\n    }\n\n    if (rec.remote) {\n      const inner = colorize(\n        `${iconFor(rec.remote)} ${rec.remote}`,\n        colorFor(rec.remote)\n      );\n      labels.push(\n        `${ANSIColors.GREY}[` +\n          colorize('distant: ', ANSIColors.GREY) +\n          inner +\n          `${ANSIColors.GREY}]${ANSIColors.RESET}`\n      );\n    }\n\n    appLogger(\n      ` - ${colon(colorizeKey(key), { colSize: keys })} ${labels.join(' ')}`\n    );\n  }\n};\n\nexport const loadDictionaries = async (\n  contentDeclarationsPaths: string[] | string,\n  configuration: IntlayerConfig\n): Promise<{\n  localDictionaries: Dictionary[];\n  remoteDictionaries: Dictionary[];\n  pluginDictionaries: Dictionary[];\n  time: {\n    localDictionaries: number;\n    remoteDictionaries: number;\n    pluginDictionaries: number;\n  };\n}> => {\n  const { plugins } = configuration;\n  const loadDictionariesStartTime = Date.now();\n  const appLogger = getAppLogger(configuration);\n\n  appLogger('Dictionaries:', { isVerbose: true });\n\n  // Load additional dictionaries via plugins (e.g., ICU JSON ingestion)\n  const resolvedPlugins = await Promise.all(plugins ?? []);\n\n  const pluginsWithLoadDictionaries = resolvedPlugins.filter(\n    (plugin) => plugin.loadDictionaries\n  );\n\n  const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(\n    async (plugin) => {\n      try {\n        const res = await plugin.loadDictionaries?.({\n          configuration,\n        });\n\n        return (res as Dictionary[] | undefined) ?? [];\n      } catch (error) {\n        logger.setPluginError(error as Error);\n\n        return [];\n      }\n    }\n  );\n\n  const pluginDictionaries: Dictionary[] = await Promise.all(\n    loadPluginDictionariesPromise as Promise<Dictionary[]>[]\n  )\n    .then((dictionaries) => dictionaries.flat())\n    .then((dictionaries) =>\n      filterInvalidDictionaries(dictionaries, configuration)\n    )\n    .then((dictionaries) => formatDictionaries(dictionaries));\n\n  logger.setPluginTotal(pluginDictionaries.length);\n  logger.setPluginDone(pluginDictionaries.length);\n\n  const pluginDictionariesTime = Date.now();\n\n  const files = Array.isArray(contentDeclarationsPaths)\n    ? contentDeclarationsPaths\n    : [contentDeclarationsPaths];\n\n  const localDictionaries: Dictionary[] = await loadContentDeclarations(\n    files,\n    configuration,\n    setLoadDictionariesStatus\n  )\n    .then((dictionaries) =>\n      filterInvalidDictionaries(dictionaries, configuration)\n    )\n    .then((dictionaries) => formatDictionaries(dictionaries));\n\n  const localDictionariesTime = Date.now();\n\n  const localDictionariesStatus = localDictionaries.map(\n    (dictionary) =>\n      ({\n        dictionaryKey: dictionary.key,\n        type: 'local',\n        status: 'built',\n      }) as const\n  );\n\n  setLoadDictionariesStatus(localDictionariesStatus);\n\n  const hasRemoteDictionaries = Boolean(\n    configuration.editor.clientId && configuration.editor.clientSecret\n  );\n\n  if (hasRemoteDictionaries) {\n    // We expect to fetch remote dictionaries soon; suppress a transient local-only render\n    logger.setExpectRemote(true);\n  }\n\n  let remoteDictionaries: Dictionary[] = [];\n\n  if (hasRemoteDictionaries) {\n    remoteDictionaries = await loadRemoteDictionaries(\n      configuration,\n      setLoadDictionariesStatus,\n      {\n        onStartRemoteCheck: () => logger.startRemoteCheck(),\n        onStopRemoteCheck: () => logger.stopRemoteCheck(),\n        onError: (e) => logger.setRemoteError(e),\n      }\n    )\n      .then((dictionaries) =>\n        filterInvalidDictionaries(dictionaries, configuration)\n      )\n      .then((dictionaries) => formatDictionaries(dictionaries));\n  }\n\n  const remoteDictionariesTime = Date.now();\n\n  // Stop spinner and show final progress line(s)\n  logger.finish();\n\n  printSummary(configuration);\n\n  return {\n    localDictionaries,\n    remoteDictionaries,\n    pluginDictionaries,\n    time: {\n      localDictionaries: localDictionariesTime - pluginDictionariesTime,\n      remoteDictionaries: remoteDictionariesTime - localDictionariesTime,\n      pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime,\n    },\n  };\n};\n"],"mappings":"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"}