Skip to content

fix(deps): update dependencies - #30

Merged
tannevaled merged 1 commit into
mainfrom
renovate/deps
Oct 15, 2026
Merged

tannevaled merged 1 commit into
mainfrom
renovate/deps

Conversation

@tannevaled

@tannevaled tannevaled commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
github.com/go-crdt/crdt v0.56.2 → v0.57.0 age confidence
github.com/go-pdfkit/ops v0.14.0 → v0.20.0 age confidence
github.com/go-pdfkit/reader v0.7.0 → v0.9.0 age confidence

Release Notes

go-crdt/crdt (github.com/go-crdt/crdt)

v0.57.0

Compare Source

go-pdfkit/ops (github.com/go-pdfkit/ops)

v0.20.0

Compare Source

v0.19.0

Compare Source

v0.18.0

Compare Source

v0.17.0

Compare Source

v0.16.0: — the colour the text is painted in

Compare Source

textcolour paints the text one colour and leaves the rest of the page alone.

pdfops textcolour -to '#​0000ff' report.pdf blue-text.pdf
pdfops textcolour -to black -pages 1-4 scan.pdf fixed.pdf

⛔ Setting a colour before each text object is not enough, and that is what
the first draft did. A text object that sets its own colour overrides it, so
a page whose paragraphs say 1 0 0 rg came out unchanged while the tool
reported success. Every colour operator inside a text object is blanked —
g, rg, k, cs, sc, scn and their stroking capitals — so the colour
asked for is the one that paints.

⛔ The colour goes outside the text object, wrapped in q/Q. A text
object does not save the graphics state, so a colour set inside one leaks into
whatever is drawn after it — which is how a recolouring turns a company's logo
the same shade as its paragraphs. A test asserts the rectangle beside the text
keeps its own red.

Both the filling and the stroking colour are set, because text has render
modes: 0 fills, 1 strokes, 2 does both. A tool that set only the fill would
leave outlined text in its old colour.

⛔ It splices, and does not re-serialise

Writing the operations back out would mean formatting every operand again,
including an inline image's still-encoded bytes, where a formatter that is
merely lossless-for-objects can change what the image means. So the
rewriting keeps every byte it does not deliberately change — which is why
reader.Operation carries its byte
range, added for this. A stream with no text comes back byte for byte
unchanged.

The colour operators are blanked with spaces rather than deleted, so every
offset after one is still the offset the scan reported. Deleting would be
correct only if the edits were applied back to front, and a rule that is
correct in one order only is a rule somebody will reorder.

⛔ What it cannot reach, it counts

Text drawn through a Form XObject is not recoloured, and the reason is not
difficulty: an XObject is shared, so recolouring one would change pages the
caller did not name. A document whose text is all inside XObjects would
otherwise come back looking converted and be unchanged — the one failure a
caller cannot see by opening the result and glancing at it. So the count is
reported:

3 drawing(s) were not recoloured: text inside a form or an image is shared
between pages, so recolouring it for one page would change others

Doc.UnreachedText is the same answer in Go, and it is zero until the document
has been written because until then there is nothing to have reached.

#f00 is full red

Each digit of a short hex colour is doubled, not shifted: #f00 is
ff0000, so the component is 0xf × 17. A shift gives 240/255 for what every
browser and design tool calls full red, and a logo recoloured to 94 % red is a
defect nobody can see but a printer. The test asserts the short and long forms
agree, and says the wrong number out loud so nobody has to work out which is
which.

v0.15.1: — the colour a print file declares

Compare Source

OutputIntents and URI join the entries a rewrite carries.

⛔ Found by an audit, not by a report

Twice in one afternoon this package was found dropping a catalogue entry
whose absence is not "no opinion" but a default — page labels, then optional
content — so the whole list was measured: a document holding twenty-three
catalogue entries, a watermark over it, and of each entry the question what
would its absence mean?

/OutputIntents ⛔ no colour management — a prepress file lost the ICC profile it declares, and would print differently with nothing to say why
/URI relative links resolve against wherever the viewer thinks the document is. The link is not removed, it is silently pointed elsewhere

Both name no page, so they copy safely. The test reaches the profile stream
and not just the array, because an /OutputIntents whose /DestOutputProfile
went with the rebuild declares a colour space it cannot supply.

What is deliberately not carried, now written down with its reason
  • /OpenAction, /AA — these are code. Dropping them is safer, and is
    what sanitize exists for;
  • /Legal, /DSS — a signature's attestation and validation data. A
    rewrite invalidated that signature the moment it changed a byte, and carrying
    the validation data of a signature that no longer verifies would say the
    document is still attested when it is not;
  • /Threads, /Collection — they point into the document, which is why
    /Names /Dests is not carried either.
⛔ And three the audit reported as lost that are not

/AcroForm, /Outlines and /StructTreeRoot are all carried. The audit's
fixture held an empty one of each, and an empty form, outline or structure
tree is deliberately not written.

A measured absence has to be read before it is believed — which is the other
half of why the audit was worth running, and why the report is in the README
rather than only in a commit message.

Checks

100 % statement coverage with zero uncovered blocks, go vet and gofmt
clean. Two mutations caught.

🤖 Generated with Claude Code

v0.15.0: — layers, and the hidden one every verb was revealing

Compare Source

Doc.Layers, SetLayerVisible, AddLayer and DropLayer, with
pdfops layers over them. This closes BentoPDF's pdf-layers.

⛔⛔ And it closes a disclosure

Measured before the change, with a probe written for the purpose: a one-page
drawing with a layer switched off, run through pdfops watermark, came back
with no /OCProperties at all — the content still marked as belonging to
a layer, the layer object still reachable through the page's own resources, and
nothing left saying which layer was hidden.

So the hidden layer showed. A drawing distributed with an "internal
pricing" layer turned off revealed it to any verb at all.

before after
/OCProperties after a watermark gone kept
the hidden layer visible still off

The witness test asserts the visibility, not the presence of the layers: a
carry that kept both and lost which was off would pass a test that counted
them, and would have exactly the same consequence.

What the file says about its own layers is obeyed
  • ⛔ /BaseState OFF inverts the question — everything is hidden unless
    /ON names it. A reader that only looked at /OFF would report every layer
    of such a document as visible, and a drawing that ships with all its layers
    off but one is exactly how an alternatives document is built;
  • ⛔ /Locked is the document asking that a layer not be switched, and
    -hide on one is refused: a drawing's dimension layer is what everything
    else is positioned against;
  • /D /Order is the nesting, written back nested, and a string inside it is
    the group's label rather than a layer.

⛔ Dropping a hidden layer is refused. What was drawn on it does not go with
it: the content stays in the page and stops being optional, so the hidden
drawing becomes permanently visible — the opposite of what somebody deleting
a layer called "internal pricing" expects.

⛔ A name is not an identifier. A drawing assembled from two others often
has two "Markup" layers, so an ambiguous name is refused with the count.

A merge keeps every source's layers, which keepCatalogue would not: it
refuses to merge two catalogues because two forms whose fields are named the
same cannot honestly become one — but two drawings' layers can.

⛔ Three defects the tests found in my own code, each invisible to the one before
the ceiling bounded the recursion, not the list it was checked on entry to the walk rather than inside its loop, so one flat /Order of six thousand layers passed it once and added all six thousand. The test that lowered the ceiling to two and got six back found it
/Order was written flat every hierarchy was lost on the way out. The test that read a nested order could not see it; only the round trip could
a child landed under the wrong parent with the nesting written, a child added under "Plan" after an unrelated layer became that layer's child, because the order is positional. The insertion goes after the parent's own subtree now, and the reported list and the written file share that one rule so the report cannot be a lie

Four guards were removed as dead code a coverage gap found: an explicit test
for a group's string label, which add already refuses by type, and three
not-found returns the validation upstream makes unreachable.

Checks

100 % statement coverage with zero uncovered blocks, go vet and gofmt
clean. Eight mutations caught, including the state this package was in
before
.

🤖 Generated with Claude Code

go-pdfkit/reader (github.com/go-pdfkit/reader)

v0.9.0

Compare Source

v0.8.0: — an Operation says which bytes of the stream it is

Compare Source

Operation gains Start and End: the byte range of the operation in the
stream it was scanned from — Start at its first operand (or at the operator
when it has none), End just past the operator.

⛔ They are here so a content stream can be edited in place

A tool that wants to put something before every BT has two honest ways to
find one:

  • re-serialise the whole stream, which risks changing what an inline
    image's bytes mean;
  • know where the operator was — and this scanner is the only thing that
    does.

BT appears inside strings, inside names, and inside an inline image's data,
and a byte search cannot tell those from an operator. The test pins the
discriminator:

(BT in a string) Tj  BT /F1 12 Tf ET
 ^ byte search: 1                      ← inside somebody's text
                     ^ the scan: 20     ← the operator

A tool splicing at index 1 corrupts the string.

Two details that are easy to get wrong
  • End is the lexer's position, not the operator's start plus its length.
    An inline image's operator token is BI and its operation runs to the EI
    three keywords later, so measuring from the operator would put the end in
    the middle of the image's data — where a splice corrupts the image instead
    of the stream around it. Asserted;
  • Start is the first operand's position, so splicing before an operation
    does not land between its operands and its operator. 1 0 0 RG starts at
    the 1, not at the RG.

The ranges of a stream are asserted ordered and disjoint, which is what
lets a caller splice at several of them in one pass, and a stream with rubbish
in it keeps honest ranges around what the scan stepped over.

Why in reader rather than in the caller

Three packages already scan content streams through this one scanner —
extract, render and latex — so the primitive is shared already; what was
missing was the one fact only the scan has. The first consumer is
go-pdfkit/ops, for a verb that recolours text without touching anything else.

Checks

100 % statement coverage, go vet and gofmt clean. Two mutations caught: the
range reduced to the operator alone, and the first-operand mark overwritten by
each later operand.

🤖 Generated with Claude Code


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

@tannevaled

tannevaled commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor Author

ℹ️ Artifact update notice

File name: go.mod

In order to perform the update(s) described in the table above, Renovate ran the go get command, which resulted in the following additional change(s):

  • 6 additional dependencies were updated
  • The go directive was updated for compatibility reasons

Details:

Package Change
go 1.27.1 -> 1.27.2
github.com/ajroetker/go-highway v0.0.4 -> v0.0.12
github.com/go-gfx/gfx v0.34.0 -> v0.34.1
github.com/go-images/jpeg2000 v0.1.0 -> v0.13.2
github.com/go-opentype/fonts v0.9.0 -> v0.12.0
github.com/go-opentype/opentype v0.12.0 -> v0.15.0
github.com/go-pdfkit/forms v0.3.0 -> v0.5.0

@tannevaled
tannevaled force-pushed the renovate/deps branch 2 times, most recently from 2b6a8e3 to a34351c Compare October 12, 2026 07:02
@tannevaled tannevaled changed the title fix(deps): update module github.com/go-crdt/crdt to v0.57.0 fix(deps): update dependencies Oct 12, 2026
@tannevaled
tannevaled merged commit d811de5 into main Oct 15, 2026
1 check passed
@tannevaled
tannevaled deleted the renovate/deps branch October 16, 2026 05:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant