Skip to content

Commit 27ab0bd

Browse files
committed
hard to optimize more here ... but it looks good
1 parent 4d4a46e commit 27ab0bd

5 files changed

Lines changed: 37 additions & 42 deletions

File tree

esm/creator.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { PersistentFragment } from './persistent-fragment.js';
2-
import { abc, detail } from './literals.js';
2+
import { bc, detail } from './literals.js';
33
import { array, hole } from './handler.js';
44
import { empty } from './utils.js';
55
import { cache } from './literals.js';
@@ -14,10 +14,15 @@ const childNodesIndex = (node, i) => node.childNodes[i];
1414

1515
/** @param {(template: TemplateStringsArray, values: any[]) => import("./parser.js").Resolved} parse */
1616
export default parse => (
17-
/** @param {(template: TemplateStringsArray, values: any[]) => import("./literals.js").Cache} parse */
17+
/**
18+
* @param {TemplateStringsArray} template
19+
* @param {any[]} values
20+
* @returns {import("./literals.js").Cache}
21+
*/
1822
(template, values) => {
1923
const { a: fragment, b: entries, c: direct } = parse(template, values);
2024
const root = fragment.cloneNode(true);
25+
/** @type {import("./literals.js").Detail[]} */
2126
let details = empty;
2227
if (entries !== empty) {
2328
details = [];
@@ -32,8 +37,7 @@ export default parse => (
3237
);
3338
}
3439
}
35-
return abc(
36-
template,
40+
return bc(
3741
direct ? root.firstChild : new PersistentFragment(root),
3842
details,
3943
);

esm/handler.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,25 +56,25 @@ const holes = new WeakMap;
5656

5757
/**
5858
* @template T
59-
* @this {import("./literals.js").Detail}
60-
* @param {Node} node
59+
* @param {import("./literals.js").Detail} detail
6160
* @param {T} value
6261
* @returns {T}
6362
*/
64-
export function hole(node, value) {
65-
let { n: hole } = this, nullish = false;
63+
export const hole = (detail, value) => {
64+
const { t: node, n: hole } = detail;
65+
let nullish = false;
6666
switch (typeof value) {
6767
case 'object':
6868
if (value !== null) {
69-
(hole || node).replaceWith((this.n = value.valueOf()));
69+
(hole || node).replaceWith((detail.n = value.valueOf()));
7070
break;
7171
}
7272
case 'undefined':
7373
nullish = true;
7474
default:
7575
node.data = nullish ? '' : value;
7676
if (hole) {
77-
this.n = null;
77+
detail.n = null;
7878
hole.replaceWith(node);
7979
}
8080
break;

esm/literals.js

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,22 @@ import { empty } from './utils.js';
66
/** @typedef {unknown} Value */
77
/** @typedef {Node | Element | PersistentFragment} Target */
88
/** @typedef {null | undefined | string | number | boolean | Node | Element | PersistentFragment} DOMValue */
9+
/** @typedef {Hole | Node} ArrayValue */
910

1011
export const abc = (a, b, c) => ({ a, b, c });
1112

13+
export const bc = (b, c) => ({ b, c });
14+
1215
/**
1316
* @typedef {Object} Detail
1417
* @property {any} v the current value of the interpolation / hole
1518
* @property {function} u the callback to update the value
1619
* @property {Node} t the target comment node or element
17-
* @property {string | null} n the attribute name, if any, or `null`
18-
* @param {Cache | Hole[] | Node[] | null} c the cache value for this detail
20+
* @property {string | null | Node} n the attribute name, if any, or `null`
21+
* @property {Cache | ArrayValue[] | null} c the cache value for this detail
1922
*/
2023

2124
/**
22-
* @param {function} u the callback to update the value
23-
* @param {Node} t the target comment node or element
24-
* @param {string | null} n the attribute name, if any, or `null`
25-
* @param {Cache | null} c the cache value for this detail
2625
* @returns {Detail}
2726
*/
2827
export const detail = (u, t, n, c) => ({ v: empty, u, t, n, c });
@@ -36,19 +35,12 @@ export const detail = (u, t, n, c) => ({ v: empty, u, t, n, c });
3635

3736
/**
3837
* @typedef {Object} Cache
39-
* @property {null | TemplateStringsArray} t the cached template
40-
* @property {null | Node | PersistentFragment} n the node returned when parsing the template
41-
* @property {Detail[]} d the list of updates to perform
42-
* @property {Cache[]} s the stack of caches per each interpolation / hole
38+
* @property {null | TemplateStringsArray} a the cached template
39+
* @property {null | Node | PersistentFragment} b the node returned when parsing the template
40+
* @property {Detail[]} c the list of updates to perform
4341
*/
4442

4543
/**
4644
* @returns {Cache}
4745
*/
4846
export const cache = () => abc(null, null, empty);
49-
50-
/**
51-
* @typedef {Object} Parsed
52-
* @property {Node | PersistentFragment} n the returned node after parsing the template
53-
* @property {Detail[]} d the list of details to update the node
54-
*/

esm/node.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { attr } from './handler.js';
55
/** @typedef {import("./literals.js").DOMValue} DOMValue */
66
/** @typedef {import("./literals.js").Target} Target */
77

8-
const tag = svg => (template, ...values) => new Hole(svg, template, values).toDOM();
8+
const tag = svg => (template, ...values) => new Hole(svg, template, values).toDOM().valueOf();
99

1010
/** @type {(template: TemplateStringsArray, ...values:DOMValue[]) => Target} A tag to render HTML content. */
1111
const html = tag(false);
@@ -21,9 +21,7 @@ const svg = tag(true);
2121
* @returns
2222
*/
2323
const render = (where, what) => {
24-
where.replaceChildren(
25-
(typeof what === 'function' ? what() : what).valueOf()
26-
);
24+
where.replaceChildren(typeof what === 'function' ? what() : what);
2725
return where;
2826
};
2927

esm/rabbit.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { cache } from './literals.js';
33
import create from './creator.js';
44
import parser from './parser.js';
55

6-
const { assign } = Object;
7-
86
const parseHTML = create(parser(false));
97
const parseSVG = create(parser(true));
108

@@ -14,31 +12,34 @@ const parseSVG = create(parser(true));
1412
* @returns {Node}
1513
*/
1614
const unroll = (info, { s, t, v }) => {
17-
if (info.a !== t)
18-
assign(info, (s ? parseSVG : parseHTML)(t, v));
15+
if (info.a !== t) {
16+
const { b, c } = (s ? parseSVG : parseHTML)(t, v);
17+
info.a = t;
18+
info.b = b;
19+
info.c = c;
20+
}
1921
for (let { c } = info, i = 0; i < c.length; i++) {
2022
const value = v[i];
2123
const detail = c[i];
22-
const { v: previous, u: update, t: target, n: name } = detail;
23-
switch (update) {
24+
switch (detail.u) {
2425
case array:
2526
detail.v = array(
26-
target,
27+
detail.t,
2728
unrollValues(detail.c, value),
28-
previous
29+
detail.v
2930
);
3031
break;
3132
case hole:
3233
const current = value instanceof Hole ?
3334
unroll(detail.c || (detail.c = cache()), value) :
3435
(detail.c = null, value)
3536
;
36-
if (current !== previous)
37-
detail.v = hole.call(detail, target, current);
37+
if (current !== detail.v)
38+
detail.v = hole(detail, current);
3839
break;
3940
default:
40-
if (value !== previous)
41-
detail.v = update(target, value, name, previous);
41+
if (value !== detail.v)
42+
detail.v = detail.u(detail.t, value, detail.n, detail.v);
4243
break;
4344
}
4445
}

0 commit comments

Comments
 (0)