Skip to content
Astera Technology

Why did a newline cleanup change an imported memo?

Convert the output record separator while preserving newlines inside the field.

Download complete case notes and answer keys ↓

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.

Filled synthetic input
RecordInput JSON
Base input{"memo":"A\r\nB"}
Download editable CSV ↓

Compare the actual paths

JSON.stringify escapes the preserved field newlines; adding LF afterward sets record framing independently. Correct memo remains A B.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"memo":"A\nB","exportRecord":"{\"memo\":\"A\\nB\"}\n"}
Corrected path{"memo":"A\r\nB","exportRecord":"{\"memo\":\"A\\r\\nB\"}\n"}
Download editable CSV ↓
Local Node.js program: 22.23.3 or 24.14.1
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);
}
Download runnable example ↓

Check boundaries before the next load

A one-line memo and an empty permitted memo round-trip without invented newline content.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Single-line memo{"memo":"AB"}{"memo":"AB","exportRecord":"{\"memo\":\"AB\"}\n"}
Empty permitted memo{"memo":""}{"memo":"","exportRecord":"{\"memo\":\"\"}\n"}
Download editable CSV ↓

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.

Related resources