Skip to content

Commit 09fc331

Browse files
committed
buffer: normalize lone "\r" in Blob native line endings
`new Blob(parts, { endings: 'native' })` failed to normalize a standalone carriage return. The replacement regex only matched `\n` and `\r\n`, so a lone `\r` (and runs such as `\r\r`) were left untouched instead of being converted to the platform's native line ending. The WHATWG "convert line endings to native" algorithm requires `\r`, `\n`, and `\r\n` to all be normalized. Match `\r\n` before a lone `\r` so that CRLF collapses to a single native ending. Refs: https://w3c.github.io/FileAPI/#convert-line-endings-to-native Signed-off-by: Daijiro Wachi <daijiro.wachi@gmail.com>
1 parent bfb2fa7 commit 09fc331

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

lib/internal/blob.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function getSource(source, endings) {
122122
source = new Uint8Array(source);
123123
} else if (!isArrayBufferView(source)) {
124124
if (endings === 'native')
125-
source = RegExpPrototypeSymbolReplace(/\n|\r\n/g, source, EOL);
125+
source = RegExpPrototypeSymbolReplace(/\r\n|\r|\n/g, source, EOL);
126126
source = enc.encode(source);
127127
}
128128

test/parallel/test-blob.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,24 @@ assert.throws(() => new Blob({}), {
403403
const b = new Blob(['hello\n'], { endings: 'native' });
404404
assert.strictEqual(b.size, EOL.length + 5);
405405

406+
// The WHATWG "convert line endings to native" algorithm normalizes every
407+
// standalone "\r", "\n", and "\r\n" sequence to the native line ending.
408+
// Refs: https://w3c.github.io/FileAPI/#convert-line-endings-to-native
409+
(async () => {
410+
const cases = [
411+
['a\rb', `a${EOL}b`],
412+
['a\nb', `a${EOL}b`],
413+
['a\r\nb', `a${EOL}b`],
414+
['a\r\rb', `a${EOL}${EOL}b`],
415+
['a\n\rb', `a${EOL}${EOL}b`],
416+
['\r\n\r', `${EOL}${EOL}`],
417+
];
418+
for (const [input, expected] of cases) {
419+
const blob = new Blob([input], { endings: 'native' });
420+
assert.strictEqual(await blob.text(), expected);
421+
}
422+
})().then(common.mustCall());
423+
406424
[1, {}, 'foo'].forEach((endings) => {
407425
assert.throws(() => new Blob([], { endings }), {
408426
code: 'ERR_INVALID_ARG_VALUE',

0 commit comments

Comments
 (0)