Repository navigation
Fix .yarnrc read by two drifted tokenizers (#1901) - #1915
Mikola Lysenko (mikolalysenko) wants to merge 6 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
The npm crawler and the hosted redirect each tokenized yarn classic's .yarnrc, and the copies drifted. Given --modules-folder 'deps', the crawler kept the quotes and crawled a folder named 'deps', missing the real install, so its packages were reported as not installed. It also accepted values yarn can't read (~/x, an unquoted C:\deps). Both now call formats::yarn::classic_rc, built from the redirect's yarn-faithful reader. A value followed by anything but a # comment is unreadable to yarn, so it now sets nothing for either caller. Fixes #1901 Assisted-by: Claude Code:claude-opus-5-5
yarn 1.22 reads a single-quoted .yarnrc value only through its YAML fallback, so only in a `key: 'value'` pair. A bare `--modules-folder 'deps'` line is ignored and the install goes to node_modules (checked against yarn 1.22.22). The shared reader now accepts a single-quoted value only after a `:` and whitespace, so neither the crawler nor the redirect roots a crawl at a folder yarn never installs into. Refs #1901 Assisted-by: Claude Code:claude-opus-5-5
yarn 1 parses .yarnrc with its lockfile grammar, and if that fails anywhere in the file, re-reads the whole file as YAML. A line-by-line reader could not model this. `--modules-folder: my deps` installs into `my deps`, while one unreadable line elsewhere (`yarn-path ~/y.js`) makes yarn ignore every setting in the file. formats::yarn::classic_rc now runs yarn's tokenizer and parser over the file and falls back to a YAML read. The crawler's --modules-folder, the redirect's global-folder and the yarn-offline-mirror read all go through it. Every case in the tests was checked against yarn 1.22.22. Refs #1901 Assisted-by: Claude Code:claude-opus-5-5
The public yarnrc docs linked to a crate-private module, which rustdoc reports as a private link. Name it in code instead. Assisted-by: Claude Code:claude-opus-5-5
Review against yarn 1.22's parse.js and js-yaml's FAILSAFE schema found these gaps in the shared reader: - An empty YAML value is null (unset), not the string "~". - A duplicate key or an unknown tag makes yarn reject the file. - An alias reads its anchored value. - Only \n or \r\n starts an indent, and a comment runs to \n. - An empty key after a comma is an error. The offline-mirror read now treats only boolean false as "no mirror": yarn resolves a string "false" as a mirror path. Callers that read several keys parse each file once. Refs #1901 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 11551ef. Configure here.
|
Labeled Ready for review by the burn-down agent.
Slack announcement could not be sent in this run (no Slack send tool available); the next run will retry. Generated by Claude Code |
Final review brief (
|
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1901
Summary
Yarn classic's
.yarnrcwas read by two tokenizers that had drifted:the npm crawler's
parse_yarnrc_modules_folder/split_yarnrc_token,and the hosted redirect's
yarnrc_setting/yarnrc_token. Theoffline-mirror read was a third variant, using
unquote_rc_value. Allof them now go through one reader,
formats::yarn::classic_rc, whichreads the file the way yarn 1.22 does.
Root cause
Each module tokenized
.yarnrcline by line in its own way. yarn 1actually parses the whole file with its lockfile grammar
(
lockfile/parse.js). If that fails anywhere in the file, yarnre-reads the whole file as YAML (js-yaml
safeLoad, FAILSAFE schema).If YAML fails too, yarn exits with an error. No per-line reader can
model that. For example, one unreadable
yarn-path ~/y.jsline makesyarn ignore
--modules-folder depson the line above.What yarn 1.22.22 actually does
I ran
yarn installwith each.yarnrcbelow and recorded whereis-numberlanded:.yarnrc--modules-folder deps/"deps"/deps # c/--modules-folder:depsdeps--modules-folder: 'deps',"--modules-folder": 'deps',--modules-folder : 'deps'(YAML fallback)deps--modules-folder: my deps(YAML fallback)my deps--modules-folder, --install.modules-folder depsdeps--modules-folder 'deps',--modules-folder:'deps',~/x,C:\deps,C:deps,deps, x,trueDeps, a tab separatornode_modules(not read)--modules-folder deps+yarn-path ~/y.js; odd indentationnode_modules(the file falls to YAML and reads as a plain string)"--modules-folder" 'deps',false,0, a nested blockCorrection to the issue: the issue says the redirect's reader gets
--modules-folder 'deps'right (deps). It doesn't: yarn ignores thatline. Both old readers were wrong for it.
Changes
crates/socket-patch-core/src/formats/yarn/classic_rc.rs(new):lockfile/parse.js:booleans, numbers,
a, bmulti-keys, indent rules, nested blocks,and a lone
\r.serde_saphyrparser already in usefor
.yarnrc.yml. It matches js-yaml FAILSAFE: an empty value isnull, a duplicate key or an unknown tag makes the file unreadable,
and an alias reads its anchored value.
settings/scalar/take_str.npm_crawler::parse_yarnrc_modules_folderis onesettingscall.split_yarnrc_tokenand the crawler's line loop are deleted.patch/redirect/yarnrc.rs:yarnrc_settingandyarnrc_tokenaredeleted.
global-folderandyarn-offline-mirrorread throughclassic_rc. The mirror is disabled only by a booleanfalse,because yarn's
getOfflineMirrorPathchecks=== falseand resolvesa string
"false"as a path.Tests (red → green)
npm_crawler::tests::yarnrc_modules_folder_reads_like_yarn(new) andnpm_crawler::tests::test_yarnrc_single_quoted_modules_folder_is_a_crawl_root(new). The second crawls a real tree:
deps/for--modules-folder: 'deps', and onlynode_modules/for--modules-folder 'deps'.npm_crawler::tests::test_parse_yarnrc_modules_folder: unquotedC:\depsis now unset, matching yarn.formats::yarn::classic_rc::tests(new) pin every table row, plusthe js-yaml and lone-
\rcases.main's reader:cargo test -p socket-patch-core --lib -- yarnrchad 3 failures. Green:cargo test -p socket-patch-core --lib -- classic_rc yarnrc yarn mirrorgives 466 passed. Also green:crawler_npm_e2e(123 passed), plus the yarn and modules-folder casesin
e2e_vex_redirect,e2e_vex_vendorandin_process_alternate_installers(real yarn 1.22.22).cargo fmt --all -- --checkandcargo clippy --workspace --all-features -- -D warningsare clean.cargo test --workspace --all-features --no-fail-fastlocally: everyfailure is environmental and none involves yarn. The container runs as
root, so the permission-based write-failure tests in core lib,
in_process_redirectandrepairdon't fail as intended. The patchAPI is unreachable through the sandbox proxy, and the local bun
version differs from CI's (
e2e_bun_lockb). CI runs these normally..yarnrc, so none needed changes.Per-issue checklist:
formats/yarn/, used by the crawler and byredirect. A single-quoted test, and an untokenizable-value test
ignored by both callers.
/code-review high
I ran it twice. The second pass was on the whole-file reader. I fixed
every confirmed finding: the YAML null value, duplicate keys, tags,
aliases,
\rhandling, an empty comma key, string"false", doubleparsing, and stale docs. One finding is not fixed here:
.yarnrcis unreadable, or sets anempty, boolean or numeric
--modules-folder, the crawler falls backto an ancestor's value. yarn would error or behave differently. That
is
yarnrc_modules_folder's hierarchy merge, not the tokenizer.Changing it would affect a different code path, which Fix crawlers missing parent dirs under --cwd . (#1902) #1906 also
touches. Left as a follow-up.
https://claude.ai/code/session_011f9aeSZeF6iZU51H3F7GgF
Generated by Claude Code