import { ApiError } from '../../api/client'; import type { EditionLineOut, LineErrorDetail } from '../../types/api'; import type { GridRow } from './statementGrid'; export type CodeOption = { code: string; name: string }; const LIST_LIMIT = 20; /** * Подсказки кода (P6-1): сначала справочник редакции по порядку, затем коды строк `ok` файла вне справочника. * Без повторов; строки без кода (unreadable / missing / detail) не попадают. */ export function codeOptions(editionLines: EditionLineOut[], rows: GridRow[]): CodeOption[] { const result: CodeOption[] = []; const seen = new Set(); for (const line of editionLines) { if (seen.has(line.code)) continue; seen.add(line.code); result.push({ code: line.code, name: line.name }); } for (const row of rows) { if (row.lineStatus !== 'ok' || !row.code || seen.has(row.code)) continue; seen.add(row.code); result.push({ code: row.code, name: row.referenceName ?? row.name ?? '' }); } return result; } const fold = (text: string) => text.toLowerCase().replace(/ё/g, 'е'); /** Отбор подсказок: код начинается с запроса или имя содержит его (регистр и ё/е не важны). */ export function filterCodeOptions(options: CodeOption[], query: string, limit = LIST_LIMIT): CodeOption[] { const q = fold(query.trim()); if (q === '') return options.slice(0, limit); return options.filter((o) => o.code.startsWith(q) || fold(o.name).includes(q)).slice(0, limit); } const LINE_ERROR_CODES = new Set(['LINE_CODE_TAKEN', 'INVALID_LINE_CODE', 'INVALID_LINE_PATCH', 'UNKNOWN_LINE', 'LINE_CODE_REQUIRED']); /** P6-9: к какой строке относится ошибка элемента `lines[]` ответа на сохранение; иная ошибка — null. */ export function lineErrorTarget(error: unknown): { lineId: string; lineCode: string | null } | null { if (!(error instanceof ApiError) || !error.code || !LINE_ERROR_CODES.has(error.code)) return null; const detail = (error.body as { detail?: Partial> } | undefined)?.detail; if (typeof detail?.line_id !== 'string') return null; return { lineId: detail.line_id, lineCode: typeof detail.line_code === 'string' ? detail.line_code : null }; }