lockfile

package
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package lockfile builds a resolve.Graph from a lockfile, without running any package manager or other process.

Lockfiles are untrusted input. Parsing is bounded by Limits: a lockfile larger than MaxBytes is not parsed, and the graph stops growing at MaxNodes nodes or MaxEdges edges. A malformed or unsupported lockfile yields an unknown root with a reason; a lockfile that parses but cannot be fully resolved yields a partial root with a reason. Parse never fails on content.

Each format names its roots after the manifest beside the lockfile, joined with the workspace directory for formats that record workspaces (package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml, uv.lock). Cargo.lock does not record where its workspace members live, so their roots come from the member manifests in Input.Members. A workspace, path or link package that something depends on is a local node, with its own dependencies as edges. Lockfile entries that no root reaches become non-direct members of the root beside the lockfile.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrUnsupported = errors.New("unsupported lockfile")

ErrUnsupported is returned for a lockfile whose base name is not a supported format.

Functions

func ManifestFor

func ManifestFor(path string) (string, bool)

ManifestFor returns the base name of the sibling manifest the format of path reads, if it reads one.

func Parse

func Parse(in Input, lim Limits) (resolve.Graph, error)

Parse builds the graph of one lockfile. The only error is ErrUnsupported; problems with the content are reported on the roots.

func ParseFS

func ParseFS(fsys fs.FS, p string, lim Limits) (resolve.Graph, error)

ParseFS reads the lockfile at path in fsys, and the sibling manifest when its format reads one, then parses them. For Cargo.lock it also reads the manifest of each workspace member the sibling Cargo.toml lists; more than MaxNodes of them is too_large, like oversized bytes. For packages.lock.json it looks for the project file beside it. The lockfile is read up to MaxBytes+1 bytes, and the manifests up to MaxBytes+1 bytes in total, so oversized input costs no more than that. A missing manifest is not an error; formats that need it report it on the root.

Example
package main

import (
	"fmt"
	"testing/fstest"

	"github.com/scanoss/scanoss.go/pkg/dependencies/resolve/lockfile"
)

func main() {
	fsys := fstest.MapFS{"web/package-lock.json": {Data: []byte(`{
  "lockfileVersion": 3,
  "packages": {
    "": {"dependencies": {"express": "^4.19.0"}},
    "node_modules/express": {"version": "4.19.2", "dependencies": {"debug": "2.6.9"}},
    "node_modules/debug": {"version": "2.6.9"}
  }
}`)}}

	g, err := lockfile.ParseFS(fsys, "web/package-lock.json", lockfile.DefaultLimits())
	if err != nil {
		panic(err)
	}
	for _, r := range g.Roots {
		fmt.Println(r.Manifest, r.Status)
		for _, m := range r.Members {
			fmt.Println(" ", m.ID, "direct:", m.Direct)
		}
		for _, e := range r.Edges {
			fmt.Println(" ", e.From, "->", e.To)
		}
	}
}
Output:
web/package.json complete
  pkg:npm/debug@2.6.9 direct: false
  pkg:npm/express@4.19.2 direct: true
  pkg:npm/express@4.19.2 -> pkg:npm/debug@2.6.9

func Supported

func Supported(path string) bool

Supported reports whether path's base name is a lockfile this package parses.

Types

type Input

type Input struct {
	Path     string // slash path of the lockfile; names the roots, never opened
	Lockfile []byte
	Manifest []byte // the sibling manifest named by ManifestFor; nil when absent
	// Members holds workspace member manifests keyed by slash path relative
	// to the lockfile's directory, such as "crates/app/Cargo.toml", for
	// Cargo.lock. For packages.lock.json it holds the project file beside
	// it, such as "App.csproj", which names the root; its content is not
	// read.
	Members map[string][]byte
}

Input is one lockfile and, when its format reads one, its sibling manifest.

type Limits

type Limits struct {
	MaxBytes int64 // largest lockfile, and largest total of its manifests, read and parsed
	MaxNodes int   // nodes kept; reaching it makes the roots partial (node_limit)
	MaxEdges int   // edges kept; reaching it makes the roots partial (edge_limit)
}

Limits bounds the work Parse does on one lockfile.

func DefaultLimits

func DefaultLimits() Limits

DefaultLimits returns limits that fit any real lockfile: 32 MiB, 50,000 nodes and 500,000 edges.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL