Somewhat-typed templating for fragments of HTML/SVG/etc

This commit is contained in:
Tony Garnock-Jones 2022-01-24 09:10:43 +01:00
parent 431a7f49b0
commit c5f69295a2
1 changed files with 27 additions and 4 deletions

View File

@ -131,12 +131,25 @@ export function join(pieces: Array<HtmlFragment>, separator: HtmlFragment): Arra
}
}
export function makeTemplate(contextElementName?: string)
: (constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => HtmlFragments {
return (constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => {
export type HtmlFragmentsTemplate =
(constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => HtmlFragments;
export type NodeTemplate<N extends ChildNode> =
(constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => N;
export interface TagTemplate {
tag(): NodeTemplate<Element>;
tag<N extends ChildNode>(c: { new (...args: any): N }): NodeTemplate<N>;
};
export function makeTemplate(
contextElementName?: string,
): HtmlFragmentsTemplate & TagTemplate {
const templater = (constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => {
const pieces: Array<HtmlFragment> = [];
function pushConst(i: number) {
const r = constantParts.raw[i].trimLeft();
const r0 = constantParts.raw[i];
const r = i === 0 ? r0.trimLeft() : r0;
if (r) pieces.push(r);
}
pushConst(0);
@ -146,6 +159,16 @@ export function makeTemplate(contextElementName?: string)
});
return new HtmlFragments(pieces, contextElementName);
};
templater.tag = <N extends ChildNode>(c?: { new (...args: any): N }) =>
(constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>): any => {
const n = templater(constantParts, ... variableParts).node();
if (n instanceof (c ?? Element)) {
return n;
} else {
throw new TypeError(`Template generated ${n}, but instance of ${c} was expected`);
}
};
return templater;
}
export const template = makeTemplate();