Read the source and its declared rule
This original export uses one JSON record followed by LF. Its already extracted memo contains A, CRLF, B and must remain exactly that field value. A global CRLF-to-LF replacement changes content even though the resulting JSON is readable.
| Record | Input JSON |
|---|---|
| Base input | {"memo":"A\r\nB"} |
Compare the actual paths
JSON.stringify escapes the preserved field newlines; adding LF afterward sets record framing independently. Correct memo remains A B.
| Path | Output JSON |
|---|---|
| Misleading path | {"memo":"A\nB","exportRecord":"{\"memo\":\"A\\nB\"}\n"} |
| Corrected path | {"memo":"A\r\nB","exportRecord":"{\"memo\":\"A\\r\\nB\"}\n"} |
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};
import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
const memo=corrected?i.memo:i.memo.replace(/\r\n/g,'\n');
const exportRecord=JSON.stringify({memo})+'\n';
return {memo,exportRecord};
};
const cases=[{"label":"misleading base","input":{"memo":"A\r\nB"},"expected":{"memo":"A\nB","exportRecord":"{\"memo\":\"A\\nB\"}\n"},"corrected":false},{"label":"corrected base","input":{"memo":"A\r\nB"},"expected":{"memo":"A\r\nB","exportRecord":"{\"memo\":\"A\\r\\nB\"}\n"},"corrected":true},{"label":"single-line field","input":{"memo":"AB"},"expected":{"memo":"AB","exportRecord":"{\"memo\":\"AB\"}\n"},"corrected":true},{"label":"empty memo field","input":{"memo":""},"expected":{"memo":"","exportRecord":"{\"memo\":\"\"}\n"},"corrected":true}];
for(const test of cases){
const actual=run(test.input,test.corrected);
assert.deepEqual(actual,test.expected,test.label);
console.log(test.label,actual);
}
Check boundaries before the next load
A one-line memo and an empty permitted memo round-trip without invented newline content.
| Case | Input JSON | Expected output JSON |
|---|---|---|
| Single-line memo | {"memo":"AB"} | {"memo":"AB","exportRecord":"{\"memo\":\"AB\"}\n"} |
| Empty permitted memo | {"memo":""} | {"memo":"","exportRecord":"{\"memo\":\"\"}\n"} |
Must a single-record LF export also replace memo CRLF?
Show the worked answer
No. The record separator and field content have separate contracts. Preserve the memo and encode its CRLF within JSON.