Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,54 @@
All notable changes to GraphCompose are documented here. Versions
follow semantic versioning; release dates are ISO 8601.

## v2.2.1 — Planned
## v2.3.0 — Planned

### Public API

- **A CV section whose shape is a value, for CVs assembled at runtime.** The four
section records each fix one shape at compile time, which is right when a CV is
written in Java — you pick the record, the compiler checks it. It is the wrong model
when the CV arrives as data: a user who has just chosen "Volunteering, shaped like
Education, with dates" cannot instantiate a different record per choice, so every
shape somebody thought of would have to become a type.

`ModuleSection` carries the choice instead. One `CvItem` record holds every optional
field — title, link, subtitle, period, location, description lines — and a `CvKind`
(`PARAGRAPH`, `BULLETS`, `BULLETS_STACKED`, `INLINE_LIST`, `ENTRIES`,
`ENTRIES_DATED`) decides which of them are read: the same item renders with or without its dates depending on the kind
alone. `BodyStyle` decides whether a description reads as prose or as bullets, and
`SectionRole` states what a section *means* — the decision multi-column presets make
by matching headings against English keywords, which a CV headed `Ausbildung` or
`Навыки` never matches. The presets do not read the role yet; it travels with the
section now so a document built today needs no rewrite when the routing work lands.

The existing four records are untouched and mix with modules in the same document.
A module renders through the existing components rather than beside them, so one
drawn as `ENTRIES_DATED` lays out exactly like the `EntriesSection` carrying the same
content — held node-for-node by a parity suite, for every kind, alongside the
extracted text so structure and content are both pinned. The addition is binary-
compatible (the japicmp gate covers this module); it is a fifth permit on a sealed
interface, so a downstream `switch` over `CvSection` that was exhaustive without a
`default` needs one.

### Fixed

- **A section shape a preset did not recognise was lost three different ways.**
`BlueBanner` and `ClassicSerif` each kept a private copy of the section dispatcher
whose final `else` threw `IllegalStateException`; `EditorialBlue`'s had no `else` at
all; and `SectionLookup.hasContent` — which presets consult *before* routing, and
which `SectionAllocation.remaining()` uses to decide what still needs a home —
answered `false` for any subtype it had not been taught, dropping the heading along
with the body. So a section type added to the model would have crashed two presets
and vanished from several more, including through the very fallback that exists to
catch unplaced sections. All three dispatchers now delegate unfamiliar shapes to the
canonical one, and `hasContent` answers for every permit.

- **An entry with no date no longer reserves a column for it.** `EntryRenderer` always
emitted the two-column title/date header, so an undated entry — a certification, a
project — had its title wrapped early to leave room for nothing. Its Javadoc had
described the collapsing behaviour since the entry renderer was written. No shipped
fixture has a blank date, so no existing render moves.

### Build

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

> **Release status** —
> 🟢 **Latest stable**: [v2.2.0](https://github.com/DemchaAV/GraphCompose/releases/tag/v2.2.0) — the **right-to-left** release: Hebrew and Arabic lay out, shape, join and mirror through PDF, PowerPoint and Word — in paragraphs and in table cells — with the fonts to render them. See [CHANGELOG.md](./CHANGELOG.md).
>  ·  🟡 **In development**: v2.2.1 on `develop` — see [CHANGELOG.md](./CHANGELOG.md).
>  ·  🟡 **In development**: v2.3.0 on `develop` — see [CHANGELOG.md](./CHANGELOG.md).

<p align="center">
<a href="https://demchaav.github.io/GraphCompose/"><b>Live Showcase</b></a>
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>io.github.demchaav</groupId>
<artifactId>graph-compose-build</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
graph-compose and graph-compose-templates dependencies below use
${project.version}, so they follow automatically.
-->
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>GraphCompose Bundle</name>
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.demchaav</groupId>
<artifactId>graph-compose-core</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>

<name>GraphCompose Core</name>
<description>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.</description>
Expand Down
2 changes: 1 addition & 1 deletion coverage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<parent>
<groupId>io.github.demchaav</groupId>
<artifactId>graph-compose-build</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion docs/roadmaps/post-2.0-engineering.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ exercise it. Report-only; thresholds can follow after a baseline read.
`japicmp` ran report-only through the 2.0 major — the major intentionally broke
binary compatibility. With the 2.0.0 GA artifacts on Central the gate switched to
per-module baselines pinned at the major's floor (2.0.0) in break-on-incompatible
mode: `graph-compose-core` first, `graph-compose-templates` since 2.2.1 — each
mode: `graph-compose-core` first, `graph-compose-templates` since 2.3.0 — each
module's `japicmp` profile lives in its own pom and runs in the PR-time
`Binary Compatibility` job, in `cut-release.ps1` step 5b, and in the publish
workflow. The remaining published modules (`render-pdf` / `render-docx` /
Expand Down
63 changes: 58 additions & 5 deletions docs/templates/v2-layered/using-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ it sets up the conceptual model in 5 minutes.
1. [The pieces you assemble](#the-pieces-you-assemble)
2. [Identity — name, contact, optional links](#identity)
3. [Section types](#section-types)
4. [Slots — main vs sidebar](#slots)
5. [Picking a preset](#picking-a-preset)
6. [Customising a theme](#customising-a-theme)
7. [Rendering — pageSize, margins, output](#rendering)
8. [Common patterns](#common-patterns)
4. [Building sections at runtime — `ModuleSection`](#runtime-modules)
5. [Slots — main vs sidebar](#slots)
6. [Picking a preset](#picking-a-preset)
7. [Customising a theme](#customising-a-theme)
8. [Rendering — pageSize, margins, output](#rendering)
9. [Common patterns](#common-patterns)

---

Expand Down Expand Up @@ -161,6 +162,58 @@ paragraph beneath.

---

<a id="runtime-modules"></a>
## Building sections at runtime — `ModuleSection`

The four types above are the right choice when you write a CV in Java:
you pick the record and the compiler checks it. They are the wrong one
when the CV is assembled from data — a form, a JSON payload, an LLM —
because the shape is not known until it arrives, and a user who picks
"dated entries" from a menu cannot instantiate a different record per
choice.

`ModuleSection` moves that choice into a value. One item record carries
every optional field, and a `CvKind` decides which of them are read:

```java
ModuleSection.builder("Volunteering", SectionRole.OTHER, CvKind.ENTRIES_DATED)
.item(CvItem.of("Mentor, Rails Girls")
.at("Rails Girls Berlin") // subtitle
.in("Berlin, DE") // location
.period("2019 - 2021") // read by dated kinds only
.bullets("Ran three weekend workshops"))
.build();
```

| `CvKind` | Shape | Reads |
|---|---|---|
| `PARAGRAPH` | prose under the section heading | `body` |
| `BULLETS` | a bullet per item, description inline | `title`, `body` (not `link`) |
| `BULLETS_STACKED` | a bullet per item, description underneath | `title`, `link`, `body` |
| `INLINE_LIST` | `Languages: Java 21, Kotlin` | `title`, `body` (not `link`) |
| `ENTRIES` | timeline, no date column | everything but `period` |
| `ENTRIES_DATED` | timeline with dates | everything |

Only `title` is required on an item. Whatever a kind does not read is
ignored, so the same item renders with or without its dates depending
on the kind alone — which is what lets a "Volunteering" module be
shaped exactly like Education without a new type.

`SectionRole` says what a section *means*, separately from how it
draws. Multi-column presets decide what belongs in a sidebar by
matching headings against English keywords, which a CV headed
`Ausbildung` or `Навыки` never matches. The role is where that
decision belongs — stated by the author, who knows the answer. **The
presets do not read it yet**: today it travels with the section and is
the input the routing work will consume, so a document built now needs
no rewrite when they do.

Modules and the four fixed types mix freely in one document, and both
render through the same components — a module drawn as `ENTRIES_DATED`
lays out exactly like the `EntriesSection` carrying the same content.

---

<a id="slots"></a>
## Slots — main vs sidebar

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>io.github.demchaav</groupId>
<artifactId>graph-compose-build</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.demchaav</groupId>
<artifactId>graph-compose-build</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<packaging>pom</packaging>

<name>GraphCompose Build Aggregator</name>
Expand Down
2 changes: 1 addition & 1 deletion qa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>io.github.demchaav</groupId>
<artifactId>graph-compose-build</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Loading
Loading