From 931dd784f2c8a59bedb8382a2dea3332e585d59e Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Thu, 23 Jul 2026 19:26:29 +0100 Subject: [PATCH 1/2] build(release): bump develop to 2.1.0-SNAPSHOT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2.1 cycle ships the fixed-layout PPTX render backend and new public DocumentSession PPTX methods — additive public surface, so the next release is a minor, not the 2.0.1 patch the GA bump left as a placeholder. Move all 13 reactor version sites to 2.1.0-SNAPSHOT so the in-development version signals the minor and japicmp compares the 2.1 line against the 2.0.0 baseline. README/web/module install snippets stay on the latest published 2.0.0 until 2.1.0 ships — VersionConsistencyGuardTest enforces both halves. --- benchmarks/pom.xml | 2 +- bundle/pom.xml | 2 +- core/pom.xml | 2 +- coverage/pom.xml | 2 +- examples/pom.xml | 2 +- pom.xml | 2 +- qa/pom.xml | 2 +- render-docx/pom.xml | 2 +- render-pdf/pom.xml | 2 +- render-pptx/pom.xml | 2 +- templates/pom.xml | 2 +- testing/pom.xml | 2 +- wrapper/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 6e5eb31a..5c8d04c5 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -7,7 +7,7 @@ io.github.demchaav graph-compose-build - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT ../pom.xml diff --git a/bundle/pom.xml b/bundle/pom.xml index 5ad64177..40b97ed7 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -32,7 +32,7 @@ graph-compose and graph-compose-templates dependencies below use ${project.version}, so they follow automatically. --> - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT jar GraphCompose Bundle diff --git a/core/pom.xml b/core/pom.xml index 1cd3357d..5935d780 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ io.github.demchaav graph-compose-core - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT GraphCompose Core A declarative layout engine for programmatic document generation, implemented primarily in Java. This is the lean engine coordinate; depend on the `graph-compose` artifact for the drop-in, PDF-capable install. diff --git a/coverage/pom.xml b/coverage/pom.xml index e2aa25e2..0a509384 100644 --- a/coverage/pom.xml +++ b/coverage/pom.xml @@ -29,7 +29,7 @@ io.github.demchaav graph-compose-build - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 26c76243..1c04bab0 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -7,7 +7,7 @@ io.github.demchaav graph-compose-build - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 9b29c825..64e9f661 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.demchaav graph-compose-build - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT pom GraphCompose Build Aggregator diff --git a/qa/pom.xml b/qa/pom.xml index 88100b32..0866454e 100644 --- a/qa/pom.xml +++ b/qa/pom.xml @@ -22,7 +22,7 @@ io.github.demchaav graph-compose-build - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT ../pom.xml diff --git a/render-docx/pom.xml b/render-docx/pom.xml index 5f01e93e..b705b658 100644 --- a/render-docx/pom.xml +++ b/render-docx/pom.xml @@ -19,7 +19,7 @@ --> io.github.demchaav graph-compose-render-docx - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT GraphCompose Render — DOCX Semantic DOCX export backend for GraphCompose, backed by Apache POI. diff --git a/render-pdf/pom.xml b/render-pdf/pom.xml index 4947d6b7..445eb319 100644 --- a/render-pdf/pom.xml +++ b/render-pdf/pom.xml @@ -25,7 +25,7 @@ --> io.github.demchaav graph-compose-render-pdf - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT GraphCompose Render — PDF The PDFBox-backed PDF render backend for GraphCompose. diff --git a/render-pptx/pom.xml b/render-pptx/pom.xml index 26a8911d..9bbf437a 100644 --- a/render-pptx/pom.xml +++ b/render-pptx/pom.xml @@ -19,7 +19,7 @@ --> io.github.demchaav graph-compose-render-pptx - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT GraphCompose Render — PPTX PPTX render backends for GraphCompose: the coordinate-exact fixed-layout backend (POI XSLF) and the slide-safe semantic export skeleton. diff --git a/templates/pom.xml b/templates/pom.xml index 34028cd3..1a05d320 100644 --- a/templates/pom.xml +++ b/templates/pom.xml @@ -17,7 +17,7 @@ --> io.github.demchaav graph-compose-templates - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT GraphCompose Templates Built-in CV, cover-letter, invoice, and proposal document templates for GraphCompose. diff --git a/testing/pom.xml b/testing/pom.xml index 3fa18625..784ca16e 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -19,7 +19,7 @@ --> io.github.demchaav graph-compose-testing - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT GraphCompose Testing Consumer testing support for GraphCompose: layout-snapshot assertions and PDF visual regression. diff --git a/wrapper/pom.xml b/wrapper/pom.xml index 2e9978d9..869b9efb 100644 --- a/wrapper/pom.xml +++ b/wrapper/pom.xml @@ -22,7 +22,7 @@ --> io.github.demchaav graph-compose - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT GraphCompose The graph-compose coordinate: a drop-in aggregator over graph-compose-core for a PDF-capable install. From f7905200159ce292f057a05eda18bfb15fb88925 Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Fri, 24 Jul 2026 23:44:40 +0100 Subject: [PATCH 2/2] docs(api): record the 2.1 surface with correct @since tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep-with-next and the alpha-state helpers landed after the v2.0.0 tag, but their Javadoc claimed `@since 2.0.0` and their changelog entries sat under the dated `## v2.0.0 — 2026-07-13` heading. Both are published artifacts — the javadoc jar on Central is immutable and the changelog section becomes the GitHub Release notes — so a reader upgrading from 2.0.0 was told the API had always been there. Retag the six members that shipped in this cycle (`DocumentNode.keepWithNext`, `SectionBuilder.keepWithNext` and its boolean overload, `LineBuilder.keepWithNext` and its boolean overload, `NodeDefinition.firstSliceHeight`) to `@since 2.1.0`, and add the missing tag to five members that had none: `MarkdownInline`'s `appendTransformed` / `appendUpperCased` / `appendIfPresent` and `PdfRenderEnvironment`'s `fillAlphaState` / `strokeAlphaState`. Move the four keep-with-next entries out of the v2.0.0 section into v2.1.0 and open that section as `## v2.1.0 — Planned`, the header form the release script dates. Record the node-model delta the feature entries omitted: the new default method on `DocumentNode` and the trailing `keepWithNext` component on `SectionNode` (13 -> 14) and `LineNode` (17 -> 18), which leaves constructor calls working through the previous-arity overloads but changes what a record deconstruction pattern must bind. The compat constructors themselves keep no `@since` — their signatures were the canonical record constructors at v2.0.0 and have been callable since then. Verified: full reactor `clean verify` green (1508 tests, 0 failures); japicmp against the 2.0.0 baseline green with the gate active at 2.1.0-SNAPSHOT; `javadoc:javadoc` green across the six published modules. --- CHANGELOG.md | 72 ++++++++++--------- .../compose/document/dsl/LineBuilder.java | 4 +- .../compose/document/dsl/SectionBuilder.java | 4 +- .../document/layout/NodeDefinition.java | 2 +- .../compose/document/node/DocumentNode.java | 2 +- .../fixed/pdf/PdfRenderEnvironment.java | 2 + .../templates/core/text/MarkdownInline.java | 3 + 7 files changed, 51 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eba9453..c12c0fd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,49 @@ All notable changes to GraphCompose are documented here. Versions follow semantic versioning; release dates are ISO 8601. -## v2.1.0 — in progress +## v2.1.0 — Planned ### Public API +- **Keep a heading with its content** — `SectionBuilder.keepWithNext()`. A section + marked keep-with-next is never left stranded as the last block on a page apart from + the content it introduces: when the section plus the first slice of the following + block would overflow the remaining page space (but fit on a fresh page), the section + relocates to the next page so the heading stays glued to its body. The first slice is + a paragraph's first line, a table's repeated header rows plus first body row, or a + list's first item, so the rule holds whether the following block is atomic or a + page-spanning table or list. Distinct from `keepTogether()`, which relocates a + *whole* block — keep-with-next binds only the start of the following block, the right + tool for a boxed section title above a long, page-spanning body. Inert when nothing + follows (a trailing heading is never moved) and best-effort when the heading plus the + first slice cannot share a page. Default off, so layouts that do not opt in are + unchanged. +- `LineBuilder.keepWithNext()` — the line counterpart of + `SectionBuilder.keepWithNext()`, so a full-width header rule joins its banner's + keep-with-next run and the whole title block (rule + banner + rule) relocates + together instead of the banner stranding apart from its rules or its body. +- Keep-with-next surfaces on the node model as well: `DocumentNode.keepWithNext()` + is a new default method (existing implementations keep the `false` default and + need no change), and `SectionNode` and `LineNode` each gain a trailing + `keepWithNext` record component. Constructor calls are unaffected — both records + keep an overload at the previous argument count that defaults the flag to + `false` — but the canonical component count changed (`SectionNode` 13 → 14, + `LineNode` 17 → 18), so a **record deconstruction pattern** written against the + 2.0.0 component list must add the new binding to compile. +- **Single-column CV presets no longer orphan a section title.** Every preset whose + sections flow down the page — BoxedSections, MinimalUnderlined, ModernProfessional, + Executive, CenteredHeadline, BlueBanner, EditorialBlue, and ClassicSerif — keeps a + section heading with the first line of its body across a page break: a standalone + header section binds to the following body section (a multi-node rule + banner + rule + group binds as one run), and a combined header+body module keeps the heading in a + nested keep-with-next group — including Panel's full-width Profile card, whose header + now stays with the summary if a long profile splits the card. Multi-column presets + place their sections in fixed columns that do not paginate, so no heading can strand + there. +- **The Modern Proposal template no longer orphans a section heading.** Its flowing + section bodies, the Timeline and Investment tables, and the Acceptance terms each keep + their title with the first line of the block it introduces across a page break — each + title now renders in its own keep-with-next section rather than a bare paragraph. - **CV entry titles and subtitles accept inline `[text](url)` links.** In the layered CV presets, a `[label](url)` in an experience/education entry title or subtitle now renders as a clickable hyperlink — the same inline-Markdown convention already used @@ -303,37 +342,6 @@ for this cycle. ### Public API -- **Keep a heading with its content** — `SectionBuilder.keepWithNext()`. A section - marked keep-with-next is never left stranded as the last block on a page apart from - the content it introduces: when the section plus the first slice of the following - block would overflow the remaining page space (but fit on a fresh page), the section - relocates to the next page so the heading stays glued to its body. The first slice is - a paragraph's first line, a table's repeated header rows plus first body row, or a - list's first item, so the rule holds whether the following block is atomic or a - page-spanning table or list. Distinct from `keepTogether()`, which relocates a - *whole* block — keep-with-next binds only the start of the following block, the right - tool for a boxed section title above a long, page-spanning body. Inert when nothing - follows (a trailing heading is never moved) and best-effort when the heading plus the - first slice cannot share a page. Default off, so layouts that do not opt in are - unchanged. -- `LineBuilder.keepWithNext()` — the line counterpart of - `SectionBuilder.keepWithNext()`, so a full-width header rule joins its banner's - keep-with-next run and the whole title block (rule + banner + rule) relocates - together instead of the banner stranding apart from its rules or its body. -- **Single-column CV presets no longer orphan a section title.** Every preset whose - sections flow down the page — BoxedSections, MinimalUnderlined, ModernProfessional, - Executive, CenteredHeadline, BlueBanner, EditorialBlue, and ClassicSerif — keeps a - section heading with the first line of its body across a page break: a standalone - header section binds to the following body section (a multi-node rule + banner + rule - group binds as one run), and a combined header+body module keeps the heading in a - nested keep-with-next group — including Panel's full-width Profile card, whose header - now stays with the summary if a long profile splits the card. Multi-column presets - place their sections in fixed columns that do not paginate, so no heading can strand - there. -- **The Modern Proposal template no longer orphans a section heading.** Its flowing - section bodies, the Timeline and Investment tables, and the Acceptance terms each keep - their title with the first line of the block it introduces across a page break — each - title now renders in its own keep-with-next section rather than a bare paragraph. - **Reproducible PDF output** (`@Beta`). `PdfFixedLayoutBackend.builder().deterministic(true)` (or `.deterministic(Instant)` for an explicit timestamp) pins the document CreationDate / ModDate and derives the PDF `/ID` from the document metadata instead diff --git a/core/src/main/java/com/demcha/compose/document/dsl/LineBuilder.java b/core/src/main/java/com/demcha/compose/document/dsl/LineBuilder.java index 6b5fe1d4..3f7ebc8a 100644 --- a/core/src/main/java/com/demcha/compose/document/dsl/LineBuilder.java +++ b/core/src/main/java/com/demcha/compose/document/dsl/LineBuilder.java @@ -289,7 +289,7 @@ public LineBuilder fill() { * {@link SectionBuilder#keepWithNext()}. * * @return this builder - * @since 2.0.0 + * @since 2.1.0 */ public LineBuilder keepWithNext() { this.keepWithNext = true; @@ -301,7 +301,7 @@ public LineBuilder keepWithNext() { * * @param value true to keep the line with the next block * @return this builder - * @since 2.0.0 + * @since 2.1.0 */ public LineBuilder keepWithNext(boolean value) { this.keepWithNext = value; diff --git a/core/src/main/java/com/demcha/compose/document/dsl/SectionBuilder.java b/core/src/main/java/com/demcha/compose/document/dsl/SectionBuilder.java index 78972e64..131bbef9 100644 --- a/core/src/main/java/com/demcha/compose/document/dsl/SectionBuilder.java +++ b/core/src/main/java/com/demcha/compose/document/dsl/SectionBuilder.java @@ -60,7 +60,7 @@ public SectionBuilder keepTogether(boolean value) { * nothing follows the section on the page. * * @return this builder - * @since 2.0.0 + * @since 2.1.0 */ public SectionBuilder keepWithNext() { this.keepWithNext = true; @@ -72,7 +72,7 @@ public SectionBuilder keepWithNext() { * * @param value true to keep the section with the first line of the next block * @return this builder - * @since 2.0.0 + * @since 2.1.0 */ public SectionBuilder keepWithNext(boolean value) { this.keepWithNext = value; diff --git a/core/src/main/java/com/demcha/compose/document/layout/NodeDefinition.java b/core/src/main/java/com/demcha/compose/document/layout/NodeDefinition.java index fdad87c1..49f4411d 100644 --- a/core/src/main/java/com/demcha/compose/document/layout/NodeDefinition.java +++ b/core/src/main/java/com/demcha/compose/document/layout/NodeDefinition.java @@ -132,7 +132,7 @@ default List emitOverlayFragments(PreparedNode prepared, * * @param prepared prepared node whose first slice is being measured * @return the first slice's height in points - * @since 2.0.0 + * @since 2.1.0 */ default double firstSliceHeight(PreparedNode prepared) { return prepared.measureResult().height(); diff --git a/core/src/main/java/com/demcha/compose/document/node/DocumentNode.java b/core/src/main/java/com/demcha/compose/document/node/DocumentNode.java index 8c8943d4..bc03759d 100644 --- a/core/src/main/java/com/demcha/compose/document/node/DocumentNode.java +++ b/core/src/main/java/com/demcha/compose/document/node/DocumentNode.java @@ -99,7 +99,7 @@ default boolean keepTogether() { * siblings relocate together, with the break hoisted before the run.

* * @return true to keep this node with the first line of the following block - * @since 2.0.0 + * @since 2.1.0 */ default boolean keepWithNext() { return false; diff --git a/render-pdf/src/main/java/com/demcha/compose/document/backend/fixed/pdf/PdfRenderEnvironment.java b/render-pdf/src/main/java/com/demcha/compose/document/backend/fixed/pdf/PdfRenderEnvironment.java index 42471903..ec8a07b4 100644 --- a/render-pdf/src/main/java/com/demcha/compose/document/backend/fixed/pdf/PdfRenderEnvironment.java +++ b/render-pdf/src/main/java/com/demcha/compose/document/backend/fixed/pdf/PdfRenderEnvironment.java @@ -123,6 +123,7 @@ public org.apache.pdfbox.pdmodel.PDPage documentPage(int localPageIndex) { * * @param alpha non-stroking alpha constant in {@code [0, 1]} * @return shared graphics state owned by the current render pass + * @since 2.1.0 */ public PDExtendedGraphicsState fillAlphaState(float alpha) { return fillAlphaStates.computeIfAbsent(alpha, value -> { @@ -139,6 +140,7 @@ public PDExtendedGraphicsState fillAlphaState(float alpha) { * * @param alpha stroking alpha constant in {@code [0, 1]} * @return shared graphics state owned by the current render pass + * @since 2.1.0 */ public PDExtendedGraphicsState strokeAlphaState(float alpha) { return strokeAlphaStates.computeIfAbsent(alpha, value -> { diff --git a/templates/src/main/java/com/demcha/compose/document/templates/core/text/MarkdownInline.java b/templates/src/main/java/com/demcha/compose/document/templates/core/text/MarkdownInline.java index 32da854d..cddfebf3 100644 --- a/templates/src/main/java/com/demcha/compose/document/templates/core/text/MarkdownInline.java +++ b/templates/src/main/java/com/demcha/compose/document/templates/core/text/MarkdownInline.java @@ -108,6 +108,7 @@ public static void appendTrimmed(RichText rich, String text, * @param text source string; null treated as empty * @param baseStyle style applied to the transformed runs * @param displayTransform transform applied to visible text (never the url) + * @since 2.1.0 */ public static void appendTransformed(RichText rich, String text, DocumentTextStyle baseStyle, @@ -133,6 +134,7 @@ public static void appendTransformed(RichText rich, String text, * @param rich target rich-text builder * @param text source string; null treated as empty * @param baseStyle style applied to the upper-cased runs + * @since 2.1.0 */ public static void appendUpperCased(RichText rich, String text, DocumentTextStyle baseStyle) { @@ -180,6 +182,7 @@ public static void appendPlainIfPresent(RichText rich, String prefix, * @param prefix separator prepended before the value (never a link) * @param value source string; null treated as empty * @param style style applied to the prefix and the value's plain runs + * @since 2.1.0 */ public static void appendIfPresent(RichText rich, String prefix, String value,