Skip to content

node/types: replace the StringOrBuffer parser bool flags with enums - #39164

Merged
alii merged 5 commits into
mainfrom
farm/6e4bfbe0/node-types-flag-enums
Aug 15, 2026
Merged

alii merged 5 commits into
mainfrom
farm/6e4bfbe0/node-types-flag-enums

Conversation

@robobun

@robobun robobun commented Aug 15, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • mordant's bare_bool_args reports four functions in src/runtime/node/types.rs (the bare_bool_args:src/runtime/node/types.rs = 4 baseline entry): BlobOrStringOrBuffer::from_js_maybe_file_maybe_async(.., allow_file, is_async), StringOrBuffer::from_js_maybe_async(.., is_async, allow_string_object), from_js_with_encoding_maybe_async_into(..) and from_js_with_encoding_maybe_async(..) (same two bools). Each has a caller passing bare literals, e.g. from_js_maybe_file_maybe_async(global, value, true, true) and from_js_maybe_async(global, value, false, true), where nothing says which flag is which.
  • The callers outside the file are not much clearer: BunObject.rs and JSTranspiler.rs pass true, allow_string_object, PBKDF2::from_js(.., true) / (.., false) forward a bare bool, Scrypt passes IS_ASYNC, true.
  • allow_file is also named backwards: allow_file == true is what makes a file-backed Blob throw "File blob cannot be used here" (types.rs:109 on main). Only the Redis client passes false.

Fix

  • Each flag becomes a two-variant enum, and the four functions (plus their forwarders from_js_maybe_file and from_js_with_encoding_value_allow_string_object) take the enums instead of bools:
    • is_async -> Flavor::{Sync, Async}. This is node_fs.rs's existing enum for the same fact (is this call serviced inline or on the thread pool). It moves to types.rs so the argument parsers can use it; node_fs.rs re-exports it, so the node_fs::Flavor / node::fs::Flavor callers are untouched.
    • allow_string_object -> StringObjects::{Allow, Reject}.
    • allow_file -> FileBlobs::{Allow, Reject}, named for what the flag does: from_js / from_js_async pass Reject (was true), the Redis client passes Allow (was false).
  • Call sites now read from_js_maybe_async(global, value, Flavor::Async, StringObjects::Allow), and the bodies compare against a variant where they tested the bool. Every call maps its old literal to the equivalent variant, so there is no behavior change. PBKDF2::from_js takes Flavor itself, since its is_async only existed to be forwarded; Scrypt (const-generic IS_ASYNC) and WriteFile::from_js (arguments.will_be_async) convert their bool once.
  • Comments describing the old parameters (is_async=true) are updated, including the ThreadSafe::adopt doc in src/jsc/node_path.rs.
  • mordant-baseline.toml: the bare_bool_args:src/runtime/node/types.rs entry is removed. Checked with mordant on bun_runtime (cargo dylint --all -p bun_runtime) with the entry removed: the unfixed tree reports the four functions above as over the baseline, this tree reports nothing, and MORDANT_BASELINE_WRITE=1 regenerates the [bun_runtime] section without the entry and without any new one. The regeneration also wanted to drop two entries this PR has nothing to do with, narrowed_two_ways:src/runtime/node/node_crypto_binding.rs (its as usize cast was removed by crypto: store PBKDF2's key length as usize #37648, after the baseline was last regenerated) and always_unwrapped_option:src/install/PackageInstall.rs, so the file is edited by hand here and those are left for the next full regeneration.
  • Tests: the value each call site passes is the only thing this change can get wrong, so the two flag values that had no coverage get a test each; the rest were already pinned (bun-cryptohasher.test.ts has Bun.file() rejected and in-memory Blob / new String inputs accepted by the static hashers, test-fs-write-file-sync.js has writeFileSync(new String(..)) rejected, bundler_files.test.ts has Blob content accepted).
    • test/bundler/bundler_files.test.ts: Bun.build({ files }) rejects a Bun.file() blob with "File blob cannot be used here" (FileBlobs::Reject on the from_js_async site).
    • test/js/node/fs/fs.test.ts: writeFileSync, appendFileSync, callback writeFile and appendFile reject a String wrapper with ERR_INVALID_ARG_TYPE and create nothing (StringObjects::Reject on the one site that uses it, on both its sync and its thread-pool flavor; Node behaves the same for all four).
    • Both pass on main as well: they pin behavior this refactor preserves, there is no input that distinguishes the old code from the new.
  • Verified with bun bd:
    • bun bd test test/js/node/fs/fs.test.ts: 511 pass (512 with the new case); bun bd test test/bundler/bundler_files.test.ts: 24 pass.
    • test/js/node/test/parallel/test-fs-write-file-sync.js, test-fs-write-file.js, test-fs-write-file-buffer.js, test-fs-write-file-typedarrays.js, test-fs-append-file.js, test-fs-append-file-sync.js, test-fs-promises-write-optional-params.js, test-fs-write-optional-params.js, test-fs-write.js: all pass.
    • bun bd test test/js/node/crypto/pbkdf2.test.ts test/js/node/crypto/scrypt.test.ts test/js/bun/util/bun-cryptohasher.test.ts test/js/bun/util/zstd.test.ts test/js/bun/transpiler/transpiler-tsconfig-uaf.test.ts: 535 pass (pbkdf2/scrypt sync and async, FileBlobs::Reject via CryptoHasher, the async zstd and Transpiler.transform paths).
    • A script exercising each changed path once (file blob and new String inputs to CryptoHasher, writeFileSync / fs.promises.writeFile, async zstd, async Transpiler.transform, pbkdf2/scrypt sync and async, net.Socket#write with an encoding, and Redis set with number / string / Buffer / Blob / Bun.file() arguments against a local server) prints identical output on this build and on the released binary. The valkey test files need the docker redis_unified service and are skipped locally.

Background

  • StringOrBuffer / BlobOrStringOrBuffer (src/runtime/node/types.rs) parse the "string or Buffer (or Blob)" arguments of node:fs, node:crypto, Bun.Transpiler, the zlib/zstd functions, sockets and the Redis client. Parsing for a call that runs on the thread pool has to produce a value that survives leaving the JS thread: strings are copied or re-referenced thread-safely, JS buffers are pinned and protect()ed until the job's owner calls unprotect(). That is what is_async selected and what Flavor::Async selects now.
  • allow_string_object exists because Node's fs.writeFile family rejects new String("..") wrapper objects while every other caller unwraps them.
  • mordant-baseline.toml is the ratchet for the lint pack run by bun run rust:mordant: it records the per-(lint, file) finding counts that predate the job, so CI only fails on a new finding. bare_bool_args fires on a crate-private function with two or more bool parameters when some call passes bare true/false for at least two of them; fixing a site means deleting (or decrementing) its entry.

no test proof · iteration 3 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/js/node/fs/fs.test.ts

StringOrBuffer::from_js_maybe_async, from_js_with_encoding_maybe_async,
from_js_with_encoding_maybe_async_into and
BlobOrStringOrBuffer::from_js_maybe_file_maybe_async took two bools each,
and several callers passed bare literals (`.., true, true`).

is_async is now node_fs's Flavor (moved into types.rs, node_fs re-exports
it), allow_string_object is StringObjects::{Allow, Reject}, and allow_file
is FileBlobs::{Allow, Reject}, named for what it does: the old `true` was
the value that rejects file-backed blobs. Every call passes the variant
equivalent to the literal it passed before; no behavior change.

Clears the bare_bool_args entry for this file in mordant-baseline.toml.
@coderabbitai

coderabbitai Bot commented Aug 15, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ec7888ea-3fee-473c-9d95-1e1b6b27c923

📥 Commits

Reviewing files that changed from the base of the PR and between e1a4ba7 and fbcaec0.

📒 Files selected for processing (13)
  • mordant-baseline.toml
  • src/jsc/node_path.rs
  • src/runtime/api/BunObject.rs
  • src/runtime/api/JSTranspiler.rs
  • src/runtime/crypto/PBKDF2.rs
  • src/runtime/node.rs
  • src/runtime/node/node_crypto_binding.rs
  • src/runtime/node/node_fs.rs
  • src/runtime/node/types.rs
  • src/runtime/socket/socket_body.rs
  • src/runtime/valkey_jsc/js_valkey_functions.rs
  • test/bundler/bundler_files.test.ts
  • test/js/node/fs/fs.test.ts
💤 Files with no reviewable changes (1)
  • mordant-baseline.toml

Walkthrough

The PR replaces boolean argument-parsing controls with Flavor, StringObjects, and FileBlobs policies. Runtime call sites, public re-exports, documentation, and tests are updated accordingly.

Changes

Argument parsing policy migration

Layer / File(s) Summary
Policy enums and parsing contracts
src/runtime/node/types.rs, src/runtime/node.rs, mordant-baseline.toml
Adds the policy enums and propagates them through string, buffer, Blob, and encoding-aware parsers.
Crypto and filesystem integration
src/runtime/crypto/PBKDF2.rs, src/runtime/node/node_crypto_binding.rs, src/runtime/node/node_fs.rs
Updates PBKDF2, Scrypt, and filesystem conversion paths to use explicit synchronous or asynchronous policies.
Runtime consumer migration
src/runtime/api/BunObject.rs, src/runtime/api/JSTranspiler.rs, src/runtime/socket/socket_body.rs, src/runtime/valkey_jsc/js_valkey_functions.rs, src/jsc/node_path.rs
Migrates compression, transpilation, socket, Valkey, and related documentation call sites to the enum-based APIs.
Argument rejection tests
test/bundler/bundler_files.test.ts, test/js/node/fs/fs.test.ts
Tests rejection of file-backed Blobs in bundling and boxed String objects in filesystem APIs.

Possibly related PRs

  • oven-sh/bun#37944: Modifies related async Node argument and buffer handling in types.rs and node_fs.rs.

Suggested reviewers: jarred-sumner, dylan-conway

Merge Risk: ⚪ Minimal · up to fbcae

This refactor replaces ambiguous parser booleans with descriptive enums while preserving behavior, supported by targeted tests and lint validation; no actionable merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description explains the problem, implementation, behavior preservation, tests, and verification results, although it does not use the template headings.
Title check ✅ Passed The title clearly identifies the main change: replacing boolean parser flags with enums in src/runtime/node/types.rs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@robobun

robobun commented Aug 15, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 4:05 PM PT - Aug 15th, 2026

@alii, your commit fbcaec0 is building: #98748

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

Related rather than a duplicate: #37180 is a workspace-wide pass (539 files, currently conflicting) that retypes these same four functions with bool_enum! types IsAsync, AllowStringObject and AllowFile. This PR covers only the types.rs sites mordant reports and differs in two choices: it reuses node_fs's Flavor instead of adding a second Sync/Async enum next to it, and it names the file flag by its effect (FileBlobs::Reject is the value that throws on a Bun.file() blob), where #37180 keeps the existing polarity as AllowFile::Yes. If #37180 lands first this can be closed; if this lands first, #37180 picks up conflicts in the files listed here (all of them are in its file list).

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — mechanical bool→enum refactor with every literal mapped to its equivalent variant.

What was reviewed:

  • Traced each bool→enum mapping at every call site (is_async↔Flavor, allow_string_object↔StringObjects, allow_file↔FileBlobs with the polarity fix) — all preserve behavior.
  • Confirmed the Flavor move from node_fs.rs to types.rs keeps ConstParamTy and the pub use re-export, so external node::fs::Flavor callers (Blob/fetch/SSLConfig/copy_file) are unaffected.
  • Grepped for all callers of the re-signatured functions and PBKDF2::from_js — every one is in the diff; the Rust type system enforces no site was missed.
Extended reasoning...

Overview

This PR replaces three bare bool parameters on the StringOrBuffer/BlobOrStringOrBuffer argument parsers in src/runtime/node/types.rs with two-variant enums (Flavor::{Sync,Async}, StringObjects::{Allow,Reject}, FileBlobs::{Allow,Reject}), updates the ~9 files that call them, moves the pre-existing Flavor enum from node_fs.rs to types.rs (re-exported so external callers are untouched), and removes the corresponding bare_bool_args mordant baseline entry. Comments referencing the old parameter names are updated in place.

Security risks

None. This is a type-level refactor of internal function signatures with no change to validation, allocation, protection/unprotection, or thread-safety semantics. Every conditional in the function bodies maps one-to-one from the old bool test to the equivalent enum comparison.

Level of scrutiny

Low-to-medium. The change touches memory-safety-adjacent code (the Flavor::Async branches take protect() and pin buffers), but the refactor is purely mechanical and compiler-enforced: Rust's type system guarantees every call site was updated, and I verified each old-literal→new-variant mapping individually. The one non-obvious mapping is FileBlobs, where the old allow_file was named backwards (true meant reject); the diff maps true→Reject and false→Allow at every site (from_js/from_js_async and both valkey call sites), and the body test if allow_file && ... becomes if file_blobs == FileBlobs::Reject && ..., preserving behavior.

Other factors

The PR description documents extensive verification against existing tests (fs, pbkdf2/scrypt sync+async, zstd, transpiler, CryptoHasher) plus a manual A/B script against the released binary. No new test is warranted since the change is a compiler-verified renaming with no behavioral delta. The Flavor enum retains its ConstParamTy derive so const-generic uses in node_fs.rs continue to compile, and the pub use super::types::Flavor re-export keeps the four external node::fs::Flavor references resolving.

@github-actions

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. Replace boolean flag parameters with two-variant enums #37180 - Converts the same StringOrBuffer/BlobOrStringOrBuffer parsers in src/runtime/node/types.rs from bool flags to two-variant enums (IsAsync/AllowStringObject/AllowFile via bun_core::bool_enum!) on the same function signatures, and shares 9 of this PR's 11 files — though as a 539-file repo-wide sweep it is a superset in scope.

🤖 Generated with Claude Code

Bun.build's files option rejecting a Bun.file() blob (the async parser's
file-blob setting) and writeFile/appendFile rejecting a String wrapper on
both the sync and callback paths (the one site that turns String objects
away) had no coverage; the other flag values already have tests.
@robobun

robobun commented Aug 15, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status: reproduced the four bare_bool_args findings with mordant on bun_runtime (baseline entry removed, unfixed tree reports them, this tree reports none); fix is the enum change described above, plus the two tests from 2ef964f. Approved; current head is the second merge of main (6760001); the diff against main is unchanged.

CI: the red lanes are main issues, not this diff, and each has been reported for main-break triage.

  • Build #98665 (first merge of main, 49858b9): test/js/web/fetch/blob.test.ts "Bun.file(path).slice(start, end) streams only the slice" on debian 13 x64-asan. The same test fails identically on a debug+ASAN build of that merge's main parent (7592a6b) without this PR's changes, and Blob: drop is_bun_file, a duplicate of needs_to_read_file #39158's description records the same failure on a clean main at 88a6398.
  • Build #98694 (second merge of main, 6760001): test/bake/deinitialization.test.ts, a segfault during dev server teardown on windows 2019 x64, which CI itself marks as pre-existing; nothing in this PR touches bake.
    Everything else in both builds is marked flaky (passed on retry or alone). The diff is green on every other lane and on the GitHub Actions checks (mordant, clippy, Format, source lints). Not retriggering, since neither red is fixed by a rerun of this branch.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — mechanical bool→enum refactor with every call site mapped 1:1.

What was reviewed:

  • Traced every is_async/allow_string_object/allow_file literal at all 9 call-site files to its enum variant; each maps correctly, including the FileBlobs polarity fix (old allow_file=true ⇒ throw ⇒ FileBlobs::Reject).
  • Flavor moved from node_fs.rs to types.rs with identical derives (ConstParamTy preserved for const-generic use) and re-exported, so the 4 external fs::Flavor callers are untouched.
  • The two new tests pin existing behavior (StringObjects::Reject for writeFile's new String() rejection; FileBlobs::Reject for Bun.build files) rather than testing anything new.
Extended reasoning...

Overview

Replaces three bare bool parameters on the StringOrBuffer / BlobOrStringOrBuffer argument parsers in src/runtime/node/types.rs with two-variant enums (Flavor::{Sync,Async}, StringObjects::{Allow,Reject}, FileBlobs::{Allow,Reject}), updates all call sites across 9 source files, moves the pre-existing Flavor enum from node_fs.rs into types.rs (re-exported for compatibility), removes the corresponding bare_bool_args mordant baseline entry, and adds two tests that pin the flag values.

Security risks

None. This is a type-level refactor of internal function signatures with no change to validation, parsing, or thread-safety semantics. The Flavor::Async path still protect()s buffers exactly where is_async == true did.

Level of scrutiny

Medium — the parsers are on the hot path for node:fs/node:crypto/zstd/sockets/Redis, and a swapped variant would silently change protect/unprotect pairing or String-object acceptance. I traced each of the ~20 call-site literals individually against the old bool value: true/is_async→Flavor::Async, false→Flavor::Sync, allow_string_object=true→StringObjects::Allow, false→Reject, and the misleadingly-named allow_file=true (which threw on file blobs) →FileBlobs::Reject at from_js/from_js_async/valkey number branch, false→Allow at the valkey general branch. All match.

Other factors

  • Flavor's derive set (including core::marker::ConstParamTy, required by const-generic dispatch in node_fs.rs) is preserved verbatim in the move; the pub use super::types::Flavor re-export keeps the 4 external fs::Flavor callers (fetch.rs, Blob.rs, copy_file.rs, SSLConfig.rs) compiling unchanged.
  • Grep confirms no callers of the retyped functions outside the PR's changed files.
  • The PR description documents extensive test verification across fs/crypto/zstd/transpiler/redis, plus a differential run against the released binary.
  • The two added tests are well-formed (synchronous throws, toThrowWithCode with specific error class/code, hermetic tempdir) and pin behavior that would break if a future edit swapped a variant.
  • The overlap with #37180 is a coordination note, not a correctness concern for this change.

Comment thread src/runtime/node/node_crypto_binding.rs
Comment thread src/runtime/node/node_crypto_binding.rs
Comment thread src/runtime/node/node_fs.rs
Comment thread src/runtime/node/types.rs
Comment thread src/runtime/node/types.rs
Comment thread src/runtime/node/types.rs
Comment thread src/runtime/node/types.rs
Comment thread src/runtime/node/types.rs
alii
alii previously approved these changes Aug 15, 2026
@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

On the comment-cop threads: the groups it flagged in node_crypto_binding.rs (the Scrypt struct comment and its Unprotect doc), types.rs:334 (StringOrBuffer's Unprotect doc) and the node_fs.rs re-export comment are pre-existing comments whose is_async=true reference is updated to the variant (one of them re-wrapped); the remaining four are the docs of the enums this PR introduces or moves (Flavor, StringObjects, StringObjects::Reject, FileBlobs), which record what each variant obliges the caller to do (Async means the owner has to unprotect()), and that StringObjects::Reject reports "not a string or buffer" while FileBlobs::Reject throws. Nothing in them justifies a workaround, so they stay as reviewed; I will resolve the threads once the API lets me.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reviewed this PR and didn't find any bugs — every bool→enum mapping at each call site checks out (is_async↔Flavor, allow_string_object↔StringObjects, and the polarity-corrected allow_file↔FileBlobs). A human look is still worthwhile: comment-cop left eight unaddressed inline flags on the new enum doc comments and on pre-existing comments this diff only reworded, and there's the overlap with #37180 to coordinate.

What was reviewed

  • Traced every changed call site (types.rs internal forwarders, BunObject/JSTranspiler/PBKDF2/Scrypt/WriteFile/socket/valkey) — each old literal maps to the semantically identical variant.
  • Confirmed Flavor keeps ConstParamTy and the node_fs/node re-exports, so existing fs::Flavor const-generic callers are unchanged; grepped for other callers of the retyped functions — all are in the diff.
  • Checked the two new tests use tempDir, assert the negative contract (nothing created), and pin behavior this refactor preserves.
Extended reasoning...

Overview

This PR replaces three bare bool parameters on the StringOrBuffer/BlobOrStringOrBuffer argument parsers in src/runtime/node/types.rs with two-variant enums: is_async → Flavor::{Sync,Async} (moved from node_fs.rs and re-exported there), allow_string_object → StringObjects::{Allow,Reject}, and allow_file → FileBlobs::{Allow,Reject} (renaming to match what the flag actually does — the old allow_file=true was the value that rejected file blobs). It updates all callers in BunObject.rs, JSTranspiler.rs, PBKDF2.rs, node_crypto_binding.rs, node_fs.rs, socket_body.rs, and js_valkey_functions.rs; propagates Flavor through PBKDF2::from_js; updates doc-comment references in node_path.rs; removes the bare_bool_args:src/runtime/node/types.rs mordant baseline entry; and adds two behavior-pinning tests.

Security risks

None. This is a type-level refactor of internal function signatures; no user-facing surface, parsing logic, or trust boundary changes. The Flavor::Async branch that protect()s JS buffers for cross-thread use is reached under exactly the same conditions as before.

Level of scrutiny

Moderate. The parsers sit on the argument-handling path for node:fs, node:crypto, zstd, sockets, and the Redis client, and Flavor::Async gates whether JS-backed buffers are pinned/protected for the thread pool — a wrong mapping could cause a UAF or a leaked protect. I therefore traced every call site individually: each true/false literal maps to the variant that reproduces the old branch (if is_async → if flavor == Flavor::Async; if allow_file && .. → if file_blobs == FileBlobs::Reject && ..; if !allow_string_object && .. → if string_objects == StringObjects::Reject && ..). The valkey number path (FileBlobs::Reject, was true) and general path (FileBlobs::Allow, was false) preserve the one caller that permitted file blobs. Flavor retains its ConstParamTy derive so const-generic read_file<{Flavor}> callers still compile, and node_fs.rs re-exports it so node::fs::Flavor paths (used in Blob.rs, fetch.rs, SSLConfig.rs, etc.) resolve to the same type.

Other factors

Two things keep me from approving outright. First, the comment-cop bot left eight unaddressed inline comments — several are clearly noise (they flag pre-existing comments where this PR only swapped is_async=true for Flavor::Async), but the ones on the new enum doc comments are a style call the author or a maintainer should make. Second, #37180 covers the same functions repo-wide with different enum names (IsAsync/AllowFile via bool_enum!); a maintainer should decide which naming lands. The refactor itself is correct and well-tested (the description lists the full test matrix run, and the two new tests pin the previously-uncovered FileBlobs::Reject on from_js_async and StringObjects::Reject on both flavors).

@alii
alii enabled auto-merge (squash) August 15, 2026 20:50

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — mechanical bool→enum refactor with every call site mapping 1:1 to its old literal.

What was reviewed:

  • Traced every changed call site: is_async→Flavor, allow_string_object→StringObjects, allow_file→FileBlobs all preserve semantics; the allow_file polarity flip (true→Reject, false→Allow) matches the old if allow_file && needs_to_read_file() check.
  • Flavor move keeps ConstParamTy and is re-exported from node_fs, so const-generic uses (read_file::<{Flavor::Sync}>) and node::fs::Flavor paths keep working.
  • comment-cop flags are false positives (enum docs and pre-existing comments with a token rename), already addressed in the thread.
Extended reasoning...

Overview

Replaces four bool parameters on StringOrBuffer/BlobOrStringOrBuffer parsers in src/runtime/node/types.rs with two-variant enums (Flavor::{Sync,Async}, StringObjects::{Allow,Reject}, FileBlobs::{Allow,Reject}), updates the ~15 call sites across BunObject.rs, JSTranspiler.rs, PBKDF2.rs, node_crypto_binding.rs, node_fs.rs, socket_body.rs, and js_valkey_functions.rs, moves Flavor from node_fs.rs to types.rs (re-exported), removes the mordant baseline entry, and adds two behavior-pinning tests.

Security risks

None. This is a type-level refactor of internal argument-parsing helpers; no new inputs are accepted, no validation is loosened, and no crypto/auth/permission logic changes.

Level of scrutiny

Medium — the change touches shared argument parsers used by fs/crypto/zstd/transpiler/socket/redis, so a mismapped literal would flip async-vs-sync buffer protection or file-blob acceptance. I verified each site individually: every true/false maps to the variant whose enum comparison reproduces the old branch. The one non-trivial mapping is allow_file (whose old name was inverted); from_js/from_js_async (old true) → FileBlobs::Reject, valkey's false → FileBlobs::Allow, and the guard if allow_file && ... → if file_blobs == FileBlobs::Reject && ... — behavior-identical.

Other factors

  • Flavor retains #[derive(ConstParamTy)] so node_fs.rs's const-generic dispatch still compiles; the re-export keeps node_fs::Flavor/node::fs::Flavor paths intact.
  • Two new tests pin the previously-uncovered flag values (FileBlobs::Reject via Bun.build({files}), StringObjects::Reject via writeFile/appendFile sync+callback); both pass on main by design since this is behavior-preserving.
  • CI on the prior head was green except a known main-break (blob.test.ts under ASAN, tracked separately); mordant/clippy/format checks pass.
  • The comment-cop bot flagged 8 doc comments; robobun already responded — they're enum documentation and pre-existing comments with is_async=true→Flavor::Async token updates, not workaround justifications. Not blocking.
  • A larger overlapping sweep (#37180) exists but is a 539-file conflicting PR; landing order is a maintainer call, not a correctness concern for this diff.

@alii
alii disabled auto-merge August 15, 2026 22:07
@alii
alii merged commit dfb31d8 into main Aug 15, 2026
9 of 10 checks passed
@alii
alii deleted the farm/6e4bfbe0/node-types-flag-enums branch August 15, 2026 22:07

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — mechanical bool→enum refactor with every call site mapping verified.

What was reviewed:

  • Traced every is_async/allow_string_object/allow_file literal to its new enum variant across all 9 source files; each maps correctly, including the deliberate allow_file polarity flip (true → FileBlobs::Reject, matching what the old code actually did).
  • Flavor move preserves ConstParamTy and is re-exported from node_fs, so const-generic and node::fs::Flavor callers are unaffected.
  • Checked the PBKDF2 error-path guard (has_exception() && flavor == Async) and the sync-only from_typed_array rewrite still gate on the same conditions.
  • New tests pin existing behavior (String-wrapper rejection in fs.writeFile/appendFile; Bun.file() rejection in Bun.build({ files })) and use tempDir per harness conventions.
Extended reasoning...

Overview

This PR replaces four bool parameters on StringOrBuffer / BlobOrStringOrBuffer parsers in src/runtime/node/types.rs with two-variant enums (Flavor::{Sync,Async}, StringObjects::{Allow,Reject}, FileBlobs::{Allow,Reject}), updates every caller in BunObject.rs, JSTranspiler.rs, PBKDF2.rs, node_crypto_binding.rs, node_fs.rs, socket_body.rs, and js_valkey_functions.rs, and drops the corresponding bare_bool_args mordant baseline entry. Flavor is the existing node_fs.rs enum moved to types.rs and re-exported. Two behavior-pinning tests are added; a handful of doc comments referencing is_async=true are updated.

Security risks

None. The change is a type-level rename of function parameters. No validation logic, thread-safety gating, or protect/unprotect balancing changes shape — every if is_async becomes if flavor == Flavor::Async, every if !allow_string_object becomes if string_objects == StringObjects::Reject, and the allow_file guard becomes file_blobs == FileBlobs::Reject (semantically identical to the old allow_file == true, which was misnamed). No new inputs are accepted; no security checks are relaxed.

Level of scrutiny

Medium — the change touches shared argument-parsing helpers used by node:fs, node:crypto, zstd, Bun.Transpiler, sockets, and the Redis client, so a mis-mapped literal could flip async/sync buffer protection or silently start accepting/rejecting inputs. I traced every call site in the diff against its old bool literal:

  • types.rs internal forwarders: from_js (false,true → Sync,Allow), from_js_async (true,true → Reject,Async), from_js_maybe_file (false → Sync), from_js_with_encoding{,_into} (false,true → Sync,Allow), from_js_with_encoding_value_allow_string_object (is_async=false → Sync), from_js_with_encoding_value_allow_request_response (true → Allow).
  • BunObject.rs zstd, JSTranspiler.rs transform: true,true → Async,Allow.
  • PBKDF2::from_js: is_async param → flavor; guard has_exception() && is_async → && flavor == Async; if !is_async → == Sync; both from_js_maybe_async calls → (flavor, Allow). Callers pass Async/Sync for old true/false.
  • Scrypt: const-generic IS_ASYNC mapped once to flavor, forwarded with Allow (was true).
  • node_fs.rs WriteFile::from_js: will_be_async mapped to flavor, allow_string_object=false → Reject.
  • socket_body.rs: true → Allow.
  • js_valkey_functions.rs: number path true → Reject, general path false → Allow (matches the old inverted-name semantics).

All map correctly. The Flavor move keeps #[derive(ConstParamTy)], so node_fs.rs's const-generic <const F: Flavor> uses continue to compile, and the pub use super::types::Flavor re-export keeps node_fs::Flavor / node::fs::Flavor paths working.

Other factors

The two new tests are behavior-pinning (documented to pass on main), correctly use tempDir/toThrowWithCode, and assert the negative contract (readdirSync(dir) is empty). The comment-cop bot threads are all resolved and were doc comments on the new enums, not workaround justifications. CI red lanes are pre-existing main failures per the robobun status comment. The overlap with #37180 is flagged in the thread as a coordination note, not a blocker — this PR's approach (reusing Flavor, fixing the allow_file polarity name) is sound on its own.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants