Repair reuse of templater at different constant-portions

This commit is contained in:
Tony Garnock-Jones 2024-06-19 09:36:31 +02:00
parent 600d9b3c15
commit 7e439b9bb1
2 changed files with 30 additions and 6 deletions

View File

@ -308,17 +308,17 @@ export type HtmlTemplater =
=> ChildNode[];
export function template(): HtmlTemplater {
let instance: HtmlFragmentInstance | null = null;
let cache: null | { instance: HtmlFragmentInstance, builder: HtmlFragmentBuilder } = null;
return (constantParts, ... variableParts) => {
let b = templateCache.get(constantParts);
if (b === void 0) {
b = new HtmlFragmentBuilder(constantParts);
templateCache.set(constantParts, b);
}
if (instance === null) {
instance = b.clone();
if (cache === null || cache.builder !== b) {
cache = { instance: b.clone(), builder: b };
}
b.update(instance, variableParts);
return instance.container;
b.update(cache.instance, variableParts);
return cache.instance.container;
};
}

View File

@ -1,7 +1,7 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { template } from '../src/html';
import { HtmlTemplater, template } from '../src/html';
import './test-utils';
function compareHTML(nodes: ChildNode[], expected: string) {
@ -89,6 +89,18 @@ describe('basic templating', () => {
compareHTML(t`<q><x t="${v()}">${ps.map(p => p())}</x></q>`, expected);
});
it('should be callable multiple times with the same syntactic location', () => {
// Because the fixed portion of a template string, the TemplateStringsArray, is hashconsed
const v = () => 'aaa';
const ps = [() => '123', () => '234', () => '345'];
const expected = '<q><x t="aaa">123234345</x></q>';
const t = template();
const f = () => compareHTML(t`<q><x t="${v()}">${ps.map(p => p())}</x></q>`, expected);
f();
f();
f();
});
it('should be callable multiple times with extra items', () => {
const v = () => 'aaa';
const t = template();
@ -99,4 +111,16 @@ describe('basic templating', () => {
ps.push(() => '3');
compareHTML(t`<q><x t="${v()}">${ps.map(p => p())}</x></q>`, '<q><x t="aaa">123</x></q>');
});
it('should be reusable for supplying arguments to itself', () => {
const inner = (t: HtmlTemplater) => t`<i>middle</i>`;
const t = template();
compareHTML(t`<p>n${inner(t)}n</p>`, '<p>n<i>middle</i>n</p>');
});
it('should accept strings', () => {
const inner = (_t: HtmlTemplater) => `<i>middle</i>`;
const t = template();
compareHTML(t`<p>n${inner(t)}n</p>`, '<p>n&lt;i&gt;middle&lt;/i&gt;n</p>');
});
});