SBT Parser Improvements
March 27, 2026 ยท View on GitHub
Summary
Rust now ships a bounded, static parser for build.sbt files even though the Python ScanCode reference has no production SBT parser today.
The supported surface is intentionally narrow: it extracts only top-level literal metadata, literal license/homepage forms, and literal external library dependencies, and it skips anything that would require Scala or sbt evaluation.
Python Status
- Python ScanCode does not currently ship a production SBT parser.
- Upstream demand exists, but there is no reference implementation to port directly.
- This gives Rust direct packagedcode support for SBT build metadata that the Python reference does not currently provide.
Rust Improvements
Safe build.sbt metadata extraction
- Rust now recognizes files literally named
build.sbtand extracts top-level literal package metadata fororganization,name,version, anddescription. - The same bounded slice also supports
ThisBuild / organization|name|version|descriptionand lets direct root settings override broaderThisBuilddefaults. homepage := Some(url("..."))andorganizationHomepage := Some(url("..."))are recovered when they are directly literal.licenses += "Name" -> url("https://...")is recovered when it is directly literal.
Literal dependency extraction without Scala evaluation
- Rust now extracts literal external dependencies from
libraryDependencies += ...andlibraryDependencies ++= Seq(...). - Supported dependency forms include both
%and%%operators plus literal scope suffixes such as% Test,% "test", and% "provided". - Rust now also supports top-level config-prefixed dependency statements such as
Test / libraryDependencies += ...,Runtime / libraryDependencies += ..., andProvided / libraryDependencies ++= Seq(...). - When a config prefix exists and the dependency itself does not already declare an explicit trailing
% scope, Rust maps the prefix into the same dependency scope/runtime semantics it already uses for trailing SBT scopes. - Dependencies are emitted as Maven package URLs because SBT resolves external artifacts from the JVM/Maven ecosystem.
- For
%%, Rust preserves the literal artifact name written inbuild.sbtand records that the dependency used SBT cross-version syntax instead of guessing a Scala binary suffix that would require evaluation.
Small bounded alias support
- Rust resolves simple same-file string
valaliases when they are used in supported top-level string settings or supported dependency coordinates/versions. - Alias handling stays intentionally narrow and does not widen into general Scala constant folding or expression evaluation.
Root-safe .settings(...) and shared bundle support
- Rust now descends into top-level root-safe
.settings(...)wrappers such aslazy val root = project.settings(...)andlazy val root = (project in file(".")).settings(...). - The parser also supports same-file literal
Seq(...)bundles reused as shared dependency or settings groups when they are referenced from supported positions. - Inline settings inside a root-safe
.settings(...)wrapper override earlier bundle-provided values using the same bounded precedence rules as the rest of the parser.
Explicit guardrails
- Unsupported constructs are skipped instead of guessed.
- Rust does not execute Scala, invoke
sbt, parse arbitrary*.sbt, parseplugins.sbt, parseproject/*.scala, or attempt multi-project graph semantics. - Rust only descends into top-level root-safe
.settings(...)wrappers; broader nested or non-root project setting graphs are still skipped.
Coverage
Coverage spans literal metadata extraction, libraryDependencies handling, limited string-alias reuse, and the non-evaluating parser guardrails.