/**
* A factual audit surface for the bundled LaTeX builder's structured records.
* This is never rendered. Reusing the HTML field vocabulary lets one gate
* compare source records without reverse-parsing TeX macros. The compiler's
* final-text gate still checks template text and non-record content.
*/
import { hasRequiredFields } from './cv-payload-schema.mjs';
// Keep TeX control syntax literal too: the verifier also accepts raw .tex,
// and must not interpret payload text as a document boundary or subheading.
const escape = value => String(value ?? '').replace(/&/g, '&').replace(/\\/g, '\').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''');
const field = (cls, value) => `
${escape(value)}
`;
const entries = (payload, section) => Array.isArray(payload[section])
? payload[section].filter(entry => hasRequiredFields(entry, section, 'tex')) : [];
/**
* Project only records whose slots exist in the selected bundled template.
* Ignore unsupported/unrendered payload keys, as the LaTeX builder does.
* @param {object} payload validated LaTeX payload
* @param {string} template template after empty sections have been removed
* @returns {string} escaped, non-rendered fact-gate input
*/
export function latexPayloadFactHtml(payload, template) {
const records = [];
if (template.includes('{{EXPERIENCE}}')) {
for (const entry of entries(payload, 'experience')) {
const bullets = Array.isArray(entry.bullets) ? entry.bullets.map(b => `${escape(b)}`).join('') : '';
records.push(`${field('job-company', entry.company)}${field('job-role', entry.role)}${field('job-period', entry.dates)}
`);
}
}
if (template.includes('{{EDUCATION}}')) {
for (const entry of entries(payload, 'education')) {
records.push(`${field('edu-title', entry.degree)}${field('edu-org', entry.institution)}${field('edu-year', entry.dates)}
`);
}
}
if (template.includes('{{AWARDS}}')) {
for (const entry of entries(payload, 'awards')) records.push(field('award-title', entry.title));
}
return records.join('\n');
}