fix(compiler): accept any Uint8Array as compile() input and decode it once - #460
YevheniiKotyrlo wants to merge 3 commits into
Conversation
… once `compile` typed its input as Node's `Buffer` and read it back with `toString()`. A `Uint8Array` that is not a `Buffer` stringifies to its bytes rather than its text, and the type kept every consumer typing against the compiler in a program without Node types from compiling at all. Widen the input to `Uint8Array | string`, decode through `TextDecoder` once, and read the rem hint and the debug log from that one string.
EvidenceThe wrong answer is plausible rather than absent: One case in Mutation proof: restoring
No device frame: the type half is a compile failure in the consumer's own program, and the byte path is reachable only from outside the bundler. |
The type half of this change had no test. `Buffer` in `compile`'s declaration is a TS2591 raised inside `node_modules` for any consumer whose tsconfig does not pull in `@types/node` — and `native/conditions/index.d.ts` imports `StyleRule` from `react-native-css/compiler`, so the surface reaches them all. Two cases over the compiler entry, type-checked with `types: []`: no diagnostic naming a missing Node global, and a control that reports one when a global is genuinely absent, so the first cannot pass over a program that resolved nothing. Checked against `src/` rather than `dist/`, so it needs no build: the published declarations are generated from these files and the `source` condition resolves a consumer here directly. Restoring `Buffer | string` fails it with the exact diagnostic above.
A coverage sweep found `defaultLogger(source)` never executed: the `debug` namespace is off under jest, so the only read this suite drove was the rem probe. That is one of the two sites this change touches, and the one whose wrong answer is a debug trail of byte values nobody can read. `debug.enable` flips the instance the compiler module already built, so the test needs no module reload; the sink is restored and the namespace disabled in a `finally`. Restoring `code.toString()` there fails it.
Problem
compiletypes its input as Node'sBuffer, so aUint8Arraythat is not aBufferpasses the type and stringifies to its byte values joined with commas — and that declaration reaches the public types, where a program without@types/nodefails insidenode_modules.Two things follow.
The declaration reaches every consumer of the native types.
native/conditions/index.d.tsimportsStyleRulefromreact-native-css/compiler, whose index re-exportscompile, so a program without@types/nodefails withTS2591: Cannot find name 'Buffer'and no first-party line named.And
toString()on a plainUint8ArrayisArray.prototype.toString— whatTextEncoder,fetchandBun.file().bytes()hand out. The rem probe then reads58,114,111,111,116instead of CSS, so:root { font-size }matches nothing,effectiveRemfalls back to 14, and everyremin the sheet is scaled wrong. lightningcss still receives the bytes it wanted, so nothing downstream reports it.Solution
Uint8Array | string, decoded once throughTextDecoder. ABufferIS aUint8Array, so every existing caller still type-checks and the decode is the same UTF-8.Tests
One case in
compiler.test.tsxcompiles the same sheet as text, asTextEncoderoutput and asBuffer.from, asserting the three stylesheetstoStrictEqual. The sheet carries:root { font-size: 16px }and a1rempadding, so the byte input is not merely accepted — its rem is read. Restoringcode.toString()at the rem probe fails it withpadding 16 expected, 14 received.public-surface-node-types.test.tscovers the type half, which nothing asserted before: two cases type-check the compiler entry withtypes: []— no diagnostic naming a missing Node global, plus a control that reports one when a global is genuinely absent, so the first cannot pass over a program that resolved nothing. It readssrc/rather thandist/, so it needs no build. RestoringBuffer | stringfails it with the exactTS2591above.Every caller in the suite and in the Metro transformer hands
compilea string or a realBuffer, and every program that type-checks the package has Node's types in scope — which is why neither half surfaces today.Mutation-proved: reverting the
src/diff and re-running these files alone turns 3 of 14 red.Verification
yarn test src/__tests__/compiler50 passed, 6 skipped ·yarn typecheck0 ·yarn lint0Known limits
No existing issue tracks this — searched the tracker for
Uint8Array,Buffer compileandTextDecoder, zero relevant hits.Base
Branched off
f70c402.mainhas since taken #451 (a5002c5). 2 of the 3 files this changes also moved there (src/__tests__/compiler/compiler.test.tsx,src/compiler/compiler.ts), and it still merges cleanly onto currentmain. Every measurement above was taken onf70c402. Say the word and I will re-apply it onto currentmain.