def process_model(
rendercv_model: RenderCVModel, file_type: Literal["typst", "markdown"]
) -> RenderCVModel:
"""Pre-process CV model for template rendering with format-specific transformations.
Why:
Templates need processed data, not raw model. This applies markdown
parsing, keyword bolding, connection formatting, date rendering, and
entry template expansion before templates execute.
Args:
rendercv_model: Validated CV model.
file_type: Target format for format-specific processors.
Returns:
Processed model ready for templates.
"""
rendercv_model = rendercv_model.model_copy(deep=True)
string_processors: list[Callable[[str], str]] = [
lambda string: make_keywords_bold(string, rendercv_model.settings.bold_keywords)
]
if file_type == "typst":
string_processors.extend([markdown_to_typst])
rendercv_model.cv.plain_name = rendercv_model.cv.name # ty: ignore[unresolved-attribute]
rendercv_model.cv.name = apply_string_processors(
rendercv_model.cv.name, string_processors
)
rendercv_model.cv.headline = apply_string_processors(
rendercv_model.cv.headline, string_processors
)
rendercv_model.cv.connections = compute_connections(rendercv_model, file_type) # ty: ignore[unresolved-attribute]
rendercv_model.cv.top_note = render_top_note_template( # ty: ignore[unresolved-attribute]
rendercv_model.design.templates.top_note,
locale=rendercv_model.locale,
current_date=rendercv_model.settings._resolved_current_date,
name=rendercv_model.cv.name,
single_date_template=rendercv_model.design.templates.single_date,
string_processors=string_processors,
)
rendercv_model.cv.footer = render_footer_template( # ty: ignore[unresolved-attribute]
rendercv_model.design.templates.footer,
locale=rendercv_model.locale,
current_date=rendercv_model.settings._resolved_current_date,
name=rendercv_model.cv.name,
single_date_template=rendercv_model.design.templates.single_date,
string_processors=string_processors,
)
pdf_title_placeholders: dict[str, str] = {
"CURRENT_DATE": date_object_to_string(
rendercv_model.settings._resolved_current_date,
locale=rendercv_model.locale,
single_date_template=rendercv_model.design.templates.single_date,
),
"NAME": rendercv_model.cv.plain_name or "", # ty: ignore[unresolved-attribute]
**build_date_placeholders(
rendercv_model.settings._resolved_current_date, locale=rendercv_model.locale
),
}
rendercv_model.settings.pdf_title = substitute_placeholders(
rendercv_model.settings.pdf_title, pdf_title_placeholders
)
if rendercv_model.cv.sections is None:
return rendercv_model
for section in rendercv_model.cv.rendercv_sections:
section.title = apply_string_processors(section.title, string_processors)
show_time_span = (
section.snake_case_title
in rendercv_model.design.sections.show_time_spans_in
)
for i, entry in enumerate(section.entries):
entry = render_entry_templates( # NOQA: PLW2901
entry,
templates=rendercv_model.design.templates,
locale=rendercv_model.locale,
show_time_span=show_time_span,
current_date=rendercv_model.settings._resolved_current_date,
)
section.entries[i] = process_fields(entry, string_processors)
return rendercv_model