feat(templates): route CV sections by what they mean, not by what they are called - #582
Open
DemchaAV wants to merge 1 commit into
Open
feat(templates): route CV sections by what they mean, not by what they are called#582DemchaAV wants to merge 1 commit into
DemchaAV wants to merge 1 commit into
Conversation
…y are called A preset with a designed layout places sections into fixed slots, and it chose what went where by matching the section's heading against a list of English words each preset kept privately — then guarded the slot on the section's Java type as well. A CV headed Ausbildung, Опыт работы, or anything else in the author's own language matched nothing: the section was dropped and the slot that wanted it rendered empty. Nothing failed. The CV came out looking finished, one job short. A module already knows the answer, because its author said so. SectionRouter asks the role first and falls back to the headings for the sections that carry none — every hand-written one, and any module left as OTHER — so a document of hand-written sections routes exactly as before. A heading may not overrule a role: a module declared EXPERIENCE and headed "Projects" goes where its author put it, and the projects slot does not also claim it, which would have rendered it twice. An empty module does not shadow a section that has content. The second half is the shape. These slots are written against one section type because each draws its content its own way, so a module reaching one was discarded by the guard however well it was routed. The router hands each slot the section lowered to the type it expects, and the preset then draws it with the entry style, rules and spacing that make it that preset. What the lowering costs is stated per finder and pinned by tests: a description is joined where the target holds one string, bulleted points join with a comma and prose with a space, a linked title survives only the row style that bolds without markdown markers, and a skill with nothing under it stays a skill rather than becoming a category holding itself. SectionAllocation.claim gained the same role-first overload for the preset that allocates rather than looks up, and TimelineMinimal learned to flatten a module the way it flattens everything else — one line per item, because those lines are what its column pagination measures. SidebarPortrait's languages slot sniffs its rows for something language-shaped, because it also accepts an Additional Information section and has to pick them out. A section routed there by role is entirely languages and needs to look like nothing, so when the sniff finds none it now takes them all; otherwise role routing would have replaced a silent drop with a heading over blank space. These presets still drop a section they have no slot for. Their whole body is one atomic row that cannot break across pages, so there is nowhere to put it — that half waits on pagination, not routing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A preset with a designed layout places sections into fixed slots, and it chose what went where by matching the section's heading against a list of English words each preset kept privately — then guarded the slot on the section's Java type as well. A CV headed
Ausbildung,Опыт работы, or anything else in the author's own language matched nothing: the section was dropped and the slot that wanted it rendered empty. Nothing failed; the CV came out looking finished, one job short. That is the failure the whole runtime-module model exists to remove, and until now it removed it only for the presets that render every section in order.A module already knows the answer, because its author said so when they picked the role.
What changed
SectionRouterasks the role first, and falls back to the headings for the sections that carry none — every hand-written one, and any module left asSectionRole.OTHER— so a document of hand-written sections routes exactly as it did.EXPERIENCEand headed "Projects" goes where its author put it; without this the experience slot claims it by role and the projects slot claims it by heading, and it renders twice. An empty module also no longer shadows a section that has content.if (!(section instanceof EntriesSection …)) return;. The router lowers a matched module to the type the slot expects, and the preset then draws it with the entry style, rules and spacing that make it that preset — rather than the canonical components, which several of these layouts cannot even host (a nested row inside a card throws).Java 21: Java 21).SectionAllocation.claim(role, keys)is the same idea for the preset that allocates rather than looks up, and TimelineMinimal learned to flatten a module the way it flattens everything else — one line per item, because those lines are what its column pagination measures; rendering it richly would decouple the draw from the height estimate and overflow an atomic row.Verification
javadoc:javadoc→ 0 warnings. The 16 visual baselines are untouched, which follows from the fallback being the old lookup verbatim for sections that carry no role.RoleRoutingTest: a CV written in Russian and German rendered through all sixteen presets, asserting the experience and education modules reach the page — plus the "wrong" kind for each slot (experience as bullets, education as an inline list), because the author picks the kind and the preset gets no veto. Proven non-vacuous: disabling role lookup turns 17 of its 34 cases red.SectionRouterTest(12 cases) pins each lowering's output strings — the separator, the linked title, the skills grouping, the period suppression, and that a section already of the right type passes through untouched rather than being rebuilt.SectionAllocationTest(+4) covers the role-first overload: role beats heading, heading still works for role-less sections, a declared role is not claimable by another slot's keywords, and claiming still hands each section out once.Lane: templates (two components, ten presets).
Limits:
flow.addRow(...), which is atomic and cannot break across pages, so there is nowhere to put an extra section. Lifting it is the pagination work (ColumnPagination), not routing, and the*_LIMITcaps that exist because of it come off in the same change.ModularCvTemplatehere, for exactly that reason;CvTemplates.modular()still lists seven.RowStylea caller passes toSectionRouter.rowsreaches the page only inPanel; the other slots draw rows their own way and ignore it.