sclass SmoothHTMLTemplater {
// input
S template;
bool verbose;
Map> entriesByType = ciMap();
// internal
LS tok;
L commentRanges;
LS comments;
*() {}
*(S *template) {}
srecord Replacement(S exampleValue, S actualValue) {
S replaceIn(S text) {
ret replaceIC(text, exampleValue, actualValue);
}
}
L mapToEntry(MapSO map) {
ret map(map, (key, value) -> new Replacement(key, str(value)));
}
S render() {
tok = htmlTok(template);
commentRanges = charRangesOfHTMLComments(template);
comments = map(commentRanges, r -> htmlCommentContents(substring(template, r)));
new Matches m;
new LPair replacements;
for i over comments: {
S comment = comments.get(i);
if (match("start * block", comment, m)) {
S type = $1;
S endPat = format3("end * block", type);
if (verbose) print("Start of block found: " + i + " / " + comment);
int j = indexOfMatches(endPat, comments, i+1);
int jEndOfList = indexOfMatches(format3("end * list", type), comments, i+1);
if (j < 0) continue with warn("End of block comment not found: " + endPat);
if (verbose) print("End of block found: " + j + " / " + comments.get(j));
if (!isEntity(type)) continue with print("Not an entity: " + type);
LL entries = getEntries(type);
if (verbose) print(nEntries(entries));
IntRange r1 = commentRanges.get(i), r2 = commentRanges.get(j);
IntRange rEndOfList = commentRanges.get(jEndOfList >= 0 ? jEndOfList : j);
S contents = substring(template, r1.end, r2.start);
addPair(replacements, intRange(r1.end, rEndOfList.start),
lines(map(entries, entry -> rewriteEntry(contents, entry))));
i = j;
}
}
if (verbose) pnlStruct("Replacement", replacements);
ret replaceCharRanges(template, replacements);
}
bool isEntity(S type) { true; }
// TODO: avoid multi-replacements
S rewriteEntry(S text, L entry) {
fOr (Replacement r : entry)
text = r.replaceIn(text);
ret text;
}
LL getEntries(S type) {
ret entriesByType.get(type);
}
}