import type { JsonValue } from '../../domain/canonical-model'; import { buildDefenderVulnerabilityModel, defenderTableRole, type DefenderSourceRow, type DefenderSourceTable, type DefenderVulnerabilityModel } from '../../domain/defender-for-iot'; import type { DatasetSheet, ImportedDataset } from '../../domain/dataset'; function recordFields(sheet: DatasetSheet, recordIndex: number): Record { const record = sheet.analysis.records[recordIndex]; return Object.fromEntries(record.fields.map(field => [field.label, field.value])); } function parsedObservations(fields: Record): Array> | undefined { const source = Object.entries(fields).find(([label]) => /^Source Observations$/i.test(label.trim()))?.[1]; if (typeof source !== 'string' || !source.trim()) return undefined; try { const parsed: unknown = JSON.parse(source); return Array.isArray(parsed) && parsed.every(item => item && typeof item === 'object' && !Array.isArray(item)) ? parsed as Array> : undefined; } catch { return undefined; } } function observationRows(sheet: DatasetSheet, tableIndex: number): DefenderSourceRow[] | undefined { const expanded = sheet.analysis.records.flatMap((record, recordIndex) => { const observations = parsedObservations(recordFields(sheet, recordIndex)); if (!observations) return []; return observations.map((observation, observationIndex): DefenderSourceRow => { const source = observation.source && typeof observation.source === 'object' && !Array.isArray(observation.source) ? observation.source as Record : {}; const additional = observation.additionalSourceFields && typeof observation.additionalSourceFields === 'object' && !Array.isArray(observation.additionalSourceFields) ? observation.additionalSourceFields as Record : {}; return { tableIndex: typeof source.tableIndex === 'number' ? source.tableIndex : tableIndex, rowIndex: typeof source.rowIndex === 'number' ? source.rowIndex : record.index + observationIndex, fields: { Name: observation.name ?? '', IP: observation.ip ?? '', Site: observation.site ?? '', Sensor: observation.sensor ?? '', CVE: observation.cve ?? '', Severity: observation.severity ?? '', NULL: additional.NULL ?? null, Beschreibung: observation.description ?? '', ...additional } }; }); }); return expanded.length ? expanded : undefined; } function sourceTable(sheet: DatasetSheet, index: number): DefenderSourceTable | undefined { const tableIndex = sheet.sourceTableIndex ?? sheet.workbookIndex ?? index; const expanded = observationRows(sheet, tableIndex); if (expanded) return { tableIndex, name: sheet.sourceSheet ?? sheet.name, headers: ['Name', 'IP', 'Site', 'Sensor', 'CVE', 'Severity', 'NULL', 'Beschreibung'], rows: expanded }; if (!defenderTableRole(sheet.analysis.headers)) return undefined; return { tableIndex, name: sheet.sourceSheet ?? sheet.name, headers: sheet.analysis.headers, rows: sheet.analysis.records.map((record, recordIndex) => ({ tableIndex, rowIndex: record.index, fields: recordFields(sheet, recordIndex) })) }; } export function defenderModelForDataset(dataset: ImportedDataset): DefenderVulnerabilityModel { const tables = dataset.sheets .filter(sheet => !sheet.isProjectSheet) .map(sourceTable) .filter((table): table is DefenderSourceTable => Boolean(table)); return buildDefenderVulnerabilityModel(tables); }