lighterhtml
Version:
The hyperHTML strength & experience without its complexity
134 lines (120 loc) • 3.58 kB
JavaScript
;
const WeakMap = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/weakmap'));
const domsanitizer = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('domsanitizer'));
const {isArray} = require('uarray');
const umap = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('umap'));
const {persistent} = require('uwire');
const {Tagger} = require('./tagger.js');
const {create, freeze, keys} = Object;
const tProto = Tagger.prototype;
const cache = umap(new WeakMap);
const createRender = Tagger => ({
html: outer('html', Tagger),
svg: outer('svg', Tagger),
render(where, what) {
const hole = typeof what === 'function' ? what() : what;
const info = cache.get(where) || cache.set(where, createCache());
const wire = hole instanceof LighterHole ?
unroll(Tagger, info, hole) : hole;
if (wire !== info.wire) {
info.wire = wire;
where.textContent = '';
where.appendChild(wire.valueOf());
}
return where;
}
});
const createCache = () => ({stack: [], entry: null, wire: null});
const outer = (type, Tagger) => {
const cache = umap(new WeakMap);
const fixed = info => function () {
return unroll(Tagger, info, hole.apply(null, arguments));
};
hole.for = (ref, id) => {
const memo = cache.get(ref) || cache.set(ref, create(null));
return memo[id] || (memo[id] = fixed(createCache()));
};
hole.node = function () {
return unroll(
Tagger,
createCache(),
hole.apply(null, arguments)
).valueOf();
};
return hole;
function hole() {
return new LighterHole(type, tta.apply(null, arguments));
}
};
const unroll = (Tagger, info, {type, template, values}) => {
const {length} = values;
unrollValues(Tagger, info, values, length);
let {entry} = info;
if (!entry || (entry.template !== template || entry.type !== type)) {
const tag = new Tagger(type);
info.entry = (entry = {
type,
template,
tag,
wire: persistent(tag(template, ...values))
});
}
else
entry.tag(template, ...values);
return entry.wire;
};
const unrollValues = (Tagger, {stack}, values, length) => {
for (let i = 0; i < length; i++) {
const hole = values[i];
if (hole instanceof Hole)
values[i] = unroll(
Tagger,
stack[i] || (stack[i] = createCache()),
hole
);
else if (isArray(hole))
unrollValues(
Tagger,
stack[i] || (stack[i] = createCache()),
hole,
hole.length
);
else
stack[i] = null;
}
if (length < stack.length)
stack.splice(length);
};
freeze(LighterHole);
function LighterHole(type, args) {
this.type = type;
this.template = args.shift();
this.values = args;
};
const Hole = LighterHole;
exports.Hole = Hole;
const custom = overrides => {
const prototype = create(tProto);
keys(overrides).forEach(key => {
prototype[key] = overrides[key](
prototype[key] ||
(key === 'convert' ? domsanitizer : String)
);
});
CustomTagger.prototype = prototype;
return createRender(CustomTagger);
function CustomTagger() {
return Tagger.apply(this, arguments);
}
};
exports.custom = custom;
const {render, html, svg} = createRender(Tagger);
exports.render = render;
exports.html = html;
exports.svg = svg;
function tta() {
let out = [], i = 0, {length} = arguments;
while (i < length)
out.push(arguments[i++]);
return out;
}