import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import { parse } from "csv-parse/sync"; const FILE_A = process.env.COMPARE_FILE_A ?? path.resolve(process.cwd(), "a.csv"); const FILE_B = process.env.COMPARE_FILE_B ?? path.resolve(process.cwd(), "b.csv"); const PHONE_COL_A = process.env.COMPARE_PHONE_COL_A ?? "phone"; const PHONE_COL_B = process.env.COMPARE_PHONE_COL_B ?? "phone"; const MODE = process.env.COMPARE_MODE ?? "intersection"; const OUTPUT_FILE = process.env.COMPARE_OUTPUT_FILE ?? path.resolve(process.cwd(), `compare-${MODE}.csv`); type CsvRow = Record; function normalizePhone(value: string): string { return value.replace(/\D+/g, ""); } function toCsv(rows: CsvRow[]): string { if (rows.length === 0) { return ""; } const headers = Array.from( rows.reduce((set, row) => { for (const key of Object.keys(row)) { set.add(key); } return set; }, new Set()), ); const escape = (value: string): string => { if (/[",\n\r]/.test(value)) { return `"${value.replace(/"/g, "\"\"")}"`; } return value; }; const lines = [headers.join(",")]; for (const row of rows) { lines.push(headers.map((header) => escape(row[header] ?? "")).join(",")); } return `${lines.join("\n")}\n`; } async function readCsv(filePath: string): Promise { const content = await readFile(filePath, "utf8"); return parse(content, { columns: true, skip_empty_lines: true, }) as CsvRow[]; } async function main(): Promise { const [rowsA, rowsB] = await Promise.all([readCsv(FILE_A), readCsv(FILE_B)]); const phonesB = new Set( rowsB.map((row) => normalizePhone(row[PHONE_COL_B] ?? "")).filter(Boolean), ); const matches: CsvRow[] = []; const onlyA: CsvRow[] = []; for (const row of rowsA) { const normalized = normalizePhone(row[PHONE_COL_A] ?? ""); if (!normalized) { continue; } if (phonesB.has(normalized)) { matches.push({ source: "a", normalized_phone: normalized, ...row, }); } else { onlyA.push({ source: "a", normalized_phone: normalized, ...row, }); } } let outputRows: CsvRow[]; switch (MODE) { case "intersection": outputRows = matches; break; case "only_a": outputRows = onlyA; break; default: throw new Error(`Unsupported COMPARE_MODE: ${MODE}. Use intersection or only_a.`); } await writeFile(OUTPUT_FILE, toCsv(outputRows), "utf8"); process.stdout.write(`${OUTPUT_FILE}\n`); } main().catch((error: unknown) => { const message = error instanceof Error ? error.message : String(error); process.stderr.write(`${message}\n`); process.exitCode = 1; });