#${placement}
`, `\t\t\t\t\t${escapeHtml(rankedMeal.title)}
`, `\t\t\t\t\t\t`, `\t\t\t\t\t\t${escapeHtml(rankedMeal.description)}
`, "\t\t\t\t\tconst fs = require("fs");
const path = require("path");
const { getRankedMeals, syncEloWithMeals } = require("./lib/elo");
const { loadMeals, repoRoot } = require("./lib/meals");
const indexTemplatePath = path.join(repoRoot, "templates", "index.html");
const indexOutputPath = path.join(repoRoot, "index.html");
const rankingsTemplatePath = path.join(repoRoot, "templates", "rankings.html");
const rankingsOutputPath = path.join(repoRoot, "rankings.html");
const ratingFormatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
});
function detectEol(text) {
return text.includes("\r\n") ? "\r\n" : "\n";
}
function escapeHtml(value) {
return String(value)
.replace(/&/g, "&")
.replace(/>/g, ">")
.replace(/",
`\t\t\t\t\t
`,
`\t\t\t\t\t
${escapeHtml(meal.description)}
`, "\t\t\t\t", ].join(eol); } function renderGallery(meals, eol) { return meals.map((meal) => renderGalleryItem(meal, eol)).join(eol); } function formatRating(rating) { return ratingFormatter.format(rating); } function renderRankingSummary(meals, eloData) { const mealLabel = meals.length === 1 ? "meal" : "meals"; return `\t\t\t\t${meals.length} ${mealLabel} seeded at Elo ${formatRating( eloData.defaultRating )} until head-to-head voting starts.
`; } function renderRankingMeta(rankedMeal) { const ratingText = `Elo ${formatRating(rankedMeal.rating)}`; if (rankedMeal.matches === 0) { return `${ratingText} | no votes yet`; } const matchLabel = rankedMeal.matches === 1 ? "match" : "matches"; return `${ratingText} | ${rankedMeal.wins}-${rankedMeal.losses} record across ${ rankedMeal.matches } ${matchLabel}`; } function renderRankingItem(rankedMeal, placement, eol) { return [ '\t\t\t\t#${placement}
`, `\t\t\t\t\t${escapeHtml(rankedMeal.description)}
`, "\t\t\t\t\t