Help us shape the future of Go! Take the 2026 Go Developer Survey

parity

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: BSD-3-Clause Imports: 8 Imported by: 0

Documentation

Overview

Package parity measures how much of another toolkit's published tool list this fleet can be SHOWN to do.

⛔ It refuses to report a figure if any claim cannot be verified. A parity number assembled from a mapping nobody checks is a vibe with a decimal point in it. The first version of this measurement, kept by hand, was wrong by under-counting, and the only reason anybody found out is that somebody said "not sure that map is up to date".

Two kinds of claim, and each is checked against something that was BUILT:

  • "verb:NAME" — the verb has to appear in a command's own help output, read off a binary compiled from the source being measured. Not from a README, not from anybody's notes.
  • "REPO#SYMBOL" — the symbol has to appear in that repository's Go source.

A tool with no claim counts as NOT covered. That is the conservative direction, and it is deliberate: this must never make the fleet look better than it is.

Index

Constants

This section is empty.

Variables

View Source
var BentoPDF = []Claim{

	{Tool: "merge-pdf", Claim: "verb:merge"},
	{Tool: "split-pdf", Claim: "verb:split"},
	{Tool: "extract-pages", Claim: "verb:select"},
	{Tool: "delete-pages", Claim: "verb:delete"},
	{Tool: "reverse-pages", Claim: "verb:reverse"},
	{Tool: "rotate-pdf", Claim: "verb:rotate"},
	{Tool: "rotate-custom", Claim: "verb:rotate"},
	{Tool: "crop-pdf", Claim: "verb:crop"},
	{Tool: "fix-page-size", Claim: "verb:resize"},
	{Tool: "organize-pdf", Claim: "verb:move"},
	{Tool: "n-up-pdf", Claim: "verb:nup"},
	{Tool: "pdf-booklet", Claim: "verb:booklet"},
	{Tool: "alternate-merge", Claim: "verb:interleave"},
	{Tool: "combine-single-page", Claim: "verb:onepage"},
	{Tool: "posterize-pdf", Claim: "verb:poster"},
	{Tool: "add-blank-page", Claim: "verb:blank"},
	{Tool: "page-dimensions", Claim: "verb:info"},

	{Tool: "add-watermark", Claim: "verb:watermark"},
	{Tool: "add-stamps", Claim: "verb:stamp"},
	{Tool: "page-numbers", Claim: "verb:number"},
	{Tool: "add-page-labels", Claim: "verb:labels"},
	{Tool: "pdf-layers", Claim: "verb:layers"},

	{Tool: "text-color", Claim: "verb:textcolour"},
	{Tool: "bates-numbering", Claim: "verb:bates"},

	{Tool: "sign-pdf", Claim: "verb:place"},

	{Tool: "edit-metadata", Claim: "verb:metadata"},
	{Tool: "view-metadata", Claim: "verb:metadata"},
	{Tool: "remove-metadata", Claim: "verb:strip"},
	{Tool: "sanitize-pdf", Claim: "verb:sanitize"},
	{Tool: "compress-pdf", Claim: "verb:compress"},
	{Tool: "flatten-pdf", Claim: "verb:flatten"},
	{Tool: "bookmark", Claim: "verb:outline"},
	{Tool: "table-of-contents", Claim: "verb:outline"},

	{Tool: "protect-pdf", Claim: "verb:encrypt"},
	{Tool: "unlock-pdf", Claim: "verb:decrypt"},
	{Tool: "change-permissions", Claim: "verb:permissions"},
	{Tool: "remove-restrictions", Claim: "verb:permissions"},

	{Tool: "pdf-to-text", Claim: "verb:text"},

	{Tool: "extract-tables", Claim: "verb:tables"},
	{Tool: "pdf-to-csv", Claim: "verb:tables"},

	{Tool: "pdf-to-markdown", Claim: "verb:markdown"},
	{Tool: "prepare-pdf-for-ai", Claim: "verb:markdown"},

	{Tool: "pdf-to-word", Claim: "verb:word"},
	{Tool: "pdf-to-excel", Claim: "verb:excel"},

	{Tool: "pdf-to-json", Claim: "verb:objects"},
	{Tool: "extract-images", Claim: "verb:images"},
	{Tool: "extract-attachments", Claim: "verb:detach"},
	{Tool: "add-attachments", Claim: "verb:attach"},
	{Tool: "edit-attachments", Claim: "verb:attachments"},

	{Tool: "form-filler", Claim: "verb:fill"},

	{Tool: "form-creator", Claim: "verb:addfields"},

	{Tool: "rasterize-pdf", Claim: "go-pdfkit/render#func Page"},
	{Tool: "invert-colors", Claim: "go-pdfkit/convert#images.Invert"},
	{Tool: "pdf-to-greyscale", Claim: "go-pdfkit/convert#images.Grayscale"},
	{Tool: "adjust-colors", Claim: "go-pdfkit/convert#images.AdjustContrast"},
	{Tool: "background-color", Claim: "go-pdfkit/convert#Background: bg"},
	{Tool: "scanner-effect", Claim: "go-pdfkit/convert#type ScannerEffect"},

	{Tool: "edit-pdf", Claim: "go-pdfkit/app#func main"},
	{Tool: "pdf-multi-tool", Claim: "go-pdfkit/app#func main"},

	{Tool: "cbz-to-pdf", Claim: "go-pdfkit/convert#func ArchiveToPDF"},
	{Tool: "pdf-to-cbz", Claim: "go-pdfkit/convert#func writeComicInfo"},
	{Tool: "pdf-to-zip", Claim: "go-pdfkit/convert#func Bundle"},
	{Tool: "svg-to-pdf", Claim: "go-pdfkit/convert#func RasterizeSVG"},

	{Tool: "odt-to-pdf", Claim: "go-odf/odf#func Parse"},
	{Tool: "ods-to-pdf", Claim: "go-odf/odf#office:spreadsheet"},
	{Tool: "odp-to-pdf", Claim: "go-odf/odf#office:presentation"},

	{Tool: "rtf-to-pdf", Claim: "go-rtf/rtf#func Parse"},

	{Tool: "word-to-pdf", Claim: "go-ooxml/ooxml#func ParseWord"},
	{Tool: "excel-to-pdf", Claim: "go-ooxml/ooxml#func ParseWorkbook"},
	{Tool: "powerpoint-to-pdf", Claim: "go-ooxml/ooxml#func ParsePresentation"},

	{Tool: "markdown-to-pdf", Claim: "go-richdoc/markdown#func Parse"},

	{Tool: "fb2-to-pdf", Claim: "go-richdoc/fb2#func Parse"},

	{Tool: "epub-to-pdf", Claim: "go-richdoc/epub#func (p *opf) readingOrder"},

	{Tool: "email-to-pdf", Claim: "go-richdoc/email#multipart/alternative"},

	{Tool: "mobi-to-pdf", Claim: "go-richdoc/mobi#func stripTrailing"},

	{Tool: "csv-to-pdf", Claim: "go-richdoc/data#func Sniff"},
	{Tool: "json-to-pdf", Claim: "go-richdoc/data#func uniformObjects"},
	{Tool: "xml-to-pdf", Claim: "go-richdoc/data#uniformKids"},
	{Tool: "txt-to-pdf", Claim: "go-richdoc/data#func laidOut"},

	{Tool: "image-to-pdf", Claim: "go-pdfkit/convert#func ToPDF"},
	{Tool: "png-to-pdf", Claim: "go-pdfkit/convert#image/png"},
	{Tool: "jpg-to-pdf", Claim: "go-pdfkit/convert#image/jpeg"},
	{Tool: "bmp-to-pdf", Claim: "go-pdfkit/convert#x/image/bmp"},
	{Tool: "tiff-to-pdf", Claim: "go-pdfkit/convert#x/image/tiff"},
	{Tool: "webp-to-pdf", Claim: "go-pdfkit/convert#x/image/webp"},

	{Tool: "psd-to-pdf", Claim: "go-pdfkit/convert#go-images/psd"},
	{Tool: "pdf-to-png", Claim: `go-pdfkit/convert#"png"`},
	{Tool: "pdf-to-jpg", Claim: `go-pdfkit/convert#"jpeg"`},
	{Tool: "pdf-to-bmp", Claim: `go-pdfkit/convert#"bmp"`},
	{Tool: "pdf-to-tiff", Claim: `go-pdfkit/convert#"tiff"`},

	{Tool: "pdf-to-webp", Claim: `go-pdfkit/convert#"webp"`},

	{Tool: "remove-annotations", Claim: "go-pdfkit/ops#func (d *Doc) RemoveAnnotations("},

	{Tool: "header-footer", Claim: `go-pdfkit/ops#"{pages}", strconv.Itoa(pages)`},

	{Tool: "duplex-collate", Claim: "verb:duplex"},

	{Tool: "divide-pages", Claim: "verb:divide"},
	{Tool: "remove-blank-pages", Claim: "verb:deblank"},

	{Tool: "repair-pdf", Claim: "verb:repair"},
}

BentoPDF maps BentoPDF's own tool names onto what this fleet can be SHOWN to do. Every entry is checked; absence is the default.

Measured against BentoPDF v2.8.8 at commit 6ce0d69 (its own last commit 2026-10-17, read 2026-10-18): 114 tools.

⛔ The commit is part of the figure. This line named 3a5f146, and that commit is not reachable in the clone the measurement actually reads — so the denominator was attributed to something nobody here can check. The count happens to be the same 114 at both readings, which is why it went unnoticed and why it is worth writing down: it would have gone on agreeing until the day BentoPDF added a tool.

Functions

func ReadTools

func ReadTools(dir fs.FS, skip ...string) ([]string, error)

ReadTools lists the other toolkit's tools from its own documentation directory: one Markdown file per tool, which is how BentoPDF publishes them.

⛔ Reading its list rather than restating it is the point. A list typed out here would be a snapshot of what somebody believed on the day they typed it, and the denominator of a parity figure is exactly the thing that must not quietly drift.

func Verbs

func Verbs(help io.Reader) ([]string, error)

Verbs reads a command's verbs off its own help output: the lines indented by exactly two spaces whose first word is lower-case.

It takes a reader rather than running anything, so that the shape of the help text is testable without a binary and the library never execs.

func Verify

func Verify(claim string, verbs []string, src fs.FS) error

Verify checks one claim. The error says what could not be shown.

Types

type Claim

type Claim struct {
	Tool  string // the other toolkit's own name for it
	Claim string // "" means we do not do this
}

A Claim is what a repository is said to do, and how to check it.

type Report

type Report struct {
	Tools     []string // every tool the other toolkit documents
	Covered   []string // those a verified claim answers
	Uncovered []string // those nothing claims
}

Report is the outcome of a measurement.

func Measure

func Measure(tools []string, table []Claim, verbs []string, src fs.FS) (Report, error)

Measure checks every claim and counts what is covered.

It refuses in three ways before it counts anything, and the three are different mistakes:

  • a tool claimed twice. The map keeps the last one and the total comes out short of what the table appears to say, SILENTLY — which is how this check came to exist: ten entries were added and the figure rose by nine.
  • a claim for a tool the other toolkit does not have. It inflates nothing by itself, but it means the table is being written against something other than the list, and that error has a direction nobody notices.
  • a claim that cannot be shown. An unverified claim is not a capability.

func (Report) Percent

func (r Report) Percent() float64

Percent is the share covered. It is only ever reached when every claim verified, because Measure returns an error otherwise.

Jump to

Keyboard shortcuts

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