Skip to content

Support the endings option in the Blob and File constructors - #8461

Open
littledivy wants to merge 1 commit into
mainfrom
littledivy/2026-11-13-blob-endings
Open

littledivy wants to merge 1 commit into
mainfrom
littledivy/2026-11-13-blob-endings

Conversation

@littledivy

Copy link
Copy Markdown
Member

endings was jsg::Unimplemented on BlobPropertyBag and FilePropertyBag, so new Blob(parts, { endings }) threw for any value, even the valid 'transparent' and 'native'. Code that sets endings: 'native' when it builds a text file couldn't run.

In this patch:

  • endings is parsed as the File API's EndingType enum. 'transparent' (the default) keeps the bytes as they are. Any other value, such as null, '' or 'NATIVE', throws a TypeError, as in browsers.
  • With 'native', each string part has its CRLF and lone CR converted to the native line ending before it is encoded. Buffer and Blob parts are left as they are, and each string is converted on its own, so ['\r', '\n'] gives two line endings.
  • The native line ending is LF on every platform, including workerd on Windows. Workers run on Linux, so a Blob built in local development has the same bytes as one built when deployed.
  • The WPT Blob-constructor-endings and File-constructor-endings tests now pass. Conversion tests are in blob-test.js, since WPT only checks which values are accepted.
before after
new Blob(['a\r\nb'], { endings: 'native' }) throws Error 'a\nb'
new Blob(['a\r\nb'], { endings: 'transparent' }) throws Error 'a\r\nb'
new Blob([], { endings: 'NATIVE' }) throws Error throws TypeError

The option threw for every value before, so no working code changes behaviour, and it ships without a compatibility flag. Leaving endings out gives the same bytes as before.

`endings` was `jsg::Unimplemented` on `BlobPropertyBag` and `FilePropertyBag`, so `new Blob(parts, { endings })` threw for any value, even the valid `'transparent'` and `'native'`. Code that sets `endings: 'native'` when it builds a text file couldn't run.

In this patch:

- `endings` is parsed as the File API's `EndingType` enum. `'transparent'` (the default) keeps the bytes as they are. Any other value, such as `null`, `''` or `'NATIVE'`, throws a `TypeError`, as in browsers.
- With `'native'`, each string part has its CRLF and lone CR converted to the native line ending before it is encoded. Buffer and Blob parts are left as they are, and each string is converted on its own, so `['\r', '\n']` gives two line endings.
- The native line ending is LF on every platform, including workerd on Windows. Workers run on Linux, so a Blob built in local development has the same bytes as one built when deployed.
- The WPT `Blob-constructor-endings` and `File-constructor-endings` tests now pass. Conversion tests are in `blob-test.js`, since WPT only checks which values are accepted.

| | before | after |
|---|---|---|
| `new Blob(['a\r\nb'], { endings: 'native' })` | throws `Error` | `'a\nb'` |
| `new Blob(['a\r\nb'], { endings: 'transparent' })` | throws `Error` | `'a\r\nb'` |
| `new Blob([], { endings: 'NATIVE' })` | throws `Error` | throws `TypeError` |

The option threw for every value before, so no working code changes behaviour, and it ships without a compatibility flag. Leaving `endings` out gives the same bytes as before.
@littledivy
littledivy requested review from a team as code owners November 14, 2026 04:34

@clanky-the-clanker clanky-the-clanker Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved — I found nothing to fix: the endings parsing and the CRLF/CR-to-LF conversion are correct, the new tests cover them, and the change is safe without a compatibility flag because the option always threw before.

Not opened by the correctness review: 3 changed files it was meant to read
  • types/generated-snapshot/experimental/index.ts
  • types/generated-snapshot/index.d.ts
  • types/generated-snapshot/index.ts

The decision is advisory: this review is a comment and never approves, blocks or requests changes on the pull request.


✅ All checks passed

🔒 Security: ✅ LGTM

No issues found. The output buffer is exactly input length minus the CRLF count, so the conversion cannot write past the end.


📖 AGENTS.md: ✅ LGTM

No issues found.


📋 Code Quality: ✅ LGTM

No issues found. The line-ending conversion sizes its output correctly, leaves strings without a CR untouched, and runs before the part sizes are cached and the blob size limit is checked.


⚡ Performance: ✅ LGTM

No issues found. A string with no CR is returned without allocating, and conversion only happens when endings: 'native' is set.


📝 Documentation: ✅ LGTM

No issues found.


Reviewed commit: 09a8115d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant