Skip to content

Commit

Permalink
throw if UTF-8 text isn't encoded to Uint8Array
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Sep 22, 2022
1 parent c58bf2b commit c2b09ca
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -118,6 +118,10 @@

The primary branch for this repository was previously called `master` but is now called `main`. This change mirrors a similar change in many other projects.

* Throw an early error if decoded UTF-8 text isn't a `Uint8Array` ([#2532](https://github.com/evanw/esbuild/issues/2532))

If you run esbuild's JavaScript API in a broken JavaScript environment where `new TextEncoder().encode("") instanceof Uint8Array` is false, then esbuild's API will fail with a confusing serialization error message that makes it seem like esbuild has a bug even though the real problem is that the JavaScript environment itself is broken. This can happen when using the test framework called "Jest". With this release, esbuild's API will now throw earlier when it detects that the environment is unable to encode UTF-8 text correctly with an error message that makes it more clear that this is not a problem with esbuild.

## Unreleased

* Fix an obscure npm package installation issue with `--omit=optional` ([#2558](https://github.com/evanw/esbuild/issues/2558))
Expand Down
32 changes: 15 additions & 17 deletions lib/shared/stdio_protocol.ts
Expand Up @@ -394,44 +394,42 @@ class ByteBuffer {

export let encodeUTF8: (text: string) => Uint8Array
export let decodeUTF8: (bytes: Uint8Array) => string
let encodeInvariant: string

// For the browser and node 12.x
if (typeof TextEncoder !== 'undefined' && typeof TextDecoder !== 'undefined') {
let encoder = new TextEncoder();
let decoder = new TextDecoder();
encodeUTF8 = text => encoder.encode(text);
decodeUTF8 = bytes => decoder.decode(bytes);
encodeInvariant = 'new TextEncoder().encode("")'
}

// For node 10.x
else if (typeof Buffer !== 'undefined') {
encodeUTF8 = text => {
let buffer: Uint8Array = Buffer.from(text);

// The test framework called "Jest" breaks node's Buffer API. Normally
// instances of Buffer are also instances of Uint8Array, but not when
// esbuild is run inside of whatever weird environment Jest uses. More
// info: https://github.com/facebook/jest/issues/4422.
if (!(buffer instanceof Uint8Array)) {
// Construct a new Uint8Array with the contents of the buffer to force
// it to be a Uint8Array instance. This is wasteful since it's slower
// than just using the Buffer, but this should only happen when esbuild
// is run inside of Jest.
buffer = new Uint8Array(buffer);
}

return buffer;
};
encodeUTF8 = text => Buffer.from(text);
decodeUTF8 = bytes => {
let { buffer, byteOffset, byteLength } = bytes;
return Buffer.from(buffer, byteOffset, byteLength).toString();
}
encodeInvariant = 'Buffer.from("")'
}

else {
throw new Error('No UTF-8 codec found');
}

// Throw an error early if this isn't true. The test framework called "Jest"
// has some bugs regarding this edge case, and letting esbuild proceed further
// leads to confusing errors that make it seem like esbuild itself has a bug.
if (!(encodeUTF8('') instanceof Uint8Array))
throw new Error(`Invariant violation: "${encodeInvariant} instanceof Uint8Array" is incorrectly false
This indicates that your JavaScript environment is broken. You cannot use
esbuild in this environment because esbuild relies on this invariant. This
is not a problem with esbuild. You need to fix your environment instead.
`)

export function readUInt32LE(buffer: Uint8Array, offset: number): number {
return buffer[offset++] |
(buffer[offset++] << 8) |
Expand Down

0 comments on commit c2b09ca

Please sign in to comment.