applyInheritance function
Folds any extend
declarations.
Implementation
Future<Document?> applyInheritance(
Document? document,
Directory currentDirectory,
void Function(JaelError error)? onError,
Iterable<Patcher>? patch) async {
if (document == null) {
return null;
}
if (document.root.tagName.name != 'extend') {
// This is not an inherited template, so just fill in the existing blocks.
var root =
replaceChildrenOfElement(document.root, {}, onError, true, false);
return Document(document.doctype, root);
}
var element = document.root;
var attr = element.attributes.firstWhereOrNull((a) => a.name == 'src');
if (attr == null) {
onError!(JaelError(JaelErrorSeverity.warning,
'Missing "src" attribute in "extend" tag.', element.tagName.span));
return null;
} else if (attr.value is! StringLiteral) {
onError!(JaelError(
JaelErrorSeverity.warning,
'The "src" attribute in an "extend" tag must be a string literal.',
element.tagName.span));
return null;
} else {
// In theory, there exists:
// * A single root template with a number of blocks
// * Some amount of <extend src="..."> templates.
// To produce an accurate representation, we need to:
// 1. Find the root template, and store a copy in a variable.
// 2: For each <extend> template:
// a. Enumerate the block overrides it defines
// b. Replace matching blocks in the current document
// c. If there is no block, and this is the LAST <extend>, fill in the default block content.
var hierarchy = await resolveHierarchy(document, currentDirectory, onError);
var out = hierarchy?.root;
if (out is! RegularElement) {
return hierarchy!.rootDocument;
}
Element setOut(Element out, Map<String?, RegularElement> definedOverrides,
bool anyTemplatesRemain) {
var children = <ElementChild>[];
// Replace matching blocks, etc.
for (var c in out.children) {
if (c is Element) {
children.addAll(replaceBlocks(
c, definedOverrides, onError, false, anyTemplatesRemain));
} else {
children.add(c);
}
}
var root = hierarchy!.root as RegularElement;
return RegularElement(root.lt, root.tagName, root.attributes, root.gt,
children, root.lt2, root.slash, root.tagName2, root.gt2);
}
// Loop through all extends, filling in blocks.
while (hierarchy!.extendsTemplates.isNotEmpty) {
var tmpl = hierarchy.extendsTemplates.removeFirst();
var definedOverrides = findBlockOverrides(tmpl, onError);
//if (definedOverrides == null) break;
out =
setOut(out!, definedOverrides, hierarchy.extendsTemplates.isNotEmpty);
}
// Lastly, just default-fill any remaining blocks.
var definedOverrides = findBlockOverrides(out!, onError);
out = setOut(out, definedOverrides, false);
// Return our processed document.
return Document(document.doctype, out);
}
}