Skip to content

Commit

Permalink
Merge pull request #140 from jviide/staticness-bits
Browse files Browse the repository at this point in the history
Add helpers for tracking subtree staticness inside `h` functions
  • Loading branch information
jviide authored Jan 21, 2020
2 parents 1ec0588 + 6b17de9 commit edab3dc
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 9 deletions.
18 changes: 9 additions & 9 deletions src/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ export const evaluate = (h, built, fields, args) => {
for (let i = 1; i < built.length; i++) {
const type = built[i++];

// Set `built[0]` to truthy if this element depends on a dynamic value.
const value = built[i] ? fields[built[0] = built[i++]] : built[++i];
// Set `built[0]`'s appropriate bits if this element depends on a dynamic value.
const value = built[i] ? ((built[0] |= type ? 1 : 2), fields[built[i++]]) : built[++i];

if (type === TAG_SET) {
args[0] = value;
Expand All @@ -97,14 +97,15 @@ export const evaluate = (h, built, fields, args) => {
else if (type === PROP_APPEND) {
args[1][built[++i]] += (value + '');
}
else if (type) {
// type === CHILD_RECURSE
tmp = h.apply(0, evaluate(h, value, fields, ['', null]));
else if (type) { // type === CHILD_RECURSE
// Set the operation list (including the staticness bits) as
// `this` for the `h` call.
tmp = h.apply(value, evaluate(h, value, fields, ['', null]));
args.push(tmp);

if (value[0]) {
// If the child element is dynamic, then so is the current element.
built[0] = 1;
// Set the 2nd lowest bit it the child element is dynamic.
built[0] |= 2;
}
else {
// Rewrite the operation list in-place if the child element is static.
Expand All @@ -116,8 +117,7 @@ export const evaluate = (h, built, fields, args) => {
built[i] = tmp;
}
}
else {
// type === CHILD_APPEND
else { // type === CHILD_APPEND
args.push(value);
}
}
Expand Down
53 changes: 53 additions & 0 deletions test/statics-caching.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,57 @@ describe('htm', () => {
expect(a).toBe(1);
expect(b).toBe(2);
});

describe('`this` in the h function', () => {
const html = htm.bind(function() {
return this;
});

test('stays the same for each call site)', () => {
const x = () => html`<div>a</div>`;
const a = x();
const b = x();
expect(a).toBe(b);
});

test('is different for each call site', () => {
const a = html`<div>a</div>`;
const b = html`<div>a</div>`;
expect(a).not.toBe(b);
});

test('is specific to each h function', () => {
let tmp = htm.bind(function() { return this; });
const x = () => tmp`<div>a</div>`;
const a = x();
tmp = htm.bind(function() { return this; });
const b = x();
expect(a).not.toBe(b);
});
});

describe('`this[0]` in the h function contains the staticness bits', () => {
const html = htm.bind(function() {
return this[0];
});

test('should be 0 for static subtrees', () => {
expect(html`<div></div>`).toBe(0);
expect(html`<div>a</div>`).toBe(0);
expect(html`<div><a /></div>`).toBe(0);
});

test('should be 2 for static nodes with some dynamic children', () => {
expect(html`<div>${'a'}<b /></div>`).toBe(2);
expect(html`<div><a y=${2} /><b /></div>`).toBe(2);
});

test('should be 1 for dynamic nodes with all static children', () => {
expect(html`<div x=${1}><a /><b /></div>`).toBe(1);
});

test('should be 3 for dynamic nodes with some dynamic children', () => {
expect(html`<div x=${1}><a y=${2} /><b /></div>`).toBe(3);
});
});
});

0 comments on commit edab3dc

Please sign in to comment.