NuGet Parser Improvements
May 28, 2026 ยท View on GitHub
Summary
Rust now intentionally differs from or improves on released Python ScanCode NuGet support in six concrete ways:
- parses additional NuGet and Visual Studio manifests (legacy
project.json,project.lock.json, and PackageReference project files) - parses
.deps.jsonruntime dependency graphs from built .NET outputs - preserves modern nuspec license hints (
license_type,license_file) instead of collapsing everything to deprecatedlicenseUrlfallbacks - reads archive-backed license file contents from
.nupkgfiles when the nuspec points at a packaged license file - parses NuGet Central Package Management files (
Directory.Packages.props) and statically backfills nearest-ancestor central versions into versionless project dependencies, including composed property-backedPackageVersionexpressions, bounded repository-local.propsimports, and bounded literalVersionOverridesupport when explicitly enabled - adds bounded
Directory.Build.propsparticipation so CPM-relevant properties can flow into central versions and project overrides without full MSBuild evaluation
Python Status
- Released ScanCode handles
.nuspec,.nupkg, andpackages.lock.json, but not legacyproject.json,project.lock.json, PackageReference project files, standaloneDirectory.Packages.props, or.deps.jsonruntime graphs. - Upstream enhancement issues explicitly ask for these extra manifests and modern nuspec/license improvements.
- Python also keeps NuGet party
typeempty and does not extract packaged license file contents from.nupkgarchives.
Rust Improvements
Extra manifest support
- Legacy
project.jsonmanifests now extract package metadata plus direct and framework-specific dependencies. project.lock.jsonnow extracts dependency groups fromprojectFileDependencyGroups.- PackageReference
.csproj,.vbproj, and.fsprojfiles now extract package metadata and<PackageReference>dependencies. Directory.Packages.propsnow extracts centralPackageVersiondeclarations as dependency metadata, includingCondition, central-package-management feature flags, and composed property-backed version expressions such as$(VersionPrefix)-$(VersionSuffix)when the bounded property chain is statically known.Directory.Build.propsnow extracts bounded literal property maps and bounded parent-import metadata relevant to CPM.- Assembly now backfills versionless PackageReference dependencies from the nearest ancestor
Directory.Packages.props, can merge bounded explicit parentDirectory.Packages.propsimports, can consume boundedDirectory.Build.propsproperty maps, can ingest bounded repository-local.propsimports addressed directly or through$(MSBuildThisFileDirectory)-anchored paths, and can prefer literal project-fileVersionOverridevalues when CPM overrides are statically enabled. .deps.jsonnow extracts runtime-target-aware resolved dependency graphs from built .NET outputs.
Static CPM backfill with bounded parent imports and build-props participation
Rust now uses Directory.Packages.props in two truthful ways: it still parses the file as standalone NuGet metadata, and it now applies its central versions to versionless PackageReference dependencies during assembly when a narrow static match is available.
This CPM slice intentionally:
- extracts
<PackageVersion Include="..." Version="..." />and<PackageVersion Update="..." Version="..." /> - preserves
Conditionmetadata on central package-version entries - preserves central flags such as
ManagePackageVersionsCentrally,CentralPackageTransitivePinningEnabled, andCentralPackageVersionOverrideEnabled - backfills versionless
PackageReferenceentries from the nearest ancestorDirectory.Packages.propswhen central package management is enabled and there is exactly one matching central entry - preserves literal
VersionOverridemetadata onPackageReferenceentries in project files - supports the documented explicit parent-import pattern for
Directory.Packages.props, including bounded static handling ofGetPathOfFileAbove(Directory.Packages.props, $(MSBuildThisFileDirectory)..) - supports bounded repository-local
.propsimports reachable fromDirectory.Packages.props/Directory.Build.props, including$(MSBuildThisFileDirectory)-anchored paths, when the resolved file stays under the same scan root - supports bounded nearest-ancestor and bounded parent-import participation for
Directory.Build.props - resolves literal and composed property-backed
PackageVersionexpressions such as$(SomeVersion)and$(VersionPrefix)-$(VersionSuffix)when the bounded import chain statically proves the needed properties - resolves literal project-file
VersionOverride="$(SomeProperty)"values when that property is statically known in the project file - prefers a literal
PackageReference VersionOverrideover the nearest central package version only when CPM overrides are statically enabled and exactly one matching central package entry exists - prefers explicit project-file versions over central backfill
- treats conditioned central versions as applicable only when the project dependency carries the exact same raw condition string
- does not evaluate full MSBuild semantics
- does not participate in
Directory.Build.targetsor broader non-CPM import graphs - does not evaluate wildcard or non-literal import targets
- does not implement broader MSBuild condition/property resolution
That keeps the implementation truthful: it improves real CPM dependency recovery without pretending that full MSBuild-driven central-version resolution already works.
Modern nuspec metadata
- NuGet author/owner parties now record
type = person. - Nuspec
<license type="expression">...and<license type="file">...now preserve their modern type hints inextra_data. - File-based nuspec licenses keep the real file reference instead of falling back to deprecated
licenseUrlplaceholders. - Repository
branchandcommitattributes are preserved inextra_datawhen present.
Archive-backed license extraction
- When a
.nupkgnuspec declares<license type="file">LICENSE.txt</license>, Rust now reads that packaged file and stores its contents as the extracted license statement. - This gives downstream license analysis a real license text source instead of only the placeholder filename.
Coverage
Coverage spans modern and legacy NuGet manifests, CPM backfill and import bounds, build-props participation, version overrides, archive-backed license extraction, and assembly behavior for the supported inputs.