Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 3x 4x 4x 4x 21x 4x | /**
* CSV helpers for the Room HTTP layer.
*
* - `csvToSocialCalc` converts a CSV string to a SocialCalc save string by
* delegating to the `csvToSave` wrapper in `@ethercalc/socialcalc-headless`,
* which calls `SocialCalc.ConvertOtherFormatToSave(csv, 'csv')`. This is
* the same entry point the legacy `src/main.ls` used via the `J` library
* (J.utils.to_socialcalc produces an object keyed by sheet name — we only
* consume the primary sheet here, matching the legacy `for k, save of …`
* first-iteration behavior).
*
* - `decodeDoubleEncoded` reproduces the `text/x-ethercalc-csv-double-encoded`
* round-trip (§7 item 4 in CLAUDE.md): UTF-8 decode → Latin-1 encode →
* UTF-8 decode. Legacy did this via `iconv-lite` (Node-only); we use the
* platform `TextDecoder('latin1')` / `TextEncoder` which is available in
* both workerd and Node 20+.
*/
import { csvToSave } from '@ethercalc/socialcalc-headless';
/** Convert a CSV string to a SocialCalc save string. */
export function csvToSocialCalc(csv: string): string {
return csvToSave(csv);
}
/**
* Re-encode a UTF-8 → Latin-1 → UTF-8 double-encoded body. Equivalent to
* the legacy `iconv-lite` triple-step.
*/
export function decodeDoubleEncoded(bytes: Uint8Array): string {
const first = new TextDecoder('utf-8').decode(bytes);
const latin1Bytes = new Uint8Array(first.length);
for (let i = 0; i < first.length; i++) {
// Latin-1 is a strict subset of Unicode up to U+00FF; code points above
// that never survived the original round-trip either (legacy would have
// produced the same replacement character). Mask to 8 bits.
latin1Bytes[i] = first.charCodeAt(i) & 0xff;
}
return new TextDecoder('utf-8').decode(latin1Bytes);
}
|