import assert from "node:assert/strict"; import { createHash } from "node:crypto"; import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import ExcelJS from "exceljs"; import { createDefaultExternalXlsxTransportConfiguration, type ExternalXlsxScalar, } from "../src/external-model/xlsx/external-xlsx-contracts.js"; import { createExternalXlsxReturn, parseExternalXlsx, } from "../src/external-model/xlsx/external-xlsx-transport.js"; async function main() { const inputPath = resolve( process.argv[2] ?? "docs/spec/kbp-Stromkreis.xlsx" ); const outputPath = resolve( process.argv[3] ?? "data/revit-reference/kbp-Stromkreis-R2-Rueckgabe.xlsx" ); assert.notEqual( inputPath, outputPath, "Eingabe- und Ausgabedatei müssen verschieden sein." ); const source = readFileSync(inputPath); const configuration = createDefaultExternalXlsxTransportConfiguration(); const document = await parseExternalXlsx({ fileName: inputPath, bytes: source, configuration, }); const objectRows = document.rows.filter((row) => row.classification === "object"); const suspectRows = document.rows.filter( (row) => row.classification === "suspect-object" ); const worksharingIdColumn = document.columns.find( (column) => column.header === configuration.columns.worksharingId )?.columnNumber; assert.ok(worksharingIdColumn, "Worksharing-ID-Spalte wurde nicht aufgelöst."); assert.equal(objectRows.length, 487, "Es werden 487 Objektzeilen erwartet."); assert.equal(suspectRows.length, 0, "Es werden keine verdächtigen Zeilen erwartet."); assert.equal( document.columns.filter((column) => column.comment !== null).length, 14, "Es werden 14 Kopfzeilenkommentare erwartet." ); assert.equal( document.issues.filter((issue) => issue.code === "duplicate-ifc-guid").length, 0, "Die Musterdatei darf keine exakten IfcGUID-Duplikate enthalten." ); const testValues = [ { circuitCombined: "UV_R2_TEST-2F1", electricalPowerW: 111, voltageV: 230, currentA: 0.48, }, { circuitCombined: "UV_R2_TEST-2F2", electricalPowerW: 222, voltageV: 230, currentA: 0.97, }, { circuitCombined: "UV_R2_TEST-3F1", electricalPowerW: 333, voltageV: 400, currentA: 0.48, }, ] satisfies Record[]; const updates = testValues.map((values, index) => { const value = objectRows[index]?.cells[worksharingIdColumn - 1]?.value; if (typeof value !== "string") { throw new Error("Worksharing-ID muss Text sein."); } return { worksharingId: value, values }; }); const result = await createExternalXlsxReturn({ fileName: inputPath, bytes: source, configuration, updates, }); assert.equal(result.exportedObjectCount, 487); mkdirSync(dirname(outputPath), { recursive: true }); writeFileSync(outputPath, result.bytes); const outputDocument = await parseExternalXlsx({ fileName: outputPath, bytes: result.bytes, configuration, }); assert.equal( outputDocument.rows.filter((row) => row.classification === "object").length, 487 ); assert.equal( outputDocument.rows.some((row) => row.classification !== "object"), false, "Die Rückgabedatei darf keine Summen- oder Hinweiszeilen enthalten." ); assert.equal(outputDocument.sheetName, document.sheetName); assert.deepEqual( outputDocument.columns, document.columns, "Kopfzeilen, Kommentare und Spaltenbreiten müssen erhalten bleiben." ); assert.deepEqual( outputDocument.rows.slice(updates.length).map((row) => row.cells), objectRows.slice(updates.length).map((row) => row.cells), "Nicht geänderte Objektzellen müssen Wert, Typ und Zahlenformat behalten." ); const outputWorkbook = new ExcelJS.Workbook(); await outputWorkbook.xlsx.load(result.bytes as never); const commentedCells: string[] = []; outputWorkbook.worksheets[0].eachRow({ includeEmpty: true }, (row) => { row.eachCell({ includeEmpty: true }, (cell) => { if (cell.note !== undefined) commentedCells.push(cell.address); }); }); assert.equal( commentedCells.length, 14, "Nur die 14 Kopfzellen dürfen Kommentare enthalten." ); assert.equal( commentedCells.every((address) => address.endsWith("1")), true, "Datenzellen dürfen keine Kommentare enthalten." ); process.stdout.write( `${JSON.stringify( { input: inputPath, output: outputPath, inputBytes: source.length, outputBytes: result.bytes.length, inputSha256: createHash("sha256").update(source).digest("hex"), outputSha256: createHash("sha256").update(result.bytes).digest("hex"), sheetName: document.sheetName, objectCount: objectRows.length, headerCommentCount: document.columns.filter( (column) => column.comment !== null ).length, exactDuplicateIfcGuidCount: 0, changedObjectCount: updates.length, }, null, 2 )}\n` ); } void main();