Repository navigation
Conversation
clauderic
added this pull request to stack #1353
October 20, 2026 19:17
clauderic
force-pushed
the
theme-check-rust
branch
from
October 21, 2026 00:24
8996a59 to
db58731
Compare
clauderic
removed this pull request from stack #1353
October 21, 2026 00:28
clauderic
added this pull request to stack #1358
October 21, 2026 00:29
1 task done
clauderic
removed this pull request from stack #1358
October 21, 2026 00:47
clauderic
force-pushed
the
theme-check-rust
branch
from
October 21, 2026 00:47
db58731 to
c5af5d0
Compare
clauderic
added this pull request to stack #1360
October 21, 2026 00:48
clauderic
force-pushed
the
theme-check-rust
branch
from
October 21, 2026 01:10
c5af5d0 to
1f062bd
Compare
clauderic
force-pushed
the
theme-check-rust
branch
from
October 21, 2026 12:47
1f062bd to
db38987
Compare
2 tasks done
clauderic
force-pushed
the
theme-check-rust
branch
from
October 21, 2026 12:59
db38987 to
d615e19
Compare
clauderic
force-pushed
the
theme-check-rust
branch
from
October 21, 2026 14:49
d615e19 to
1dc19bf
Compare
karreiro
self-requested a review
October 21, 2026 15:10
Theme Check in Rust, in three crates under crates/: - liquid-ast: the syntax tree of @shopify/liquid-html-parser. - liquid-parser: the parser. - theme-check: the checks, the runner, config loading, the docs cache, the theme graph and a CLI like theme-check-node's. It reports the same offenses as the TypeScript, with the same messages, positions and fixes. `cargo test` runs the specs in specs/checks and specs/graph, and it passes all of them, and runs the CLI on small themes. A new Rust job in CI runs it and checks the formatting. The crate has copies of theme-check-node's configs and of the checks' metadata. The code quality job checks that they match the TypeScript. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Changesets only versions packages that have a package.json, so the crates get one: crates/theme-check/package.json, a private package named theme-check-rs. Its name keeps it out of the @shopify/theme-check-* group, so the crates have their own version, from 0.1.0. A changeset for theme-check-rs bumps it, and the release orchestrator then copies it into Cargo.toml and Cargo.lock. The three crates share it, and CI checks that they have it. CI also dry-runs the publish, which builds each crate from the files it would upload. The release workflow publishes each crate whose version isn't on crates.io yet, with trusted publishing, so a run that fails partway is finished by the next. It does this in a job of its own, in the crates-io environment, so no npm package runs where it can get a crates.io token. Until theme-check is on crates.io, it skips them: the first publish is by hand, and so is adding the trusted publisher. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
clauderic
force-pushed
the
theme-check-rust
branch
from
October 22, 2026 00:51
1dc19bf to
82b5472
Compare
This branch has not been deployed
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.
Stacked on #1359, the parser specs. Under it are #1347, the executable specs, and #1357, a parser fix. Review those first; this PR's base moves down the stack as they merge.
What are you adding in this PR?
Theme Check in Rust: a port of
@shopify/theme-check-nodeand the packages it uses, in three crates undercrates/.liquid-ast: the syntax tree, as@shopify/liquid-html-parserbuilds it.liquid-parser: the parser.theme-check: the checks, the runner, config loading, the theme graph, the docs cache and a CLI.It reports the same offenses as TypeScript, with the same messages, positions, fixes and suggestions:
cargo testruns the specs from Add executable check specs #1347: every case inspecs/checks(all 1,680, and each check's severity) andspecs/graph(all 13).cli.ts, byte for byte, onpackages/theme-graph/fixtures/skeleton.The parser builds the same trees as TypeScript, and throws the same errors:
cargo testruns the parser specs from #1359, and all 415 cases inspecs/parserpass. It includes the fix from #1357: an unclosed block in{% liquid %}ends where its last line does. Past 1,000 levels of nesting, a template is a syntax error,Maximum call stack size exceeded, as it is in TypeScript once Node runs out of stack. Node's limit isn't a fixed number, so a template nested between about 900 and 1,000 levels parses in Rust only. The specs give trees in the TypeScript shape, socrates/liquid-parser/tests/specs.rsprints them that way; the crate itself has no JSON.A full run with every dependency is about 11 to 13 times faster than theme-check-node: 125 ms against 1,608 ms on Dawn. It uses about 75 MB of memory, against 400 to 750 MB.
crates/theme-check/README.mdhas the rules the port follows: UTF-8 byte offsets in the AST, UTF-16 positions in offenses, and JS semantics where offenses depend on them.There are two commits:
rustjob runscargo fmt --checkandcargo test --locked.crates/theme-check/tests/cli.rsruns the binary on small themes: config files,extends,ignoreandroot, app mode, bad configs and exit codes,--autofixand deep nesting. Every expected value is theme-check-node's on the same files.Versioning and publishing
Changesets versions the crates, like everything else here.
crates/theme-check/package.jsonis a private package,theme-check-rs, outside the fixed theme-check group. To release the crates, add a changeset for it.pnpm releasegets a step,syncCrateVersion, that copies its version intoCargo.tomlandCargo.lock. All three crates have the same version.package.jsonworkspaces andpnpm-workspace.yaml, since changesets reads the former.release.ymlpublishes the crates to crates.io after the npm packages. It's a job of its own,publish-crates, in thecrates-ioenvironment, so no npm package runs where it can get a crates.io token.rust-lang/crates-io-auth-action), so there's no token secret.theme-checkis on crates.io, it publishes nothing.There's no changeset: 0.1.0 is published by hand once this merges.
After merge
publish-newscope, limited totheme-check,liquid-astandliquid-parser, with a short expiry.main, publish 0.1.0:cargo publish --workspace --locked. This needs cargo 1.90 or newer.cargo owner --add github:Shopify-Partners:crates-publish <crate>, and one more person.Shopify, repositorytheme-tools, workflowrelease.yml, environmentcrates-io.crates-ioenvironment tomain. GitHub creates it, with no rules, the first time the job runs.From then on, a changeset for
theme-check-rsreleases the crates.What's next? Any followup issues?
cargo install theme-checkdoesn't get the fallback docs. They're read from adatafolder next to the executable, so they need to be embedded in the binary.curl.Providershas one flag, and every caller sets it totrue, so it can go.What did you learn?
Changesets reads the root
package.jsonworkspaces beforepnpm-workspace.yaml. A package that's only inpnpm-workspace.yamlis invisible to it.Tophatting
cargo testruns the unit tests, the CLI tests and the specs.theme-check-rsand runpnpm release.Cargo.tomlandCargo.lockget the new version.Before you deploy
🤖 Generated with Claude Code