From f8bc05685e5f1dd577f91f091cda47436242fe03 Mon Sep 17 00:00:00 2001 From: Victor Noguera Date: Wed, 20 May 2026 16:18:12 -0400 Subject: [PATCH] feat: add XLSX export functionality and refactor argument parsing in main script --- src/index.ts | 59 +++++++++++++++++++++++++++++++++++++++++++++------ src/writer.ts | 19 +++++++++++++++++ 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index b6b9efd..f88f424 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,10 @@ import { readProducts } from "./reader.ts"; import { connectCache, disconnectCache } from "./cache.ts"; -import { printResults, writeResultsToDb } from "./writer.ts"; +import { + printResults, + writeResultsToDb, + writeResultsWorkbook, +} from "./writer.ts"; import { initDb, closeDb } from "./database.ts"; import { chunkArray, @@ -40,14 +44,18 @@ function parseArgs(): { sellability: SellabilityFilter; } { const args = process.argv.slice(2); - const inputFile = args.find((a) => !a.startsWith("--")); - const outIdx = args.indexOf("--out"); - const outputFile = outIdx !== -1 ? args[outIdx + 1] : undefined; + const outputFile = readFlagValue(args, "--out", "--output"); + const inputFile = readInputFileArg( + args, + "--out", + "--output", + "--sellability", + ); const sellability = parseSellabilityArg(args); if (!inputFile) { console.error( - "Usage: bun run src/index.ts [--out results.csv] [--sellability available|all]", + "Usage: bun run src/index.ts [--out results.xlsx|--output results.xlsx] [--sellability available|all]", ); process.exit(1); } @@ -55,6 +63,44 @@ function parseArgs(): { return { inputFile, outputFile, sellability }; } +function readFlagValue(args: string[], ...flags: string[]): string | undefined { + for (const flag of flags) { + const equalsArg = args.find((arg) => arg.startsWith(`${flag}=`)); + if (equalsArg) { + const value = equalsArg.slice(flag.length + 1); + if (value) return value; + } + + const flagIdx = args.indexOf(flag); + if (flagIdx !== -1) { + return args[flagIdx + 1]; + } + } + + return undefined; +} + +function readInputFileArg( + args: string[], + ...flagsWithValues: string[] +): string | undefined { + for (let i = 0; i < args.length; i++) { + const arg = args[i]!; + if (flagsWithValues.includes(arg)) { + i++; + continue; + } + if (flagsWithValues.some((flag) => arg.startsWith(`${flag}=`))) { + continue; + } + if (!arg.startsWith("--")) { + return arg; + } + } + + return undefined; +} + function resolveBaseOutputPath(inputFile: string, outputFile?: string): string { if (outputFile) return outputFile; @@ -103,7 +149,8 @@ async function main() { } printResults(allResults); - writeResultsToDb(allResults, DB_PATH, inputFile, outputFile); + writeResultsWorkbook(allResults, resolvedBaseOutputPath); + writeResultsToDb(allResults, DB_PATH, inputFile, resolvedBaseOutputPath); } finally { await disconnectCache(); closeDb(); diff --git a/src/writer.ts b/src/writer.ts index 477d918..5120191 100644 --- a/src/writer.ts +++ b/src/writer.ts @@ -1,5 +1,8 @@ import { getDb } from "./database.ts"; import type { AnalysisResult, SupplierAnalysisResult } from "./types.ts"; +import { mkdirSync } from "node:fs"; +import path from "node:path"; +import * as XLSX from "xlsx"; export type RunCounts = { totalProducts: number; @@ -93,6 +96,22 @@ export function writeResultsToDb( console.log(`Results written to SQLite database for run_id: ${runId}`); } +export function writeResultsWorkbook( + results: AnalysisResult[], + outputFile: string, +): void { + const outputDir = path.dirname(outputFile); + if (outputDir && outputDir !== ".") { + mkdirSync(outputDir, { recursive: true }); + } + + const workbook = XLSX.utils.book_new(); + const worksheet = XLSX.utils.json_to_sheet(results.map(buildRow)); + XLSX.utils.book_append_sheet(workbook, worksheet, "Results"); + XLSX.writeFile(workbook, outputFile); + console.log(`Results workbook written: ${outputFile}`); +} + export function startRunInDb( dbPath: string, inputFile: string,