pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/WebReflection/uhtml/pull/113.diff

*/ -const cache = new WeakMap; -const prefix = 'isµ'; - /** * @param {boolean} xml + * @param {boolean} holed * @returns {(template: TemplateStringsArray, values: any[]) => Resolved} */ -export default xml => (template, values) => cache.get(template) || resolve(template, values, xml); +export const parse = (xml, holed) => { + /** @type {WeakMap} */ + const cache = new WeakMap; + return (template, values) => ( + cache.get(template) || + set(cache, template, resolve(template, values, xml, holed)) + ); +}; diff --git a/esm/rabbit.js b/esm/rabbit.js index 686afdb..4cae51d 100644 --- a/esm/rabbit.js +++ b/esm/rabbit.js @@ -1,10 +1,10 @@ import { array, hole } from './handler.js'; import { cache } from './literals.js'; +import { parse } from './parser.js'; import create from './creator.js'; -import parser from './parser.js'; -const createHTML = create(parser(false)); -const createSVG = create(parser(true)); +const createHTML = create(parse(false, false)); +const createSVG = create(parse(true, false)); /** * @param {import("./literals.js").Cache} info diff --git a/package-lock.json b/package-lock.json index 54a2a27..5df5924 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uhtml", - "version": "4.5.0", + "version": "4.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "uhtml", - "version": "4.5.0", + "version": "4.6.0", "license": "MIT", "dependencies": { "@preact/signals-core": "1.6.0", diff --git a/package.json b/package.json index 1751b97..f567ddd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uhtml", - "version": "4.5.0", + "version": "4.6.0", "description": "A micro HTML/SVG render", "main": "./cjs/index.js", "scripts": { diff --git a/rollup/es.config.js b/rollup/es.config.js index fce0e38..1522029 100644 --- a/rollup/es.config.js +++ b/rollup/es.config.js @@ -28,6 +28,14 @@ export default [ name: 'uhtml', }, }, + { + plugins, + input: './esm/hydro.js', + output: { + esModule: true, + file: './hydro.js', + }, + }, { plugins, input: './esm/index.js', diff --git a/rollup/ssr.cjs b/rollup/ssr.cjs index 5795b7b..35b1b3a 100644 --- a/rollup/ssr.cjs +++ b/rollup/ssr.cjs @@ -8,6 +8,7 @@ const uhtml = readFileSync(init).toString(); const content = [ 'const document = content ? new DOMParser().parseFromString(content, ...rest) : new Document;', 'const { constructor: DocumentFragment } = document.createDocumentFragment();', + 'document[__chunks__] = true;', ]; writeFileSync(init + '_', ` @@ -15,6 +16,7 @@ writeFileSync(init + '_', ` import Document from './dom/document.js'; import DOMParser from './dom/dom-parser.js'; +import { __chunks__ } from './dom/symbols.js'; import { value } from './dom/symbols.js'; import Comment from './dom/comment.js'; diff --git a/test/hydro.html b/test/hydro.html new file mode 100644 index 0000000..faf5cbc --- /dev/null +++ b/test/hydro.html @@ -0,0 +1,50 @@ + + + + Hello Hydro + +

Hello Hydro

+
+ + + +
+ + + diff --git a/test/hydro.mjs b/test/hydro.mjs new file mode 100644 index 0000000..4a5dcce --- /dev/null +++ b/test/hydro.mjs @@ -0,0 +1,59 @@ +import init from '../esm/init-ssr.js'; + +function App(state) { + return html` +

${state.title}

+
+ + + +
+ `; +} + +const component = (target, Callback) => { + const effect = { + target, + update(...args) { + render(target, Callback.apply(effect, args)); + } + }; + return Callback.bind(effect); +}; + +const state = { title: 'Hello Hydro', count: 0 }; + +const { document, render, html } = init(` + + + + + + ${state.title} + + + +`); + +const { body } = document; + +const Body = component(body, App); + +render(body, Body(state)); + +console.log(document.toString()); diff --git a/test/parser.mjs b/test/parser.mjs new file mode 100644 index 0000000..0a36fab --- /dev/null +++ b/test/parser.mjs @@ -0,0 +1,11 @@ +import parser from '@webreflection/uparser'; + +const prefix = 'isµ'; +const re = new RegExp(``, 'g'); + +const template = t => t; + +console.log( + parser(template`a${1}b`, prefix, false) + .replace(re, '$&') +); diff --git a/test/virtual.mjs b/test/virtual.mjs new file mode 100644 index 0000000..1c048fb --- /dev/null +++ b/test/virtual.mjs @@ -0,0 +1,118 @@ +const ELEMENT_NODE = 1; +const TEXT_NODE = 3; +const COMMENT_NODE = 8; + +const mapped = new WeakMap; + +const asArray = data => /^\[(\d+)\]$/.test(data) ? +RegExp.$1 : -1; + +const faker = ({ tagName }) => ({ tagName, childNodes: [] }); + +const skipArray = (node, many) => { + return many; +}; + +// in a hole there could be: +// * a fragment +// * a hole +// * an element +// * a dom node +const skipHole = (fake, node) => { + let first = true, level = 0; + fake.unshift(node); + while ((node = node.previousSibling)) { + if (node.nodeType === COMMENT_NODE) { + const { data } = node; + if (data === '{') { + if (!level--) { + fake.unshift(node); + return; + } + } + else if (data === '}') { + if (!level++ && first) { + // hole in a hole + } + } + else if (first && data === '') { + // fragment in hole + } + } + // element or text in hole + else if (first) fake.unshift(node); + first = false; + } +}; + +const virtual = (parent, asFragment) => { + let ref = mapped.get(parent); + if (!ref) { + mapped.set(parent, (ref = faker(parent))); + const { childNodes: fake } = ref; + const { childNodes: live } = parent; + for (let { length } = live; length--;) { + let node = live[length]; + switch (node.nodeType) { + case ELEMENT_NODE: + fake.unshift(virtual(node, false)); + break; + case COMMENT_NODE: { + const { data } = node; + if (data === '}') { + skipHole(fake, node); + length -= 2; + } + else if (data === '') { + + } + else { + fake.unshift(node); + const many = asArray(data); + if (-1 < many) + length -= skipArray(node, many); + } + break; + } + case TEXT_NODE: + if (asFragment && !node.data.trim()) break; + fake.unshift(node); + } + asFragment = false; + } + } + return ref; +}; + + +import init from '../esm/init-ssr.js'; + +const { document, render, html } = init(); + +const reveal = ({ tagName, childNodes }, level = 0) => { + const out = []; + out.push('\n', ' '.repeat(level), `<${tagName}>`); + for (let i = 0; i < childNodes.length; i++) { + const node = childNodes[i]; + switch (node.nodeType) { + case COMMENT_NODE: + if (!i) out.push('\n', ' '.repeat(level + 1)); + out.push(``); + break; + case TEXT_NODE: + if (!i) out.push('\n', ' '.repeat(level + 1)); + out.push(node.data); + break; + default: + out.push(reveal(node, level + 1)); + break; + } + } + out.push('\n', ' '.repeat(level), ``); + return out.join(''); +}; + +render(document.body, html`
a${[html`b`]}c${[html`d`, html`e`]}f
`); +console.log(document.body.toString()); + +console.debug(virtual(document.body, false).childNodes[0]); +console.log(reveal(virtual(document.body, false))); pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy