Skip to content

Commit 950a653

Browse files
committed
Pre-generated cache
1 parent c72665c commit 950a653

8 files changed

Lines changed: 46 additions & 61 deletions

File tree

esm/creator.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { PersistentFragment } from './persistent-fragment.js';
2-
import { detail, parsed } from './literals.js';
2+
import { detail } from './literals.js';
3+
import { array, hole } from './handler.js';
34
import { empty } from './utils.js';
5+
import { cache } from './literals.js';
46

57
/**
68
* @param {DocumentFragment} content
@@ -12,19 +14,26 @@ const childNodesIndex = (node, i) => node.childNodes[i];
1214

1315
/** @param {(template: TemplateStringsArray, values: any[]) => import("./parser.js").Resolved} parse */
1416
export default parse => (
15-
/** @param {(template: TemplateStringsArray, values: any[]) => import("./literals.js").Parsed} parse */
17+
/** @param {(template: TemplateStringsArray, values: any[]) => import("./literals.js").Cache} parse */
1618
(template, values) => {
1719
const { f: fragment, e: entries, d: direct } = parse(template, values);
1820
const root = fragment.cloneNode(true);
19-
let current, prev, details = entries === empty ? empty : [];
20-
for (let i = 0; i < entries.length; i++) {
21-
const { p: path, u: update, n: name } = entries[i];
22-
const node = path === prev ? current : (current = find(root, (prev = path)));
23-
details[i] = detail(empty, update, node, name);
21+
let details = empty, stack = empty;
22+
if (entries !== empty) {
23+
details = [];
24+
stack = [];
25+
for (let current, prev, i = 0; i < entries.length; i++) {
26+
const { p: path, u: update, n: name } = entries[i];
27+
const node = path === prev ? current : (current = find(root, (prev = path)));
28+
details[i] = detail(empty, update, node, name);
29+
stack[i] = update === array ? cache([]) : (update === hole ? cache(empty) : null);
30+
}
2431
}
25-
return parsed(
26-
direct ? root.firstChild : new PersistentFragment(root),
27-
details
28-
);
32+
return {
33+
t: template,
34+
n: direct ? root.firstChild : new PersistentFragment(root),
35+
d: details,
36+
s: stack,
37+
};
2938
}
3039
);

esm/keyed.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*! (c) Andrea Giammarchi - MIT */
2-
import { Hole, unroll } from './rabbit.js';
2+
import { Hole } from './rabbit.js';
33
import { attr } from './handler.js';
44
import { cache } from './literals.js';
55
import { empty, set } from './utils.js';
@@ -24,7 +24,7 @@ const keyed = new WeakMap;
2424
const createRef = svg => /** @type {Bound} */ (ref, key) => {
2525
/** @type {Tag} */
2626
function tag(template, ...values) {
27-
return unroll(this, new Hole(svg, template, values));
27+
return new Hole(svg, template, values).toDOM(this);
2828
}
2929

3030
const memo = keyed.get(ref) || set(keyed, ref, new Map);

esm/literals.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,20 @@ export const entry = (p, u, n) => ({ p, u, n });
4949

5050
/**
5151
* @typedef {Object} Cache
52-
* @property {Cache[]} s the stack of caches per each interpolation / hole
5352
* @property {null | TemplateStringsArray} t the cached template
5453
* @property {null | Node | PersistentFragment} n the node returned when parsing the template
5554
* @property {Detail[]} d the list of updates to perform
55+
* @property {Cache[]} s the stack of caches per each interpolation / hole
5656
*/
5757

5858
/**
5959
* @param {Cache[]} s the cache stack
6060
* @returns {Cache}
6161
*/
62-
export const cache = s => ({ s, t: null, n: null, d: empty});
62+
export const cache = s => ({ t: null, n: null, d: empty, s });
6363

6464
/**
6565
* @typedef {Object} Parsed
6666
* @property {Node | PersistentFragment} n the returned node after parsing the template
6767
* @property {Detail[]} d the list of details to update the node
6868
*/
69-
70-
/**
71-
* @param {Node | PersistentFragment} n the returned node after parsing the template
72-
* @param {Detail[]} d the list of details to update the node
73-
* @returns {Parsed}
74-
*/
75-
export const parsed = (n, d) => ({ n, d });

esm/node.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
/*! (c) Andrea Giammarchi - MIT */
2-
import { Hole, unroll } from './rabbit.js';
2+
import { Hole } from './rabbit.js';
33
import { attr } from './handler.js';
4-
import { cache } from './literals.js';
5-
import { empty } from './utils.js';
64

75
/** @typedef {import("./literals.js").DOMValue} DOMValue */
86
/** @typedef {import("./literals.js").Target} Target */
97

10-
const tag = svg => (template, ...values) => unroll(
11-
cache(empty),
12-
new Hole(svg, template, values)
13-
);
8+
const tag = svg => (template, ...values) => new Hole(svg, template, values).toDOM();
149

1510
/** @type {(template: TemplateStringsArray, ...values:DOMValue[]) => Target} A tag to render HTML content. */
1611
const html = tag(false);

esm/parser.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ import createContent from './create-content.js';
1212

1313
/**
1414
* @typedef {Object} Resolved
15-
* @property {DocumentFragment} content
16-
* @property {Entry[]} entries
17-
* @property {function[]} updates
18-
* @property {number} length
15+
* @param {DocumentFragment} f content retrieved from the template
16+
* @param {Entry[]} e entries per each hole in the template
17+
* @param {boolean} d direct node to handle
1918
*/
2019

2120
/**

esm/rabbit.js

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,38 @@
1-
import { array, hole, text } from './handler.js';
1+
import { array, hole } from './handler.js';
22
import { cache as newCache } from './literals.js';
33
import { empty } from './utils.js';
44
import create from './creator.js';
55
import parser from './parser.js';
66

7+
const { assign } = Object;
8+
79
const parseHTML = create(parser(false));
810
const parseSVG = create(parser(true));
911

10-
const createCache = ({ u }) => (
11-
u === array ?
12-
newCache([]) : (
13-
u === hole ?
14-
newCache(empty) :
15-
null
16-
)
17-
);
18-
1912
/**
2013
* @param {import("./literals.js").Cache} cache
2114
* @param {Hole} hole
2215
* @returns {Node}
2316
*/
24-
export const unroll = (cache, { s, t, v }) => {
25-
let i = 0, { d: details, s: stack } = cache;
26-
if (cache.t !== t) {
27-
const { n, d } = (s ? parseSVG : parseHTML)(t, v);
28-
cache.t = t;
29-
cache.n = n;
30-
cache.d = (details = d);
31-
if (v.length) cache.s = (stack = d.map(createCache));
32-
}
33-
for (; i < details.length; i++) {
17+
const unroll = (cache, { s, t, v }) => {
18+
if (cache.t !== t)
19+
assign(cache, (s ? parseSVG : parseHTML)(t, v));
20+
for (let { d, s } = cache, i = 0; i < d.length; i++) {
3421
const value = v[i];
35-
const detail = details[i];
22+
const detail = d[i];
3623
const { v: previous, u: update, t: target, n: name } = detail;
3724
switch (update) {
3825
case array:
3926
detail.v = array(
4027
target,
41-
unrollValues(stack[i], value),
28+
unrollValues(s[i], value),
4229
previous
4330
);
4431
break;
4532
case hole:
4633
const current = value instanceof Hole ?
47-
unroll(stack[i], value) :
48-
value
34+
unroll(s[i] || (s[i] = newCache(empty)), value) :
35+
(s[i] = null, value)
4936
;
5037
if (current !== previous)
5138
detail.v = hole.call(detail, target, current);
@@ -89,4 +76,7 @@ export class Hole {
8976
this.t = template;
9077
this.v = values;
9178
}
79+
toDOM(cache = newCache(empty)) {
80+
return unroll(cache, this);
81+
}
9282
};

esm/render/hole.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { unroll } from '../rabbit.js';
21
import { cache } from '../literals.js';
32
import { empty, set } from '../utils.js';
43

@@ -16,7 +15,7 @@ const known = new WeakMap;
1615
*/
1716
export default (where, what) => {
1817
const info = known.get(where) || set(known, where, cache(empty));
19-
if (info.n !== unroll(info, typeof what === 'function' ? what() : what))
18+
if (info.n !== (typeof what === 'function' ? what() : what).toDOM(info))
2019
where.replaceChildren(info.n.valueOf());
2120
return where;
2221
};

esm/render/shared.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Hole, unroll } from '../rabbit.js';
1+
import { Hole } from '../rabbit.js';
22
import { cache } from '../literals.js';
33
import { empty, set } from '../utils.js';
44

@@ -16,7 +16,7 @@ export default (where, what, check) => {
1616
const info = known.get(where) || set(known, where, cache(empty));
1717
const hole = (check && typeof what === 'function') ? what() : what;
1818
const { n } = info;
19-
const node = hole instanceof Hole ? unroll(info, hole) : hole;
19+
const node = hole instanceof Hole ? hole.toDOM(info) : hole;
2020
if (n !== node)
2121
where.replaceChildren((info.n = node).valueOf());
2222
return where;

0 commit comments

Comments
 (0)