{"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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"}