Skip to content

fix(core): keep the external-core stager CRLF-safe - #322

Open
jhodges10 wants to merge 1 commit into
vercel-labs:mainfrom
jhodges10:fix/external-core-stager-crlf
Open

fix(core): keep the external-core stager CRLF-safe#322
jhodges10 wants to merge 1 commit into
vercel-labs:mainfrom
jhodges10:fix/external-core-stager-crlf

Conversation

@jhodges10

Copy link
Copy Markdown
Contributor

The bug

Every TypeScript-core app fails to build on Windows, and the error blames the SDK rather than the stager that caused it:

error SC0001: Module '"./sdk/core.ts"' has no exported member 'Cmd'.

Git for Windows installs with core.autocrlf=true and this repository carries no .gitattributes, so a Windows checkout lands every source in the working tree with CRLF. stage_external_core.mjs splits its inputs on "\n" and then makes line-shaped decisions about them, which leaves a trailing CR that a $-anchored terminator or an exact-equality compare no longer matches.

Transform 4 fails hardest. Its terminator scan matches nothing, so the first alias it means to drop reads as an unterminated multi-line declaration, skipping latches on and never clears, and the remainder of the static @native-sdk/core restatement is dropped from the stage — Cmd and Sub with it.

Concretely, staging packages/core/compile-surface/core.ts for examples/voice-memo: 25,543 bytes in, 2,995 out, truncated at line 90. The alias that trips it is single-line and ends in ;:

export type AudioState = "loaded" | "position" | "completed" | "failed" | "rejected" | "spectrum";

It is correctly terminated. Only the CR makes it read otherwise.

Transform 3's Bytes-alias folding fails the same way — line !== "export type Uint8Array = Uint8Array;" never matches — quietly keeping the alias it exists to remove.

The fix

Tolerate the optional CR in all three guards. This is a no-op on LF input, so the staged bytes the compiled-core batteries pin byte-identical against the transpiler lane are unchanged, and the fixture twin in tests/compiled-core/build_core.sh needs no matching edit — it runs under POSIX shell on LF inputs.

.gitattributes

Added so the working tree is LF on every platform. This repository reads its own sources byte-exactly in more places than most — the staged tree, the compiled-core output pins, the pinned goldens, and the POSIX shell the gate and CI scripts run under — so a CRLF checkout does not fail loudly, it changes build output. The regex fix addresses one symptom; this closes the class.

It is a safe addition: the index is already all-LF, so git add --renormalize . after adding it produces zero churn. third_party/** is marked -text because the WebView2 headers Microsoft ships are committed CRLF.

Happy to split this into its own PR if you would rather take the stager fix alone.

Tests

packages/core/test/stage_external_core.test.ts stages a fixture under both line endings and asserts the surface survives past a deduped alias, the dedupe still happens, the Bytes fold still happens, and CRLF staging agrees with LF staging line for line.

Against the unpatched stager the three CRLF cases fail and every LF case passes — which is also the evidence that the fix changes nothing on LF:

✔ LF: the static surface survives past a deduped alias
✔ LF: transform 4 still drops the duplicated alias
✔ LF: transform 3 still folds the Bytes alias away
✖ CRLF: the static surface survives past a deduped alias
✔ CRLF: transform 4 still drops the duplicated alias
✖ CRLF: transform 3 still folds the Bytes alias away
✖ CRLF staging agrees with LF staging line for line

With the fix, all 7 pass. npm test in packages/core is 140/143; the 3 failures are in docs_samples and reproduce identically on unpatched main on this machine.

Verified end to end by building examples/voice-memo on Windows, which now produces zig-out/bin/voice-memo.exe.

🤖 Generated with Claude Code

On a Windows checkout Git ships core.autocrlf=true and this repository
carries no .gitattributes, so every source lands in the working tree with
CRLF. The stager splits its inputs on "\n" and then makes line-shaped
decisions about them, which leaves a trailing CR that a `$`-anchored
terminator or an exact-equality compare no longer matches.

Transform 4 fails hardest. Its terminator scan never matches, so the first
alias it means to drop reads as an unterminated multi-line declaration,
`skipping` latches on and never clears, and the remainder of the static
@native-sdk/core restatement is dropped from the stage. The build does not
fail there; it fails much later, and blames the SDK:

    error SC0001: Module '"./sdk/core.ts"' has no exported member 'Cmd'.

Every TypeScript-core app is unbuildable on Windows as a result — the
staged surface is truncated at the first deduped alias, taking Cmd and Sub
with it. Transform 3's Bytes-alias folding fails the same way, quietly
keeping the alias it exists to remove.

Tolerate the optional CR in all three guards. This is a no-op on LF input,
so the staged bytes the compiled-core batteries pin against the transpiler
lane are unchanged, and the fixture twin in tests/compiled-core needs no
matching edit.

Add .gitattributes so the working tree is LF on every platform. This
repository reads its own sources byte-exactly in several places, so a CRLF
checkout does not fail loudly, it changes build output. The index is
already all-LF, so this changes checkout behavior only; third_party keeps
its upstream bytes, since the WebView2 headers are committed CRLF.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

@jhodges10 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@jhodges10

Copy link
Copy Markdown
Contributor Author

@ctate I get the impression based on this and the fact there's only a single example that declares Window support that it's a bit of a lower priority right now 😆!

I'm prototyping a video editor to see how far I can get so I'm focused on cross-platform compatibility from the start, so you'll probably see quite a few more PR's from me re: Windows support.

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