Skip to content

fix(bundle): read TOML with @preventive/lockfile's parser - #183

Merged
ChALkeR merged 1 commit into
mainfrom
claude/preventive-lockfile-toml-02j8b2
Sep 29, 2026
Merged

ChALkeR merged 1 commit into
mainfrom
claude/preventive-lockfile-toml-02j8b2

Conversation

@exo-nikita

Copy link
Copy Markdown
Collaborator

Adds @preventive/lockfile 1.0.0-alpha.1, the latest. main had no dependency on it; #172 pins 1.0.0-alpha.0. Cargo.toml, Cargo.lock and foundry.toml are now read with its strict TOML 1.0 parser, parseToml, instead of the reader loaders/toml.js has carried since #179.

What changes

  • stasis/package.json, pnpm-lock.yaml: @preventive/lockfile pinned exactly, like @preventive/upstream. It has no dependencies of its own.
  • loaders/toml.js: 502 → 66 lines. It keeps:
    • readToml(text, file): parseToml, with a TomlError's message prefixed by the file (crates/app/Cargo.toml: unterminated string at line 3). The error keeps its class and line, and the build still stops;
    • isTomlTable, which tells a table from a TomlFloat or TomlDateTime;
    • the bracket helpers the Rust scanner shares (matchClose, splitTopLevel). They were never part of the TOML reader.
  • parseCargoManifest, parseCargoLock, parseFoundryToml: these walk the parsed table tree instead of an entry stream, so the dotted, inline and header spellings of a table are one table by construction. DEP_KINDS has a null prototype, since its keys now come straight from the document.

Behavior

The parser refuses everything the old reader refused, plus what these files are never written in:

  • local dates and times;
  • a byte order mark;
  • U+FFFD where a lenient decoder replaced bytes that aren't UTF-8;
  • a dotted key through a table a header made (Cargo's toml crate refuses it too).

Error messages follow the package: <file>: <detail> at line N.

One deliberate change in foundry.toml: a profile's sub-tables are its values however they are written. So a no-collision extends now sees a [profile.default.fuzz] table, as forge does. The old reader skipped header-spelled sub-tables, all except extends.

main's handling of a dependency's foundry.toml it can't read (skipped with a warning) is unchanged here. #175 changes that separately.

Verification

  • Differential against main's reader: all 123 Cargo.toml / Cargo.lock / foundry.toml files of a 45-crate crates.io corpus and the test fixtures parse to identical results.
  • toml-test suite: the new parser accepts nothing the old one refused. It refuses:
    • 18 valid-suite files, all within its documented exclusions: local dates and times, date-times with a space, a dotted key through an implicit table;
    • 6 invalid files the old one accepted: bad UTF-8, read as U+FFFD.
  • Tests:
    • tests/toml.test.js now tests what the loaders rely on: the file-named error, the refusals above, and the tree's shapes (null-prototype tables, BigInt, TomlFloat, __proto__ as a key). The parser's own tests live with the package.
    • The Cargo and foundry error-message expectations follow the new messages.
    • A new foundry test covers extends written as a table, and a no-collision over a fuzz sub-table.
    • The CLI test that runs a copy of stasis without oxc-parser also vendors @preventive/lockfile, like the zero-dependency @exodus/stasis-core. The loaders import it when the bundle command loads.
  • Full suite: 2032 pass, 0 fail, 3 skipped; oxlint clean.

#175 uses tomlEntries and will be rebased onto this once it lands.

🤖 Generated with Claude Code

https://claude.ai/code/session_015nbp2vC4jLPbGN8cmorxAL


Generated by Claude Code

Adds @preventive/lockfile 1.0.0-alpha.1 and reads Cargo.toml, Cargo.lock and
foundry.toml with its strict TOML parser (parseToml) in place of the reader
loaders/toml.js carried since #179. The readers walk the parsed table tree:
the dotted, inline and header spellings of a table are one table by
construction. loaders/toml.js keeps readToml (the parser, with the file named
in its errors), isTomlTable and the bracket helpers the Rust scanner shares.

The parser refuses what those files are never written in, on top of what
isn't TOML: local dates and times, a byte order mark, U+FFFD where a lenient
decoder replaced bytes, a dotted key through a table a header made (Cargo's
toml crate refuses it too). A foundry.toml profile's sub-tables are its values
whichever way they are written, so a `no-collision` extends sees a
`[profile.default.fuzz]` table as forge does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015nbp2vC4jLPbGN8cmorxAL
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.

3 participants