A Go library for parsing package manager manifest and lockfiles. Extracts dependencies with version constraints, scopes, and integrity hashes.
go get github.com/git-pkgs/manifestspackage main
import (
"fmt"
"os"
"github.com/git-pkgs/manifests"
)
func main() {
content, _ := os.ReadFile("package.json")
result, err := manifests.Parse("package.json", content)
if err != nil {
panic(err)
}
fmt.Printf("Ecosystem: %s\n", result.Ecosystem)
fmt.Printf("Kind: %s\n", result.Kind)
fmt.Printf("Package: %s %s\n", result.Name, result.Version)
for _, dep := range result.Dependencies {
fmt.Printf(" %s@%s (%s)\n", dep.Name, dep.Version, dep.Scope)
}
}| Ecosystem | Manifests | Lockfiles |
|---|---|---|
| alpine | APKBUILD | |
| arch | PKGBUILD | |
| asdf | .tool-versions | |
| bazel | MODULE.json | |
| bower | bower.json | |
| brew | Brewfile | Brewfile.lock.json |
| cargo | Cargo.toml | Cargo.lock |
| carthage | Cartfile, Cartfile.private | Cartfile.resolved |
| clojars | project.clj | |
| cocoapods | Podfile, *.podspec | Podfile.lock |
| composer | composer.json | composer.lock |
| conan | conanfile.txt, conanfile.py | conan.lock |
| conda | environment.yml, environment.yaml | |
| cpan | cpanfile, Makefile.PL, Build.PL, dist.ini, META.json, META.yml | cpanfile.snapshot |
| cran | DESCRIPTION | renv.lock |
| crystal | shard.yml | shard.lock |
| deno | deno.json, deno.jsonc | deno.lock |
| docker | Dockerfile, docker-compose.yml | |
| dub | dub.json, dub.sdl | |
| elm | elm.json, elm-package.json | |
| gem | Gemfile, gems.rb, *.gemspec | Gemfile.lock, gems.locked |
| git | .gitmodules | |
| github-actions | .github/workflows/*.yml | .github/workflows/actions.lock |
| golang | go.mod, Godeps, glide.yaml, Gopkg.toml | Godeps.json, glide.lock, Gopkg.lock, vendor.json, go-resolved-dependencies.json, vendor/manifest |
| guix | manifest.scm | |
| hackage | *.cabal | stack.yaml.lock, cabal.config, cabal.project.freeze |
| haxelib | haxelib.json | |
| hex | mix.exs, gleam.toml | mix.lock, rebar.lock |
| julia | Project.toml, REQUIRE | Manifest.toml |
| lean | lakefile.toml, lakefile.lean | lake-manifest.json |
| luarocks | *.rockspec | |
| maven | pom.xml, ivy.xml, build.gradle, build.gradle.kts, build.sbt | gradle.lockfile, gradle-dependencies-q.txt, maven-resolved-dependencies.txt, verification-metadata.xml |
| nimble | *.nimble | |
| nix | flake.nix | flake.lock, sources.json |
| pre-commit | .pre-commit-config.yaml, prek.toml | |
| npm | package.json, bower.json | package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml, bun.lock, npm-ls.json |
| nuget | *.csproj, *.vbproj, *.fsproj, *.nuspec, packages.config, Project.json | packages.lock.json, paket.lock, project.assets.json, *.deps.json, Project.lock.json |
| opam | opam, *.opam | |
| pub | pubspec.yaml | pubspec.lock |
| pypi | requirements.txt, Pipfile, pyproject.toml, setup.py, setup.cfg | Pipfile.lock, poetry.lock, pdm.lock, uv.lock, pip-dependency-graph.json, pip-resolved-dependencies.txt, pylock.toml |
| rpm | *.spec | |
| swift | Package.swift | Package.resolved |
| vcpkg | vcpkg.json |
| Lockfile | Registry URL | Integrity | Scope | Direct |
|---|---|---|---|---|
| package-lock.json | ✓ | ✓ | ✓ | ✓ |
| npm-shrinkwrap.json | ✓ | ✓ | ✓ | ✓ |
| yarn.lock | ✓ | ✓ | ||
| pnpm-lock.yaml | ✓ | ✓ | ✓ | |
| bun.lock | ✓ | ✓ | ||
| npm-ls.json | ✓ | ✓ | ✓ | |
| deno.lock | ✓ | |||
| Gemfile.lock | ✓ | ✓ | ✓ | |
| Cargo.lock | ✓ | ✓ | ||
| poetry.lock | ✓ | ✓ | ✓ | |
| Pipfile.lock | ✓ | ✓ | ✓ | |
| pdm.lock | ✓ | ✓ | ||
| uv.lock | ✓ | ✓ | ||
| pylock.toml | ✓ | |||
| pip-resolved-dependencies.txt | ||||
| pip-dependency-graph.json | ||||
| composer.lock | ✓ | ✓ | ✓ | |
| Podfile.lock | ✓ | ✓ | ||
| mix.lock | ✓ | |||
| rebar.lock | ✓ | |||
| pubspec.lock | ✓ | ✓ | ✓ | |
| conan.lock | ✓ | |||
| packages.lock.json | ✓ | ✓ | ||
| paket.lock | ||||
| project.assets.json | ✓ | |||
| *.deps.json | ✓ | |||
| Project.lock.json | ✓ | |||
| stack.yaml.lock | ✓ | |||
| cabal.config | ||||
| cabal.project.freeze | ||||
| renv.lock | ✓ | |||
| shard.lock | ||||
| flake.lock | ✓ | |||
| sources.json | ✓ | |||
| Brewfile.lock.json | ✓ | ✓ | ||
| lake-manifest.json | ✓ | ✓ |
Supplement files: go.sum is parsed as a supplement rather than a lockfile. It provides integrity hashes that can be matched against go.mod dependencies by name and version, but it doesn't represent a standalone dependency tree.
Parses a manifest or lockfile and returns extracted dependencies.
func Parse(filename string, content []byte) (*ParseResult, error)Returns the ecosystem and kind for a filename without parsing.
func Identify(filename string) (ecosystem string, kind Kind, ok bool)Returns all matching ecosystems for a filename (some files match multiple parsers).
func IdentifyAll(filename string) []MatchReturns a list of supported ecosystems.
func Ecosystems() []stringDiscovers root manifests, GitHub Actions workflows, and declared Cargo, Go,
npm/Yarn, and pnpm workspace members. Discovery is repository-aware while
Parse remains a pure single-file operation.
reader := manifests.NewFSReader(os.DirFS("."))
found, warnings := manifests.DiscoverManifests(reader)Callers reading historical revisions can implement RepositoryReader over a
Git tree. Paths and glob patterns are rooted, slash-separated repository paths.
Workspace records set ParentPath to the configuration that selected them.
Warnings report malformed workspace configuration or failed lookups without
discarding manifests that were discovered successfully.
Discovers package-manager vendor roots and exact package identities stored in
the repository. The initial implementation recognizes npm node_modules
trees exposed by the supplied reader, Go vendor/modules.txt, Python
[tool.vendoring] configuration, and Cargo directory sources selected through
.cargo/config.toml or .cargo/config.
reader := manifests.NewFSReader(os.DirFS("."))
found, warnings := manifests.DiscoverVendors(reader)VendorDiscovery.Roots classifies each vendor directory by ecosystem and
records the configuration or inventory that selected it. Each
VendoredDependency has Kind == Vendor, an exact package identity and PURL,
its vendor root, and the evidence file from which the identity was read.
Results are normalized and deterministic. Invalid configuration, unreadable
evidence, and incomplete package identities are returned as warnings without
discarding successful discoveries.
type Dependency struct {
Name string // Package name
Version string // Version constraint or resolved version
Scope Scope // runtime, development, test, build, optional
Integrity string // Opaque verification value, when available
Direct bool // True if declared directly, false if transitive
PURL string // Package URL (pkg:ecosystem/name@version)
RegistryURL string // Source registry URL (if non-default)
}Integrity is an opaque verification value derived from the source file. The
digest encoding remains ecosystem-specific, and parsers may add an algorithm
prefix such as sha256- when the source stores it separately. That prefix does
not imply Subresource Integrity: the digest may use hexadecimal, base64, Nix
base32, or another ecosystem-specific form. Consumers should only decode or
convert the value with knowledge of the source format.
When a dependency comes from a non-default registry, the PURL includes a repository_url qualifier (e.g., pkg:npm/foo@1.0.0?repository_url=https://npm.mycompany.com/). Default registries like registry.npmjs.org, pypi.org, and rubygems.org are not included in the PURL.
type Declaration struct {
Name string // Package name
Version string // Version requirement as written in the manifest
Scope Scope // runtime, development, test, build, optional
PURL string // Versionless Package URL
Location string // Opaque parser-defined identity within the manifest
}Declarations preserve source-level references without applying inheritance,
merging, interpolation, or other effective-model resolution. Consumers can use
Location to match the same logical entry across edits, but should not parse
its ecosystem-specific value. A declaration PURL omits the version because the
raw requirement may be a range or property expression.
Parsers that do not preserve source locations leave Declarations empty.
The pom.xml parser populates parents, dependencies, dependency management,
plugins, plugin dependencies, plugin management, build extensions, and their
profile-scoped forms.
type ParseResult struct {
Ecosystem string // npm, gem, pypi, golang, cargo, etc.
Kind Kind // manifest, lockfile, or supplement
Name string // the package's own name, when the format declares one
Version string // the package's own version, when declared
Licenses []string // raw declared license values
LicenseFile string // manifest-relative path to a declared license file
Dependencies []Dependency
Declarations []Declaration
}Name and Version are populated for manifest formats that declare their own package identity (Cargo.toml [package], package.json "name", go.mod module, .gemspec, and so on). They are empty for lockfiles and for dependency-only files like Gemfile or requirements.txt.
Licenses contains decoded values as declared by the manifest; it does not normalize them into SPDX expressions. LicenseFile is populated when a format explicitly identifies a license file. Both are empty for formats without license metadata.
type VendorDiscovery struct {
Roots []VendorRoot
Dependencies []VendoredDependency
}
type VendorRoot struct {
Path string
Ecosystem string
ConfigPath string
}
type VendoredDependency struct {
Name string
Version string
Ecosystem string
Kind Kind
PURL string
RootPath string
EvidencePath string
}const (
Manifest Kind = "manifest" // Declared dependencies with version constraints
Lockfile Kind = "lockfile" // Resolved dependencies with exact versions
Supplement Kind = "supplement" // Provides extra data (e.g. integrity hashes) for a manifest's dependencies
Vendor Kind = "vendor" // Exact package identity stored under a vendor root
)const (
Runtime Scope = "runtime"
Development Scope = "development"
Test Scope = "test"
Build Scope = "build"
Optional Scope = "optional"
)