feat(api)!: fold the decode options into one struct - #838
Merged
Conversation
andiwand
force-pushed
the
feat/mirror-text-encoding
branch
from
September 6, 2026 13:55
a480dda to
d744f6b
Compare
DecodePreference answered "which type" and CsvOptions answered "how to read it", on different roads: CsvFile::from_file bypassed open_strategy entirely, so a caller who wanted to name a separator could not get there through open. DecodeOptions carries both, and with a default argument the six open overloads become two. Two things fell out of routing csv through the strategy. A named type is not a probe with one candidate, so its engine's own refusal now reaches the caller instead of UnknownFileType - which is what kept from_file's diagnostics when it went - and an incoherent dialect stays std::invalid_argument rather than becoming "not a csv", because it is a caller mistake, not a claim about the bytes. DecodeOptions::as and ::as_csv are named factories rather than designated initializers: partial designated initialisation warns under -Wextra on the emscripten toolchain, and CI builds with -Werror. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016hxDa2rev11eLUEJZJ5nmz
andiwand
force-pushed
the
feat/decode-options
branch
from
September 6, 2026 14:04
037532d to
d4e5968
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Generated with Claude Code
PR 8 of the v7 API plan.
Stacked on #837.
The asymmetry this fixes
DecodePreferenceanswered which type;CsvOptionsanswered how to readit. They sat on different roads —
CsvFile::from_file(file.cpp:331)constructed
internal::csv::CsvFiledirectly and never touchedopen_strategy— so a caller who wanted to name a separator could not getthere through
open. That was the real finding behind the overload count inthe plan.
Two declarations where there were six;
CsvFile::from_fileand::with_optionsgo.Two things fell out of it, both worth reading
1. A named type now reports the engine's own refusal. Routing csv through
the strategy first made it worse:
open_by_probecatches everything and endsin
UnknownFileType, sofrom_file's preciseNoCsvFilewould have been lost —removing it would have been lossy. The fix is in the strategy, not the tests:
open(f, DecodeOptions::as(FileType::rich_text_format))on non-rtf bytes nowthrows
NoRtfFile; asking forhtmlthrowsUnsupportedFileTypenaming it,instead of a flat
UnknownFileType. Five tests pinned the old collapsing andare updated, including one whose comment documented it as deliberate —
that rationale ("the caller sees the strategy's own answer") applied when a
named type was still routed through the probe, and no longer holds. Detection
without a named type is untouched and still ends in
UnknownFileType.2. An incoherent dialect stays
std::invalid_argument.separator == quoteis a caller mistake, not a claim about the bytes; saying "not a csv" would send
them to look at the file. The csv branch rethrows it rather than folding it in.
Why named factories and not designated initializers
I wrote the call sites as
{.as_file_type = X}first. The emscriptentoolchain rejects that:
-Wmissing-designated-field-initializersfires on apartial designated initializer,
CMakeLists.txt:38sets-Wall -Wextra, andbuild_test.yml:119adds-Werror. AppleClang here does not have the warning,so the local build was silent — this only surfaced in the syntax check against
the real wasm compiler.
DecodeOptions::as(type)and::as_csv(options)avoid the constructaltogether and read better at the call site.
Bindings
CsvOptionsis mirrored for the first time, alongside the renamedDecodeOptions:DecodeOptions(wasDecodePreference) +CsvOptions;Odr.open(path, options)DecodeOptions/CsvOptionswith keyword constructors; plusCsvFile,as_csv_file(),is_csv_file(), which were never boundODRDecodeOptions(wasODRDecodePreference) +ODRCsvOptions;decode(path:options:)openAsgoes through the struct internallyVerified
Full gtest suite 1456 passed / 6 skipped, 72 python tests, JNI junit.
Apple (11 TUs) and wasm (6 TUs) syntax-checked with
-Wall -Wextra -Werror.Migration