hyper-html-api 0.6.5 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/hyper-html-api.engine.min.js +1 -1
- package/dist/hyper-html-api.min.js +4 -4
- package/dist/hyper-html-api.upgrade.min.js +2 -2
- package/package.json +4 -3
- package/packed-contract.json +1 -0
- package/src/adapters/cheerio.js +4 -0
- package/src/adapters/dom.js +191 -0
- package/src/dom-api.js +17 -6
- package/src/engine/apply.js +28 -4
- package/src/engine/diff.js +67 -54
- package/src/engine/extract.js +29 -3
- package/src/engine/index.js +1 -1
- package/src/engine/row-match.js +155 -0
- package/src/lib/content-dom.js +110 -0
- package/src/lib/region-capabilities.js +71 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var hyperHtmlApiUpgrade=(()=>{var X=Object.defineProperty;var Ne=Object.getOwnPropertyDescriptor;var _e=Object.getOwnPropertyNames;var Pe=Object.prototype.hasOwnProperty;var fe=(e,t)=>{for(var r in t)X(e,r,{get:t[r],enumerable:!0})},De=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of _e(t))!Pe.call(e,n)&&n!==r&&X(e,n,{get:()=>t[n],enumerable:!(o=Ne(t,n))||o.enumerable});return e};var Le=e=>De(X({},"__esModule",{value:!0}),e);var st={};fe(st,{default:()=>ot,engine:()=>ie,upgrade:()=>Ie});var q=["textContent","innerText","innerHTML","outerHTML","value","checked","selected","disabled","readOnly","type","tagName","nodeName","nodeType","nodeValue","childElementCount","id","className","classList","baseURI","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","dataset","currentSrc","duration","paused","title","documentURI","contentType"],Q=new Set(q),ae=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),pe=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var F={};fe(F,{EmptyListInsert:()=>j,MAX_RULE_DEPTH:()=>_,MaxRuleDepthExceeded:()=>w,RuleTargetReadOnly:()=>C,RulesParseError:()=>N,ShapeMismatch:()=>L,UnknownRulesVersion:()=>O});var N=class extends Error{constructor(t,r){super(t),this.name="RulesParseError",this.cause=r}},O=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},_=20,w=class extends Error{constructor(t){super(`rule depth exceeded ${_} at path: ${t.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=t}},L=class extends Error{constructor(t){super(`shape mismatch: ${t.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=t}},j=class extends Error{constructor(t){super(`cannot add items to empty list at "${t.join(".")}" \u2014 no sibling to clone as template. Seed the list with a hidden item first.`),this.name="EmptyListInsert",this.path=t}},C=class extends Error{constructor(t){super(`cannot write to read-only DOM property "${t}"`),this.name="RuleTargetReadOnly",this.target=t}};function x(e){let t=0,r=null,o=-1;for(let n=0;n<e.length;n++){let s=e[n];s==="\\"?n++:r?s===r&&(r=null):s==='"'||s==="'"?r=s:s==="["||s==="("?t++:s==="]"||s===")"?t>0&&t--:s==="@"&&t===0&&(o=n)}return o}function Z(e){let t=x(e);return t===-1?{selector:e,prop:null}:{selector:e.slice(0,t),prop:e.slice(t+1)||null}}function g(e,t,r,o={}){return ee(e,t,r,{depth:0,path:[]},o)}function ee(e,t,r,o,n){if(o.depth>_)throw new w(o.path);if(typeof r=="string")return je(e,t,r,n);if(Array.isArray(r)){let[s,l]=r;return e.find(t,s,n).map((c,f)=>ee(e,c,l,{depth:o.depth+1,path:[...o.path,f]},n))}if(typeof r=="object"&&r!==null){let s={};for(let[l,i]of Object.entries(r))s[l]=ee(e,t,i,{depth:o.depth+1,path:[...o.path,l]},n);return s}return null}function je(e,t,r,o){if(r.endsWith("[]")){let l=r.slice(0,-2);return e.find(t,l,o).map(i=>e.text(i))}if(r.startsWith("@"))return de(e,t,r.slice(1));let n=x(r);if(n!==-1){let l=r.slice(0,n),i=r.slice(n+1),c=l?e.find(t,l,o):[t];return c.length===0?null:de(e,c[0],i)}if(r===".")return e.text(t);let s=e.find(t,r,o);return s.length===0?null:e.text(s[0])}function de(e,t,r){if(Q.has(r)){let n=e.prop(t,r);return n==null?null:String(n)}let o=e.attr(t,r);return o||null}var Ce=.5;function te(e,t,r,o,n,s,l,i={}){let c=e.find(t,r,i);if(n.length===0){c.forEach(d=>e.remove(d));return}let f=n.length>c.length,u=c[0]||null;if(f&&!u&&(u=He(e,t,r,i),!u))throw new j(s.path);let p=c.map(d=>ke(e,d,o,i)),a=null;if(u){a=e.clone(u),i.templateAttr&&e.removeAttr(a,i.templateAttr);let d=e.stripIds(a);d>0&&console.warn(`[hyper-html-api] stripped ${d} id attribute(s) from cloned template at "${s.path.join(".")||"(root)"}"`)}let E=$e(n,p,o),m=c[0]||u,R=e.parent(m),W=c.length>0?me(e,R,m):0,I=We(e,c),A=new Set,Y=[],B=n.map((d,D)=>{let M=E[D];if(M>=0)return A.add(M),Y.push(!1),c[M];Y.push(!0);let z=e.clone(a);return e.stripIds(z),z});if(c.forEach((d,D)=>{A.has(D)||e.remove(d)}),I){B.forEach((d,D)=>{let M=W+D;e.children(R).findIndex(Me=>e.sameNode(Me,d))!==M&&e.insertAt(R,d,M)}),he(e,B,o,n,s,l,i);return}Be(e,B,Y,R,W),he(e,B,o,n,s,l,i)}function he(e,t,r,o,n,s,l){t.forEach((i,c)=>{if(r===null){let f=o[c],u=f==null?"":String(f);e.text(i)!==u&&e.text(i,u)}else{let f=s(e,i,r,o[c],{depth:n.depth+1,path:[...n.path,c]},l);f&&f!==i&&(t[c]=f)}})}function ke(e,t,r,o){return r===null?e.text(t):g(e,t,r,o)}function $e(e,t,r){let o=new Array(e.length).fill(-1),n=new Set;return e.forEach((s,l)=>{let i=-1,c=-1;t.forEach((f,u)=>{if(n.has(u))return;let p=Ue(s,f,r),a=p===c&&i>=0?Math.abs(u-l)<Math.abs(i-l):!1;(p>c||a)&&(c=p,i=u)}),c>=Ce&&(o[l]=i,n.add(i))}),o}function Ue(e,t,r){if(r===null)return e===t?1:0;let o=Object.keys(r||{});if(o.length===0)return 0;let n=0;for(let s of o)JSON.stringify(e?.[s])===JSON.stringify(t?.[s])&&n++;return n/o.length}function me(e,t,r){let o=e.children(t);for(let n=0;n<o.length;n++)if(e.sameNode(o[n],r))return n;return-1}function He(e,t,r,o){if(!o.templateAttr)return null;let n=t;for(;n;){let s=e.find(n,r,{includeRulesTag:!1,templateAttr:null});for(let l of s)if(e.attr(l,o.templateAttr)!=null)return l;n=e.parent(n)}return null}function We(e,t){if(t.length<=1)return!0;let r=e.parent(t[0]);if(!r)return!1;let o=e.children(r),n=[];for(let s of t){let l=o.findIndex(i=>e.sameNode(i,s));if(l===-1)return!1;n.push(l)}return n.sort((s,l)=>s-l),n[n.length-1]-n[0]===n.length-1}function Be(e,t,r,o,n){let s=null,l=n;for(let i=0;i<t.length;i++){if(!r[i]){s=t[i];continue}let c=s?e.parent(s):o;if(!c)continue;let f=s?me(e,c,s)+1:l++;e.insertAt(c,t[i],f),s=t[i]}}var ge=new Set(["checked","selected","disabled","readOnly","paused"]);function T(e,t,r,o,n={}){let s=[];if(re(r,o,[],s),s.length)throw new L(s);J(e,t,r,o,{depth:0,path:[]},n)}function J(e,t,r,o,n,s={}){if(n.depth>_)throw new w(n.path);if(o===void 0)return t;if(typeof r=="string")return qe(e,t,r,o,n,s);if(Array.isArray(r)){let[l,i]=r;return te(e,t,l,i,o,n,J,s),t}if(typeof r=="object"&&r!==null){for(let[l,i]of Object.entries(r)){let c=J(e,t,i,o==null?o:o[l],{depth:n.depth+1,path:[...n.path,l]},s);c&&c!==t&&(t=c)}return t}return t}function qe(e,t,r,o,n,s){if(r.endsWith("[]")){let c=r.slice(0,-2);return te(e,t,c,null,o,n,J,s),t}if(r.startsWith("@"))return ye(e,t,r.slice(1),o);let l=x(r);if(l!==-1){let c=r.slice(0,l),f=r.slice(l+1),u=c?e.find(t,c,s):[t];return u.length===0||ye(e,u[0],f,o),t}if(r===".")return e.text(t,o==null?"":String(o)),t;let i=e.find(t,r,s);return i.length===0||e.text(i[0],o==null?"":String(o)),t}function ye(e,t,r,o){if(pe.has(r))throw new C(r);if(r==="outerHTML"){let n=o==null?"":String(o);return e.replaceWith(t,n)}return ae.has(r)?(e.prop(t,r,Fe(r,o)),t):(e.attr(t,r,o==null?"":String(o)),t)}function Fe(e,t){return t==null?ge.has(e)?!1:"":ge.has(e)?!!t:t}function re(e,t,r,o){if(t!==void 0){if(typeof e=="string"){if(e.endsWith("[]")){Array.isArray(t)?t.forEach((n,s)=>{typeof n=="object"&&n!==null&&o.push({path:$([...r,s]),expected:"scalar",got:k(n)})}):o.push({path:$(r),expected:"array",got:k(t)});return}t!==null&&typeof t=="object"&&o.push({path:$(r),expected:"scalar",got:k(t)});return}if(Array.isArray(e)){if(!Array.isArray(t)){o.push({path:$(r),expected:"array",got:k(t)});return}let n=e[1];t.forEach((s,l)=>re(n,s,[...r,l],o));return}if(typeof e=="object"&&e!==null){if(t===null||Array.isArray(t)||typeof t!="object"){o.push({path:$(r),expected:"object",got:k(t)});return}for(let[n,s]of Object.entries(e))re(s,t[n],[...r,n],o)}}}function k(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function $(e){return e.join(".")}function ne(e){try{return JSON.parse(e)}catch(t){throw new N(`Invalid strict JSON: ${t.message}`,t)}}function S(e){try{return JSON.parse(e)}catch{}let t={BRACE_OPEN:"{",BRACE_CLOSE:"}",BRACKET_OPEN:"[",BRACKET_CLOSE:"]",COLON:":",COMMA:",",STRING:"STRING",SELECTOR:"SELECTOR",IDENTIFIER:"IDENTIFIER",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN"};function r(n){let s=[],l=0;for(;l<n.length;){let i=n[l];if(/\s/.test(i)){l++;continue}if("{}".includes(i)){s.push({type:i,value:i}),l++;continue}if(i==="["){let p=!1,a=l+1;for(;a<n.length&&/\s/.test(n[a]);)a++;if(a<n.length&&/[a-zA-Z_]/.test(n[a])&&(p=!0),!p){s.push({type:i,value:i}),l++;continue}}if(i==="]"){s.push({type:i,value:i}),l++;continue}if(i===":"){s.push({type:t.COLON,value:i}),l++;continue}if(i===","){s.push({type:t.COMMA,value:i}),l++;continue}if(i==='"'||i==="'"){let p=i,a=l+1;for(;a<n.length&&n[a]!==p;)n[a]==="\\"&&a++,a++;s.push({type:t.STRING,value:n.substring(l+1,a),quoted:!0,sourceQuote:p}),l=a+1;continue}let c=l,f;for(;c<n.length&&!/[{},]/.test(n[c]);)if(n[c]===":"){let p=[":first",":last",":nth-child",":nth-of-type",":first-child",":last-child",":first-of-type",":last-of-type",":only-child",":only-of-type",":hover",":focus",":active",":visited",":disabled",":enabled",":checked",":empty",":root",":target",":not",":before",":after",":nth-last-child",":nth-last-of-type"],a=!1;for(let E of p){let m=E.substring(1);if(n.substring(c+1,c+1+m.length)===m){a=!0,c+=m.length;break}}if(!a)break}else if(n[c]==="["){for(c++;c<n.length&&n[c]!=="]";){if(n[c]==='"'||n[c]==="'"){let p=n[c];for(c++;c<n.length&&n[c]!==p;)n[c]==="\\"&&c++,c++}c++}c<n.length&&n[c]==="]"&&c++}else c++;f=n.substring(l,c);let u=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(f)?u=t.NUMBER:f==="true"||f==="false"||f==="null"?u=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(f)&&(u=t.SELECTOR),s.push({type:u,value:f,quoted:!1}),l=c}return s}function o(n){let s="";for(let l=0;l<n.length;l++){let i=n[l];if("{}".includes(i.type)||"[]".includes(i.type)){s+=i.value;continue}if(i.type===t.COLON){s+=i.value;continue}if(i.type===t.COMMA){let c=n[l+1];if(c&&(c.type==="}"||c.type==="]"))continue;s+=i.value;continue}if(i.type===t.STRING&&i.quoted){let c=i.value;i.sourceQuote==="'"&&(c=c.replace(/\\'/g,"'"),c=c.replace(/(\\*)"/g,(f,u)=>u.length%2===0?u+'\\"':f)),s+=`"${c}"`;continue}if(i.type===t.NUMBER||i.type===t.BOOLEAN){s+=i.value;continue}if(i.type===t.SELECTOR||i.type===t.IDENTIFIER){s+=`"${i.value}"`;continue}s+=`"${i.value}"`}return s}try{let n=r(e),s=o(n);return JSON.parse(s)}catch(n){throw new N("Invalid extraction rules syntax: "+n.message,n)}}var oe="1",Ee=/^[a-zA-Z0-9_-]+$/;function U(e,t,r){let o;if(r===void 0)o="script[data-rules-name]";else{if(typeof r!="string"||!Ee.test(r))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(r)} (must match ${Ee})`);o=`script[data-rules-name~="${r}"]`}let n=e.find(t,o,{includeRulesTag:!0});if(n.length===0)return null;r!==void 0&&n.length>1&&console.warn(`hyper-html-api: ${n.length} rules tags match data-rules-name~="${r}"; using the first.`);let s=n[0],l=e.attr(s,"data-rules-version");if(l!==oe)throw new O(l);return{rules:S(e.text(s)),tagNode:s}}function se(e,t,r){if(r&&typeof r=="object")return{rules:r,tagNode:null};if(typeof r=="string"){let o=t&&t.ownerDocument?t.ownerDocument:t;return U(e,o,r)}return null}function xe(e,t,r,o){let n=se(e,t,r);if(!n){let i=typeof r=="string"?`data-rules-name~="${r}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${i}`)}let{rules:s,tagNode:l}=n;return{rules:s,tagNode:l,get:()=>g(e,t,s,o),set:i=>T(e,t,s,i,o)}}function Ve(e){return e&&e.nodeType===1&&e.tagName==="SCRIPT"&&e.hasAttribute&&e.hasAttribute("data-rules-name")}function ve(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var Ke={find(e,t,r={}){let o=ve(e);if(!o||!o.querySelectorAll)return[];let n=Array.from(o.querySelectorAll(t));r.includeRulesTag||(n=n.filter(i=>!Ve(i)));let s=[];r.skip&&s.push(r.skip);let l=r.templateAttr===null?null:r.templateAttr||"cms-template";if(l&&s.push("["+l+"]"),s.length){let i=s.join(", ");n=n.filter(c=>!c.closest||!c.closest(i))}return n},parent(e){return e?e.parentElement:null},children(e){return e?Array.from(e.children):[]},text(e,t){if(t===void 0)return(e.textContent||"").trim();e.textContent=t},attr(e,t,r){if(r===void 0)return e.hasAttribute&&e.hasAttribute(t)?e.getAttribute(t):null;e.setAttribute(t,r)},removeAttr(e,t){e&&e.removeAttribute&&e.removeAttribute(t)},prop(e,t,r){if(r===void 0){let o=e?e[t]:void 0;return o!==void 0?o:null}e[t]=r},clone(e){return e.cloneNode(!0)},insertAt(e,t,r){let o=e.children[r]||null;e.insertBefore(t,o)},remove(e){e&&e.parentNode&&e.parentNode.removeChild(e)},replaceWith(e,t){if(!e||!e.parentNode)throw new Error("dom.replaceWith: node has no parent");let o=e.ownerDocument.createElement("template");o.innerHTML=t;let n=o.content.firstElementChild;if(!n)throw new Error("dom.replaceWith: html did not parse to an element");return e.parentNode.replaceChild(n,e),n},stripIds(e){let t=0;return e.id&&(e.removeAttribute("id"),t++),(e.querySelectorAll?e.querySelectorAll("[id]"):[]).forEach(o=>{o.removeAttribute("id"),t++}),t},sameNode(e,t){return e===t}},h=Ke;var ie={extract:(e,t,r)=>g(h,e,t,r),apply:(e,t,r,o)=>T(h,e,t,r,o),findRulesIn:(e,t)=>U(h,e,t),findRules:(e,t)=>se(h,e,t),bind:(e,t,r)=>xe(h,e,t,r),parseStrict:ne,parseRelaxed:S,ruleAttrIndex:x,splitRule:Z,errors:F,DOM_PROPERTIES:q};var Ge="hha:upgrade-check:";function y(e,t){let r=e.querySelector(`meta[name="${t}"]`),o=r?r.getAttribute("content"):null;return o&&o.trim()?o.trim():null}function Re(e){if(typeof e!="string")return null;let t=e.trim().replace(/^v/,"");return/^\d+(\.\d+)*$/.test(t)?t.split(".").map(Number):null}function Ye(e,t){let r=Re(e),o=Re(t);if(!r||!o)return!1;let n=Math.max(r.length,o.length);for(let s=0;s<n;s++){let l=r[s]||0,i=o[s]||0;if(l!==i)return l>i}return!1}function ze(e){try{let t=globalThis.localStorage.getItem(e);return t?JSON.parse(t):null}catch{return null}}function Xe(e,t){try{globalThis.localStorage.setItem(e,JSON.stringify(t))}catch{}}async function Ae({force:e=!1,doc:t,loc:r,fetchFn:o,now:n,ttlMs:s=864e5}={}){if(t=t||(typeof document<"u"?document:null),r=r||(typeof location<"u"?location:null),o=o||(a=>fetch(a)),n=n??Date.now(),!t)return null;let l=y(t,"hyper-source");if(!l)return null;let i=y(t,"hyper-version"),c;try{c=new URL(l,r?r.href:void 0)}catch{return null}if(r&&c.origin===r.origin&&c.pathname===r.pathname)return null;let f=`${Ge}${c.href}:${i||"none"}`,u,p=e?null:ze(f);if(p&&typeof p.checkedAt=="number"&&n-p.checkedAt<s)u=p.sourceVersion;else{try{let a=await o(c.href);if(!a.ok)throw new Error(`HTTP ${a.status}`);let E=await a.text(),m=new DOMParser().parseFromString(E,"text/html");u=y(m,"hyper-version")}catch{u=null}Xe(f,{checkedAt:n,sourceVersion:u})}return u?{available:Ye(u,i||"0.0.0"),currentVersion:i,sourceVersion:u,sourceUrl:c.href}:null}var Qe="script[data-rules-name]";function Ze(e){return typeof e=="string"?e.trim().replace(/\s+/g," "):""}function V(e,t){let r=e.find(t,Qe,{includeRulesTag:!0}),o=new Set,n=[];for(let s of r){let l=Ze(e.attr(s,"data-rules-name"));if(!l)continue;if(o.has(l)){console.warn(`hyper-html-api: duplicate rules tag name "${l}"; using the first.`);continue}let i=e.attr(s,"data-rules-version");if(i!==oe)throw new O(i);o.add(l),n.push({name:l,rules:S(e.text(s))})}return n}function le(e,t){let r={};for(let{name:o,rules:n}of V(e,t))r[o]=g(e,t,n);return r}function Oe(e){let t=e||document,r=t.nodeType===9?t:t.ownerDocument||t;return{dataByName:le(h,t),version:y(r,"hyper-version")}}var H=class extends Error{constructor(t,r){super(`could not fetch upgrade source: ${t}`),this.name="UpgradeSourceUnreachable",this.sourceUrl=t,this.cause=r}},v=class extends Error{constructor(t){super(`upgrade source has no rules tags; refusing to drop all existing data: ${t}`),this.name="UpgradeSourceHasNoRules",this.sourceUrl=t}},b=class extends Error{constructor(t,r){super(t),this.name="UpgradeTransformInvalid",this.cause=r}},K=class extends Error{constructor(t){super(`found ${t} script[type="text/hyper-upgrade"] tags; only one is allowed per document.`),this.name="UpgradeMultipleTransforms",this.count=t}};var et="text/hyper-upgrade";function we(e,t){let r=e.find(t,`script[type="${et}"]`);if(r.length===0)return null;if(r.length>1)throw new K(r.length);return e.text(r[0])||null}var tt=new Function("url","return import(url)");async function Te(e){let t=new Blob([e],{type:"text/javascript"}),r=URL.createObjectURL(t),o;try{o=await tt(r)}catch(n){throw new b(`transform failed to load: ${n&&n.message?n.message:n}`,n)}finally{URL.revokeObjectURL(r)}if(typeof o.default!="function")throw new b("transform must `export default` a function");return o.default}function G(e,t){let r={carriedOver:0,discarded:0,listItems:0},o=ce(t,e,r);return ue(t,e,r),{data:o,summary:r}}function ce(e,t,r){if(typeof e=="string")return e.endsWith("[]")?Array.isArray(t)?(r.listItems+=t.length,r.carriedOver+=t.length,t):void 0:t==null||typeof t=="object"?void 0:(r.carriedOver++,t);if(Array.isArray(e)){let[,o]=e;return Array.isArray(t)?(r.listItems+=t.length,t.map(n=>ce(o,n,r))):void 0}if(typeof e=="object"&&e!==null){let o={};for(let[n,s]of Object.entries(e)){let l=ce(s,t?.[n],r);l!==void 0&&(o[n]=l)}return o}}function ue(e,t,r){if(t!=null){if(typeof e=="object"&&e!==null&&!Array.isArray(e)){if(typeof t!="object"||Array.isArray(t))return;let o=new Set(Object.keys(e));for(let n of Object.keys(t))o.has(n)?ue(e[n],t[n],r):r.discarded+=P(t[n]);return}if(Array.isArray(e)&&Array.isArray(t)){let o=e[1];t.forEach(n=>ue(o,n,r));return}typeof e=="string"&&!e.endsWith("[]")&&typeof t=="object"&&t!==null&&(r.discarded+=P(t))}}function P(e){return e==null?0:Array.isArray(e)?e.reduce((t,r)=>t+P(r),0):typeof e=="object"?Object.values(e).reduce((t,r)=>t+P(r),0):1}function Se(e,t,r){let o=V(e,t),n={carriedOver:0,discarded:0,listItems:0},s={},l=new Set;for(let{name:i,rules:c}of o){if(l.add(i),!Object.prototype.hasOwnProperty.call(r,i)){s[i]={carriedOver:0,discarded:0,listItems:0};continue}let{data:f,summary:u}=G(r[i],c);T(e,t,c,f),s[i]=u,n.carriedOver+=u.carriedOver,n.discarded+=u.discarded,n.listItems+=u.listItems}for(let i of Object.keys(r))l.has(i)||(n.discarded+=P(r[i]));return{totals:n,byName:s,rulesTagCount:o.length}}async function be({sourceUrl:e,dataByName:t,fromVersion:r,doc:o,loc:n,fetchFn:s}={}){if(o=o||(typeof document<"u"?document:null),n=n||(typeof location<"u"?location:null),s=s||(I=>fetch(I)),!o)throw new Error("upgrade.run requires a document context");if(e=e||y(o,"hyper-source"),!e)throw new Error("upgrade.run: no sourceUrl given and no hyper-source meta tag found");let l=new URL(e,n?n.href:void 0);r=r!==void 0?r:y(o,"hyper-version"),t=t||le(h,o);let i;try{i=await s(l.href)}catch(I){throw new H(l.href,I)}if(!i.ok)throw new H(l.href,new Error(`HTTP ${i.status}`));let c=await i.text(),f=new DOMParser().parseFromString(c,"text/html"),u=y(f,"hyper-version"),p=t,a=!1,E=we(h,f);if(E){let A=await(await Te(E))(p,{fromVersion:r,toVersion:u});if(!A||typeof A!="object"||Array.isArray(A))throw new b("transform must return a plain object map of { rulesName: data }");p=A,a=!0}let{totals:m,byName:R,rulesTagCount:W}=Se(h,f,p);if(W===0&&Object.keys(p).length>0)throw new v(l.href);return{html:rt(f),fromVersion:r,toVersion:u,summary:{transformApplied:a,totals:m,byName:R}}}function rt(e){return`<!DOCTYPE ${e.doctype&&e.doctype.name?e.doctype.name:"html"}>
|
|
2
|
-
`+e.documentElement.outerHTML}var
|
|
1
|
+
var hyperHtmlApiUpgrade=(()=>{var te=Object.defineProperty;var Ke=Object.getOwnPropertyDescriptor;var Ve=Object.getOwnPropertyNames;var Je=Object.prototype.hasOwnProperty;var Ee=(e,t)=>{for(var n in t)te(e,n,{get:t[n],enumerable:!0})},Ye=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Ve(t))!Je.call(e,r)&&r!==n&&te(e,r,{get:()=>t[r],enumerable:!(o=Ke(t,r))||o.enumerable});return e};var Ge=e=>Ye(te({},"__esModule",{value:!0}),e);var St={};Ee(St,{default:()=>bt,engine:()=>pe,upgrade:()=>ze});var J=["textContent","innerText","innerHTML","outerHTML","value","checked","selected","disabled","readOnly","type","tagName","nodeName","nodeType","nodeValue","childElementCount","id","className","classList","baseURI","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","dataset","currentSrc","duration","paused","title","documentURI","contentType"],ne=new Set(J),we=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),re=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var Y={};Ee(Y,{EmptyListInsert:()=>U,MAX_RULE_DEPTH:()=>_,MaxRuleDepthExceeded:()=>I,RuleTargetReadOnly:()=>H,RulesParseError:()=>k,ShapeMismatch:()=>v,UnknownRulesVersion:()=>j});var k=class extends Error{constructor(t,n){super(t),this.name="RulesParseError",this.cause=n}},j=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},_=20,I=class extends Error{constructor(t){super(`rule depth exceeded ${_} at path: ${t.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=t}},v=class extends Error{constructor(t){super(`shape mismatch: ${t.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=t}},U=class extends Error{constructor(t){super(`cannot add items to empty list at "${t.join(".")}" \u2014 no sibling to clone as template. Seed the list with a hidden item first.`),this.name="EmptyListInsert",this.path=t}},H=class extends Error{constructor(t){super(`cannot write to read-only DOM property "${t}"`),this.name="RuleTargetReadOnly",this.target=t}};function N(e){let t=0,n=null,o=-1;for(let r=0;r<e.length;r++){let i=e[r];i==="\\"?r++:n?i===n&&(n=null):i==='"'||i==="'"?n=i:i==="["||i==="("?t++:i==="]"||i===")"?t>0&&t--:i==="@"&&t===0&&(o=r)}return o}function oe(e){let t=N(e);return t===-1?{selector:e,prop:null}:{selector:e.slice(0,t),prop:e.slice(t+1)||null}}function M(e,t,n,o={}){if(Object.prototype.hasOwnProperty.call(o,"exclude")&&e.semanticExclude===!1)throw new Error("This adapter does not support semantic exclude queries; omit exclude or use the DOM adapter.");return ie(e,t,n,{depth:0,path:[]},o)}function ie(e,t,n,o,r){if(o.depth>_)throw new I(o.path);if(typeof n=="string")return Xe(e,t,n,o,r);if(Array.isArray(n)){let[i,c]=n,s=e.find(t,i,r);return xe(r,o,s),s.map((l,a)=>ie(e,l,c,{depth:o.depth+1,path:[...o.path,a]},r))}if(typeof n=="object"&&n!==null){let i={};for(let[c,s]of Object.entries(n))i[c]=ie(e,t,s,{depth:o.depth+1,path:[...o.path,c]},r);return i}return null}function Xe(e,t,n,o,r){if(n.endsWith("[]")){let s=n.slice(0,-2),l=e.find(t,s,r);return xe(r,o,l),l.map(a=>e.text(a))}if(n.startsWith("@"))return Te(e,t,n.slice(1));let i=N(n);if(i!==-1){let s=n.slice(0,i),l=n.slice(i+1),a=s?e.find(t,s,r):[t];return a.length===0?null:Te(e,a[0],l)}if(n===".")return e.text(t);let c=e.find(t,n,r);return c.length===0?null:e.text(c[0])}function xe(e,t,n){if(typeof e.onRowsRead=="function")try{e.onRowsRead(t.path.slice(),n)}catch(o){console.warn(`[hyper-html-api] onRowsRead threw at "${t.path.join(".")||"(root)"}"`,o)}}function Te(e,t,n){if(ne.has(n)){let r=e.prop(t,n);return r==null?null:String(r)}let o=e.attr(t,n);return o||null}function be(e,t,n,o){let r=e.length,i=t.length,c=new Array(r).fill(-1);if(o){let u=new Set;for(let p=0;p<r;p++){let g=o[p];!(g>=0&&g<i)||u.has(g)||(c[p]=g,u.add(g))}}if(r===0||i===0)return c;let s=e.map(u=>Oe(u,n)),l=t.map(u=>Oe(u,n)),a=new Array(i).fill(!1);for(let u of c)u>=0&&(a[u]=!0);let f=new Map;l.forEach((u,p)=>{a[p]||f.set(u,f.has(u)?-1:p)});let y=new Map;s.forEach((u,p)=>{c[p]>=0||y.set(u,(y.get(u)||0)+1)}),s.forEach((u,p)=>{if(c[p]>=0||y.get(u)!==1)return;let g=f.get(u);g===void 0||g===-1||a[g]||(c[p]=g,a[g]=!0)});let d=[];for(let u=0;u<r;u++)c[u]<0&&d.push(u);let T=[];for(let u=0;u<i;u++)a[u]||T.push(u);if(d.length===0||T.length===0)return c;let h=r*i+1,m=(u,p)=>Qe(e[u],t[p],n)*h+Math.abs(u-p);for(let[u,p]of Ze(d,T,m))c[u]=p;return c}var Se=e=>typeof e=="object"&&e!==null;function Oe(e,t){if(!Se(t))return e==null?" null":String(e);let n=Object.keys(t);return JSON.stringify(n.map(o=>{let r=JSON.stringify(e?.[o]);return r===void 0?" undef":r}))}function Qe(e,t,n){if(!Se(n))return e===t?0:1;let o=Object.keys(n);if(o.length===0)return 0;let r=0;for(let i of o){let c=JSON.stringify(e?.[i]),s=JSON.stringify(t?.[i]);c!==s&&r++}return r}function Ze(e,t,n){return e.length<=t.length?Ae(e,t,n,!1):Ae(t,e,(o,r)=>n(r,o),!0)}function Ae(e,t,n,o){let r=e.length,i=t.length,c=[];for(let y=0;y<=r;y++)c.push(new Float64Array(i+1).fill(1/0));let s=[];for(let y=0;y<=r;y++)s.push(new Uint8Array(i+1));for(let y=0;y<=i;y++)c[r][y]=0;for(let y=r-1;y>=0;y--)for(let d=i-1;d>=0;d--){let T=n(e[y],t[d])+c[y+1][d+1],h=c[y][d+1];T<=h?(c[y][d]=T,s[y][d]=1):c[y][d]=h}let l=[],a=0,f=0;for(;a<r&&f<i;)s[a][f]&&(l.push(o?[t[f],e[a]]:[e[a],t[f]]),a++),f++;return l}function le(e,t,n,o,r,i,c,s={}){let l=e.find(t,n,s);if(r.length===0){l.forEach(E=>e.remove(E)),se(s,"onRowsApplied",i.path,[]);return}let a=r.length>l.length,f=l[0]||null;if(a&&!f&&(f=rt(e,t,n,s),!f))throw new U(i.path);let y=l.map(E=>nt(e,E,o,s)),d=null;if(a&&f){d=e.clone(f),s.templateAttr&&e.removeAttr(d,s.templateAttr);let E=e.stripIds(d);E>0&&console.warn(`[hyper-html-api] stripped ${E} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let T=be(r,y,o,et(e,l,r,i,s)),h=l[0]||f,m=e.parent(h),u=l.length>0?Re(e,m,h):0,p=ot(e,l),g=new Set,A=[],O=r.map((E,x)=>{let w=T[x];if(w>=0)return g.add(w),A.push(!1),l[w];A.push(!0);let R=e.clone(d);return e.stripIds(R),R});l.forEach((E,x)=>{g.has(x)||e.remove(E)}),p?O.forEach((E,x)=>{let w=u+x;e.children(m).findIndex(Fe=>e.sameNode(Fe,E))!==w&&e.insertAt(m,E,w)}):it(e,O,A,m,u),tt(e,O,o,r,i,c,s),se(s,"onRowsApplied",i.path,O)}function se(e,t,n,o){if(typeof e[t]=="function")try{return e[t](n.slice(),o)}catch(r){console.warn(`[hyper-html-api] ${t} threw at "${n.join(".")||"(root)"}"`,r);return}}function et(e,t,n,o,r){let i=se(r,"identifyRows",o.path,n);if(!Array.isArray(i))return null;let c=new Array(n.length).fill(-1),s=new Set;for(let l=0;l<n.length;l++)if(i[l]){for(let a=0;a<t.length;a++)if(!(s.has(a)||!e.sameNode(t[a],i[l]))){c[l]=a,s.add(a);break}}return c}function tt(e,t,n,o,r,i,c){t.forEach((s,l)=>{if(n===null){let a=o[l],f=a==null?"":String(a);e.text(s)!==f&&e.text(s,f)}else{let a=i(e,s,n,o[l],{depth:r.depth+1,path:[...r.path,l]},c);a&&a!==s&&(t[l]=a)}})}function nt(e,t,n,o){return n===null?e.text(t):M(e,t,n,o.onRowsRead?{...o,onRowsRead:void 0}:o)}function Re(e,t,n){let o=e.children(t);for(let r=0;r<o.length;r++)if(e.sameNode(o[r],n))return r;return-1}function rt(e,t,n,o){if(!o.templateAttr)return null;let r=t;for(;r;){let i=e.find(r,n,{includeRulesTag:!1,templateAttr:null});for(let c of i)if(e.attr(c,o.templateAttr)!=null)return c;r=e.parent(r)}return null}function ot(e,t){if(t.length<=1)return!0;let n=e.parent(t[0]);if(!n)return!1;let o=e.children(n),r=[];for(let i of t){let c=o.findIndex(s=>e.sameNode(s,i));if(c===-1)return!1;r.push(c)}return r.sort((i,c)=>i-c),r[r.length-1]-r[0]===r.length-1}function it(e,t,n,o,r){let i=null,c=r;for(let s=0;s<t.length;s++){if(!n[s]){i=t[s];continue}let l=i?e.parent(i):o;if(!l)continue;let a=i?Re(e,l,i)+1:c++;e.insertAt(l,t[s],a),i=t[s]}}var Me=new Set(["checked","selected","disabled","readOnly","paused"]);function P(e,t,n,o,r={}){if(Object.prototype.hasOwnProperty.call(r,"exclude")&&e.semanticExclude===!1)throw new Error("This adapter does not support semantic exclude queries; omit exclude or use the DOM adapter.");let i=[];if(ce(n,o,[],i),i.length)throw new v(i);G(e,t,n,o,{depth:0,path:[]},r)}function G(e,t,n,o,r,i={}){if(r.depth>_)throw new I(r.path);if(o===void 0)return t;if(typeof n=="string")return st(e,t,n,o,r,i);if(Array.isArray(n)){let[c,s]=n;return le(e,t,c,s,o,r,G,i),t}if(typeof n=="object"&&n!==null){for(let[c,s]of Object.entries(n)){let l=G(e,t,s,o==null?o:o[c],{depth:r.depth+1,path:[...r.path,c]},i);l&&l!==t&&(t=l)}return t}return t}function st(e,t,n,o,r,i){if(n.endsWith("[]")){let l=n.slice(0,-2);return le(e,t,l,null,o,r,G,i),t}if(n.startsWith("@"))return Ne(e,t,n.slice(1),o);let c=N(n);if(c!==-1){let l=n.slice(0,c),a=n.slice(c+1),f=l?e.find(t,l,i):[t];return f.length===0||Ne(e,f[0],a,o),t}if(n===".")return Ce(e,t,o),t;let s=e.find(t,n,i);return s.length===0||Ce(e,s[0],o),t}function Ce(e,t,n){let o=n==null?"":String(n);e.text(t)!==o&&e.text(t,o)}function Ne(e,t,n,o){if(re.has(n))throw new H(n);if(n==="outerHTML"){let i=o==null?"":String(o);return e.replaceWith(t,i)}if(we.has(n)){let i=lt(n,o);return e.prop(t,n)!==i&&e.prop(t,n,i),t}let r=o==null?"":String(o);return e.attr(t,n)!==r&&e.attr(t,n,r),t}function lt(e,t){return t==null?Me.has(e)?!1:"":Me.has(e)?t==="false"?!1:!!t:t}function ce(e,t,n,o){if(t!==void 0){if(typeof e=="string"){if(e.endsWith("[]")){Array.isArray(t)?t.forEach((r,i)=>{typeof r=="object"&&r!==null&&o.push({path:q([...n,i]),expected:"scalar",got:W(r)})}):o.push({path:q(n),expected:"array",got:W(t)});return}t!==null&&typeof t=="object"&&o.push({path:q(n),expected:"scalar",got:W(t)});return}if(Array.isArray(e)){if(!Array.isArray(t)){o.push({path:q(n),expected:"array",got:W(t)});return}let r=e[1];t.forEach((i,c)=>ce(r,i,[...n,c],o));return}if(typeof e=="object"&&e!==null){if(t===null||Array.isArray(t)||typeof t!="object"){o.push({path:q(n),expected:"object",got:W(t)});return}for(let[r,i]of Object.entries(e))ce(i,t[r],[...n,r],o)}}}function W(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function q(e){return e.join(".")}function fe(e){try{return JSON.parse(e)}catch(t){throw new k(`Invalid strict JSON: ${t.message}`,t)}}function L(e){try{return JSON.parse(e)}catch{}let t={BRACE_OPEN:"{",BRACE_CLOSE:"}",BRACKET_OPEN:"[",BRACKET_CLOSE:"]",COLON:":",COMMA:",",STRING:"STRING",SELECTOR:"SELECTOR",IDENTIFIER:"IDENTIFIER",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN"};function n(r){let i=[],c=0;for(;c<r.length;){let s=r[c];if(/\s/.test(s)){c++;continue}if("{}".includes(s)){i.push({type:s,value:s}),c++;continue}if(s==="["){let y=!1,d=c+1;for(;d<r.length&&/\s/.test(r[d]);)d++;if(d<r.length&&/[a-zA-Z_]/.test(r[d])&&(y=!0),!y){i.push({type:s,value:s}),c++;continue}}if(s==="]"){i.push({type:s,value:s}),c++;continue}if(s===":"){i.push({type:t.COLON,value:s}),c++;continue}if(s===","){i.push({type:t.COMMA,value:s}),c++;continue}if(s==='"'||s==="'"){let y=s,d=c+1;for(;d<r.length&&r[d]!==y;)r[d]==="\\"&&d++,d++;i.push({type:t.STRING,value:r.substring(c+1,d),quoted:!0,sourceQuote:y}),c=d+1;continue}let l=c,a;for(;l<r.length&&!/[{},]/.test(r[l]);)if(r[l]===":"){let y=[":first",":last",":nth-child",":nth-of-type",":first-child",":last-child",":first-of-type",":last-of-type",":only-child",":only-of-type",":hover",":focus",":active",":visited",":disabled",":enabled",":checked",":empty",":root",":target",":not",":before",":after",":nth-last-child",":nth-last-of-type"],d=!1;for(let T of y){let h=T.substring(1);if(r.substring(l+1,l+1+h.length)===h){d=!0,l+=h.length;break}}if(!d)break}else if(r[l]==="["){for(l++;l<r.length&&r[l]!=="]";){if(r[l]==='"'||r[l]==="'"){let y=r[l];for(l++;l<r.length&&r[l]!==y;)r[l]==="\\"&&l++,l++}l++}l<r.length&&r[l]==="]"&&l++}else l++;a=r.substring(c,l);let f=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(a)?f=t.NUMBER:a==="true"||a==="false"||a==="null"?f=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(a)&&(f=t.SELECTOR),i.push({type:f,value:a,quoted:!1}),c=l}return i}function o(r){let i="";for(let c=0;c<r.length;c++){let s=r[c];if("{}".includes(s.type)||"[]".includes(s.type)){i+=s.value;continue}if(s.type===t.COLON){i+=s.value;continue}if(s.type===t.COMMA){let l=r[c+1];if(l&&(l.type==="}"||l.type==="]"))continue;i+=s.value;continue}if(s.type===t.STRING&&s.quoted){let l=s.value;s.sourceQuote==="'"&&(l=l.replace(/\\'/g,"'"),l=l.replace(/(\\*)"/g,(a,f)=>f.length%2===0?f+'\\"':a)),i+=`"${l}"`;continue}if(s.type===t.NUMBER||s.type===t.BOOLEAN){i+=s.value;continue}if(s.type===t.SELECTOR||s.type===t.IDENTIFIER){i+=`"${s.value}"`;continue}i+=`"${s.value}"`}return i}try{let r=n(e),i=o(r);return JSON.parse(i)}catch(r){throw new k("Invalid extraction rules syntax: "+r.message,r)}}var ue="1",je=/^[a-zA-Z0-9_-]+$/;function B(e,t,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!je.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${je})`);o=`script[data-rules-name~="${n}"]`}let r=e.find(t,o,{includeRulesTag:!0});if(r.length===0)return null;n!==void 0&&r.length>1&&console.warn(`hyper-html-api: ${r.length} rules tags match data-rules-name~="${n}"; using the first.`);let i=r[0],c=e.attr(i,"data-rules-version");if(c!==ue)throw new j(c);return{rules:L(e.text(i)),tagNode:i}}function ae(e,t,n){if(n&&typeof n=="object")return{rules:n,tagNode:null};if(typeof n=="string"){let o=t&&t.ownerDocument?t.ownerDocument:t;return B(e,o,n)}return null}var Ie=Object.freeze({data:Object.freeze({tokens:["no-data"],bundles:["editor-ui"]}),save:Object.freeze({tokens:["no-save"],bundles:["editor-ui"]}),snapshot:Object.freeze({tokens:["no-snapshot"],bundles:["editor-ui"]}),watch:Object.freeze({tokens:["no-watch"],bundles:["editor-ui"]}),undo:Object.freeze({tokens:["no-undo"],bundles:["editor-ui"]}),history:Object.freeze({tokens:[],bundles:["editor-ui"]})}),ft=Object.freeze({"editor-ui":Object.freeze(["no-data","no-save","no-snapshot","no-watch","no-undo"])}),rn=Object.freeze(["no-save","no-snapshot","no-trigger-autosave","no-dirty","no-watch","no-undo","no-data","freeze","editor-ui"]);function de(e,t){if(!e||e.nodeType!==1)return!1;let n=e.getAttribute?.("clay");return!!(n&&n.split(/\s+/).includes(t)||e.hasAttribute?.(t))}function ut(e,t){if(de(e,t))return!0;for(let[n,o]of Object.entries(ft))if(o.includes(t)&&de(e,n))return!0;return!1}function z(e){let t=Ie[e];if(!t)throw new Error(`Unknown region capability: ${e}`);return[...t.tokens,...t.bundles].flatMap(n=>[`[clay~="${n}"]`,`[${n}]`]).join(", ")}function at(e,t){let n=e&&e.nodeType===1?e:e?.parentElement;for(;n&&n.nodeType===1;){let o=Ie[t];if(!o)throw new Error(`Unknown region capability: ${t}`);if(o.tokens.some(r=>ut(n,r))||o.bundles.some(r=>de(n,r)))return n;n=n.parentElement}return null}function Pe(e,t){return!!at(e,t)}var dt=/:(?:focus(?:-within|-visible)?|hover|active|visited|defined)\b/i;function Le(e,t){if(!/^(INPUT|TEXTAREA|SELECT|OPTION)$/.test(e.tagName||""))return;let n=(e.getAttribute?.("type")||"").toLowerCase();if("value"in e&&"value"in t&&e.tagName!=="OPTION"&&n!=="checkbox"&&n!=="radio"&&(t.value=e.value),"checked"in e&&"checked"in t&&(t.checked=e.checked),"selected"in e&&"selected"in t&&(t.selected=e.selected),e.tagName==="SELECT")for(let o=0;o<e.options.length;o++)t.options[o].selected=e.options[o].selected;"indeterminate"in e&&"indeterminate"in t&&(t.indeterminate=e.indeterminate)}function De(e,t,n,o){if(o)return!!e.closest?.(t);let r=e;for(;r?.nodeType===1;){if(r.matches(t))return!0;if(r===n)break;r=r.parentElement}return!1}function ke(e,t,n,o,r,i,c,s){if(e.nodeType===1&&((c?Pe(e,n):De(e,o,i,!1))||r&&De(e,r,i,c)))return null;let l=t.importNode(e,!1);s.cloneToLive.set(l,e),s.liveToClone.set(e,l);let a=e.nodeType===1&&e.tagName==="TEMPLATE"?e.content:e,f=l.nodeType===1&&l.tagName==="TEMPLATE"?l.content:l;a!==e&&(s.cloneToLive.set(f,a),s.liveToClone.set(a,f));for(let y of a.childNodes||[]){let d=ke(y,t,n,o,r,i,c,s);d&&(f.appendChild(d),y.nodeType===1&&Le(y,d))}return e.nodeType===1&&Le(e,l),l}function F(e,{capability:t="data",exclude:n=null,inherit:o=!0}={}){if(!e)throw new TypeError("createContentView requires a DOM context");let r=e.nodeType===9?e:e.ownerDocument;if(!r?.implementation?.createHTMLDocument)throw new TypeError("createContentView requires an HTML DOM implementation");let i=r.implementation.createHTMLDocument(""),c=new WeakMap,s=new WeakMap,l=e.nodeType===9?e.documentElement:e;n&&i.documentElement.matches(n);let a=z(t),f=ke(l,i,t,a,n,l,o,{cloneToLive:c,liveToClone:s});e.nodeType===9&&f&&(i.replaceChild(f,i.documentElement),s.set(e,i),c.set(i,e));let y=d=>{if(dt.test(d))throw new Error(`Filtered content queries do not support stateful selector: ${d}`)};return{root:f,document:i,capability:t,selector:z(t),cloneToLive:c,liveToClone:s,original(d){return c.get(d)||null},cloneOf(d){return s.get(d)||null},query(d,T=f){return y(d),Array.from(T.querySelectorAll(d),h=>c.get(h)||h)},text(d=f){return(d===f?f:s.get(d))?.textContent||""},html(d=f){return(d===f?f:s.get(d))?.innerHTML??""},clone(d=f){let T=d===f?f:s.get(d);return T?i.importNode(T,!0):null}}}function _e(e){return e&&e.nodeType===1&&e.tagName==="SCRIPT"&&e.hasAttribute&&e.hasAttribute("data-rules-name")}function pt(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var b={semanticExclude:!0,find(e,t,n={}){let o=pt(e);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(t));n.includeRulesTag||(r=r.filter(s=>!_e(s)));let i=[];n.skip&&i.push(n.skip);let c=n.templateAttr===null?null:n.templateAttr||"cms-template";if(c&&i.push("["+c+"]"),i.length){let s=i.join(", ");r=r.filter(l=>!l.closest||!l.closest(s))}return r},parent(e){return e?e.parentElement:null},children(e){return e?Array.from(e.children):[]},text(e,t){if(t===void 0)return(e.textContent||"").trim();e.textContent=t},attr(e,t,n){if(n===void 0)return e.hasAttribute&&e.hasAttribute(t)?e.getAttribute(t):null;e.setAttribute(t,n)},removeAttr(e,t){e&&e.removeAttribute&&e.removeAttribute(t)},prop(e,t,n){if(n===void 0){let o=e?e[t]:void 0;return o!==void 0?o:null}e[t]=n},clone(e){return e.cloneNode(!0)},insertAt(e,t,n){let o=e.children[n]||null;e.insertBefore(t,o)},remove(e){e&&e.parentNode&&e.parentNode.removeChild(e)},replaceWith(e,t){if(!e||!e.parentNode)throw new Error("dom.replaceWith: node has no parent");let o=e.ownerDocument.createElement("template");o.innerHTML=t;let r=o.content.firstElementChild;if(!r)throw new Error("dom.replaceWith: html did not parse to an element");return e.parentNode.replaceChild(r,e),r},stripIds(e){let t=0;return e.id&&(e.removeAttribute("id"),t++),(e.querySelectorAll?e.querySelectorAll("[id]"):[]).forEach(o=>{o.removeAttribute("id"),t++}),t},sameNode(e,t){return e===t}};function K(e,t={}){if(t.exclude===null)return b;let n=[z("data"),t.exclude].filter(Boolean).join(", "),o=e.nodeType===9?e:e.ownerDocument||e,r=e.nodeType===9?e.documentElement:e;if(!t._write&&!r?.matches?.(n)&&!r?.querySelector?.(n)&&!o?.querySelector?.(n))return b;let i=e.nodeType===9||!e.isConnected?e:e.ownerDocument,c=e.nodeType===9?e:e.ownerDocument,s=null,l=()=>s||(s=F(i,{capability:"data",exclude:t.exclude||null})),a=h=>{let m=l();return h===e?m.cloneOf(e):m.cloneOf(h)||h},f=h=>s?.original(h)||h,y=(h,m)=>{l().liveToClone.set(h,m),l().cloneToLive.set(m,h);let u=h.childNodes||[],p=m.childNodes||[];for(let g=0;g<Math.min(u.length,p.length);g++)y(u[g],p[g])},d=(h,m,u,p)=>{let g=Array.from(h.childNodes).filter(w=>s.cloneOf(w)),O=g[0];for(;O&&g.includes(O);)O=O.nextSibling;for(let w of g)w.remove();if(u==="innerHTML"){let w=c.createElement("template");w.innerHTML=p;for(let R of Array.from(w.content.childNodes))h.insertBefore(R,O||null)}else h.insertBefore(c.createTextNode(p),O||null);let E=F(h,{capability:"data",exclude:t.exclude||null});m.replaceChildren(...Array.from(E.root?.childNodes||[]));let x=w=>{let R=E.original(w);R&&(s.liveToClone.set(R,w),s.cloneToLive.set(w,R));for(let ge of Array.from(w.childNodes||[]))x(ge)};for(let w of Array.from(m.childNodes))x(w)},T={...b,find(h,m,u={}){let p=a(h);if(!p?.querySelectorAll)return[];let g=l().query(m,p);u.includeRulesTag||(g=g.filter(E=>!_e(E)));let A=[];u.skip&&A.push(u.skip);let O=u.templateAttr===null?null:u.templateAttr||"cms-template";if(O&&A.push(`[${O}]`),A.length){let E=A.join(", ");g=g.filter(x=>!x.closest?.(E))}return g},parent(h){let m=a(h)?.parentElement;return m?f(m):null},children(h){return Array.from(a(h)?.children||[],f)},text(h,m){if(m===void 0){let g=f(h);return!g?.matches?.(n)&&!g?.querySelector?.(n)?b.text(g):(a(h)?.textContent||"").trim()}let u=f(h);if(!u?.matches?.(n)&&!u?.querySelector?.(n)&&!s){b.text(u,m);return}let p=l().cloneOf(u);p?d(u,p,"textContent",m):b.text(u,m)},attr(h,m,u){let p=f(h);if(u===void 0)return b.attr(p,m);b.attr(p,m,u);let g=s?.cloneOf(p);g&&(b.attr(g,m,u),F(p,{capability:"data",exclude:t.exclude||null}).root===null&&(g.remove(),s.liveToClone.delete(p),s.cloneToLive.delete(g)))},removeAttr(h,m){let u=f(h);b.removeAttr(u,m);let p=s?.cloneOf(u);p&&b.removeAttr(p,m)},prop(h,m,u){let p=f(h);if(u===void 0)return m==="innerHTML"||m==="outerHTML"||m==="textContent"||m==="innerText"?b.prop(a(p),m):b.prop(p,m);let g=m==="innerHTML"||m==="textContent"||m==="innerText",A=g?l().cloneOf(p):s?.cloneOf(p);A&&g?d(p,A,m,u):(b.prop(p,m,u),A&&b.prop(A,m,u))},clone(h){let m=a(h);return m===h?b.clone(h):c.importNode(m,!0)},insertAt(h,m,u){let p=f(h),A=T.children(p)[u]||(()=>{for(let x=p.children.length-1;x>=0;x--){let w=p.children[x];if(l().cloneOf(w))return w.nextElementSibling}return p.firstElementChild})(),O=f(m);p.insertBefore(O,A||null);let E=l().cloneOf(p);if(E){let x=l().cloneOf(O);x||(x=c.importNode(O,!0),y(O,x));let w=Array.from(E.children);E.insertBefore(x,w[u]||null)}},remove(h){let m=f(h),u=l().cloneOf(m);b.remove(m),u&&b.remove(u)},replaceWith(h,m){let u=f(h),p=l().cloneOf(u),g=b.replaceWith(u,m);if(p){let A=F(g,{capability:"data",exclude:t.exclude||null});if(!A.root)p.remove();else{p.replaceWith(A.root);let O=E=>{let x=A.original(E);x&&(s.liveToClone.set(x,E),s.cloneToLive.set(E,x));for(let w of Array.from(E.childNodes||[]))O(w)};O(A.root)}}return g}};return T}var S=b;var pe={extract:(e,t,n={})=>M(K(e,n),e,t,n),apply:(e,t,n,o={})=>P(K(e,{...o,_write:!0}),e,t,n,o),findRulesIn:(e,t)=>B(S,e,t),findRules:(e,t)=>ae(S,e,t),bind:(e,t,n={})=>{let o=ae(S,e,t);if(!o){let r=typeof t=="string"?`data-rules-name~="${t}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${r}`)}return{...o,get:()=>M(K(e,n),e,o.rules,n),set:r=>P(K(e,{...n,_write:!0}),e,o.rules,r,n)}},parseStrict:fe,parseRelaxed:L,ruleAttrIndex:N,splitRule:oe,errors:Y,DOM_PROPERTIES:J};var ht="hha:upgrade-check:";function C(e,t){let n=e.querySelector(`meta[name="${t}"]`),o=n?n.getAttribute("content"):null;return o&&o.trim()?o.trim():null}function $e(e){if(typeof e!="string")return null;let t=e.trim().replace(/^v/,"");return/^\d+(\.\d+)*$/.test(t)?t.split(".").map(Number):null}function mt(e,t){let n=$e(e),o=$e(t);if(!n||!o)return!1;let r=Math.max(n.length,o.length);for(let i=0;i<r;i++){let c=n[i]||0,s=o[i]||0;if(c!==s)return c>s}return!1}function yt(e){try{let t=globalThis.localStorage.getItem(e);return t?JSON.parse(t):null}catch{return null}}function gt(e,t){try{globalThis.localStorage.setItem(e,JSON.stringify(t))}catch{}}async function ve({force:e=!1,doc:t,loc:n,fetchFn:o,now:r,ttlMs:i=864e5}={}){if(t=t||(typeof document<"u"?document:null),n=n||(typeof location<"u"?location:null),o=o||(d=>fetch(d)),r=r??Date.now(),!t)return null;let c=C(t,"hyper-source");if(!c)return null;let s=C(t,"hyper-version"),l;try{l=new URL(c,n?n.href:void 0)}catch{return null}if(n&&l.origin===n.origin&&l.pathname===n.pathname)return null;let a=`${ht}${l.href}:${s||"none"}`,f,y=e?null:yt(a);if(y&&typeof y.checkedAt=="number"&&r-y.checkedAt<i)f=y.sourceVersion;else{try{let d=await o(l.href);if(!d.ok)throw new Error(`HTTP ${d.status}`);let T=await d.text(),h=new DOMParser().parseFromString(T,"text/html");f=C(h,"hyper-version")}catch{f=null}gt(a,{checkedAt:r,sourceVersion:f})}return f?{available:mt(f,s||"0.0.0"),currentVersion:s,sourceVersion:f,sourceUrl:l.href}:null}var Et="script[data-rules-name]";function wt(e){return typeof e=="string"?e.trim().replace(/\s+/g," "):""}function X(e,t){let n=e.find(t,Et,{includeRulesTag:!0}),o=new Set,r=[];for(let i of n){let c=wt(e.attr(i,"data-rules-name"));if(!c)continue;if(o.has(c)){console.warn(`hyper-html-api: duplicate rules tag name "${c}"; using the first.`);continue}let s=e.attr(i,"data-rules-version");if(s!==ue)throw new j(s);o.add(c),r.push({name:c,rules:L(e.text(i))})}return r}function he(e,t){let n={};for(let{name:o,rules:r}of X(e,t))n[o]=M(e,t,r);return n}function Ue(e){let t=e||document,n=t.nodeType===9?t:t.ownerDocument||t;return{dataByName:he(S,t),version:C(n,"hyper-version")}}var V=class extends Error{constructor(t,n){super(`could not fetch upgrade source: ${t}`),this.name="UpgradeSourceUnreachable",this.sourceUrl=t,this.cause=n}},Q=class extends Error{constructor(t){super(`upgrade source has no rules tags; refusing to drop all existing data: ${t}`),this.name="UpgradeSourceHasNoRules",this.sourceUrl=t}},D=class extends Error{constructor(t,n){super(t),this.name="UpgradeTransformInvalid",this.cause=n}},Z=class extends Error{constructor(t){super(`found ${t} script[type="text/hyper-upgrade"] tags; only one is allowed per document.`),this.name="UpgradeMultipleTransforms",this.count=t}};var Tt="text/hyper-upgrade";function He(e,t){let n=e.find(t,`script[type="${Tt}"]`);if(n.length===0)return null;if(n.length>1)throw new Z(n.length);return e.text(n[0])||null}var xt=new Function("url","return import(url)");async function We(e){let t=new Blob([e],{type:"text/javascript"}),n=URL.createObjectURL(t),o;try{o=await xt(n)}catch(r){throw new D(`transform failed to load: ${r&&r.message?r.message:r}`,r)}finally{URL.revokeObjectURL(n)}if(typeof o.default!="function")throw new D("transform must `export default` a function");return o.default}function ee(e,t){let n={carriedOver:0,discarded:0,listItems:0},o=me(t,e,n);return ye(t,e,n),{data:o,summary:n}}function me(e,t,n){if(typeof e=="string")return e.endsWith("[]")?Array.isArray(t)?(n.listItems+=t.length,n.carriedOver+=t.length,t):void 0:t==null||typeof t=="object"?void 0:(n.carriedOver++,t);if(Array.isArray(e)){let[,o]=e;return Array.isArray(t)?(n.listItems+=t.length,t.map(r=>me(o,r,n))):void 0}if(typeof e=="object"&&e!==null){let o={};for(let[r,i]of Object.entries(e)){let c=me(i,t?.[r],n);c!==void 0&&(o[r]=c)}return o}}function ye(e,t,n){if(t!=null){if(typeof e=="object"&&e!==null&&!Array.isArray(e)){if(typeof t!="object"||Array.isArray(t))return;let o=new Set(Object.keys(e));for(let r of Object.keys(t))o.has(r)?ye(e[r],t[r],n):n.discarded+=$(t[r]);return}if(Array.isArray(e)&&Array.isArray(t)){let o=e[1];t.forEach(r=>ye(o,r,n));return}typeof e=="string"&&!e.endsWith("[]")&&typeof t=="object"&&t!==null&&(n.discarded+=$(t))}}function $(e){return e==null?0:Array.isArray(e)?e.reduce((t,n)=>t+$(n),0):typeof e=="object"?Object.values(e).reduce((t,n)=>t+$(n),0):1}function qe(e,t,n){let o=X(e,t),r={carriedOver:0,discarded:0,listItems:0},i={},c=new Set;for(let{name:s,rules:l}of o){if(c.add(s),!Object.prototype.hasOwnProperty.call(n,s)){i[s]={carriedOver:0,discarded:0,listItems:0};continue}let{data:a,summary:f}=ee(n[s],l);P(e,t,l,a),i[s]=f,r.carriedOver+=f.carriedOver,r.discarded+=f.discarded,r.listItems+=f.listItems}for(let s of Object.keys(n))c.has(s)||(r.discarded+=$(n[s]));return{totals:r,byName:i,rulesTagCount:o.length}}async function Be({sourceUrl:e,dataByName:t,fromVersion:n,doc:o,loc:r,fetchFn:i}={}){if(o=o||(typeof document<"u"?document:null),r=r||(typeof location<"u"?location:null),i=i||(p=>fetch(p)),!o)throw new Error("upgrade.run requires a document context");if(e=e||C(o,"hyper-source"),!e)throw new Error("upgrade.run: no sourceUrl given and no hyper-source meta tag found");let c=new URL(e,r?r.href:void 0);n=n!==void 0?n:C(o,"hyper-version"),t=t||he(S,o);let s;try{s=await i(c.href)}catch(p){throw new V(c.href,p)}if(!s.ok)throw new V(c.href,new Error(`HTTP ${s.status}`));let l=await s.text(),a=new DOMParser().parseFromString(l,"text/html"),f=C(a,"hyper-version"),y=t,d=!1,T=He(S,a);if(T){let g=await(await We(T))(y,{fromVersion:n,toVersion:f});if(!g||typeof g!="object"||Array.isArray(g))throw new D("transform must return a plain object map of { rulesName: data }");y=g,d=!0}let{totals:h,byName:m,rulesTagCount:u}=qe(S,a,y);if(u===0&&Object.keys(y).length>0)throw new Q(c.href);return{html:Ot(a),fromVersion:n,toVersion:f,summary:{transformApplied:d,totals:h,byName:m}}}function Ot(e){return`<!DOCTYPE ${e.doctype&&e.doctype.name?e.doctype.name:"html"}>
|
|
2
|
+
`+e.documentElement.outerHTML}var ze={checkForUpdate:ve,run:Be,extractAll:Ue,shapeMatch:ee};var At={engine:pe,upgrade:ze},bt=At;return Ge(St);})();
|
package/package.json
CHANGED
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
"apply",
|
|
10
10
|
"CMS"
|
|
11
11
|
],
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.8.1",
|
|
13
13
|
"homepage": "https://github.com/panphora/hyper-html-api",
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/panphora/hyper-html-api/issues"
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT-0",
|
|
18
18
|
"files": [
|
|
19
|
+
"packed-contract.json",
|
|
19
20
|
"LICENSE",
|
|
20
21
|
"README.md",
|
|
21
22
|
"src/**/*.js",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"build:upgrade": "npx esbuild src/upgrade.js --bundle --minify --format=iife --global-name=hyperHtmlApiUpgrade --outfile=dist/hyper-html-api.upgrade.min.js",
|
|
41
42
|
"copy-to-hyperclayjs": "npm run build:engine && npm run build:upgrade && node scripts/copy-to-hyperclayjs.js",
|
|
42
43
|
"copy-to-clayjs": "npm run build:engine && node scripts/copy-to-clayjs.js",
|
|
43
|
-
"prepublishOnly": "npm run build",
|
|
44
|
+
"prepublishOnly": "npm run build && npm run build:engine && npm run build:upgrade",
|
|
44
45
|
"demo": "http-server . -p 5693 -c-1 -o /demo/",
|
|
45
46
|
"test": "web-test-runner",
|
|
46
47
|
"test:debug": "web-test-runner --manual --open",
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
"url": "git+https://github.com/panphora/hyper-html-api.git"
|
|
62
63
|
},
|
|
63
64
|
"dependencies": {
|
|
64
|
-
"hyper-morph": "^0.5.
|
|
65
|
+
"hyper-morph": "^0.5.3"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
68
|
"@web/test-runner": "^0.20.0",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"load":["hyper-html-api","hyper-html-api/cheerio","hyper-html-api/cms","hyper-html-api/data","hyper-html-api/dom","hyper-html-api/engine","hyper-html-api/upgrade"]}
|
package/src/adapters/cheerio.js
CHANGED
|
@@ -12,7 +12,11 @@ function toWrappers(cheerioSet) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const cheerioAdapter = {
|
|
15
|
+
semanticExclude: false,
|
|
15
16
|
find(ctx, selector, opts = {}) {
|
|
17
|
+
if (Object.prototype.hasOwnProperty.call(opts, 'exclude')) {
|
|
18
|
+
throw new Error('Cheerio does not support semantic exclude queries; omit exclude or use the DOM adapter.')
|
|
19
|
+
}
|
|
16
20
|
if (!ctx || !ctx.find) return []
|
|
17
21
|
let matches = toWrappers(ctx.find(selector))
|
|
18
22
|
if (!opts.includeRulesTag) matches = matches.filter((n) => !isRulesTag(n))
|
package/src/adapters/dom.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createContentView } from '../lib/content-dom.js'
|
|
2
|
+
import { capabilitySelector } from '../lib/region-capabilities.js'
|
|
3
|
+
|
|
1
4
|
function isRulesTag(node) {
|
|
2
5
|
return node && node.nodeType === 1 && node.tagName === 'SCRIPT'
|
|
3
6
|
&& node.hasAttribute && node.hasAttribute('data-rules-name')
|
|
@@ -11,6 +14,7 @@ function resolveSearchRoot(ctx) {
|
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
const dom = {
|
|
17
|
+
semanticExclude: true,
|
|
14
18
|
find(ctx, selector, opts = {}) {
|
|
15
19
|
const root = resolveSearchRoot(ctx)
|
|
16
20
|
if (!root || !root.querySelectorAll) return []
|
|
@@ -110,4 +114,191 @@ const dom = {
|
|
|
110
114
|
},
|
|
111
115
|
}
|
|
112
116
|
|
|
117
|
+
export function createDomAdapter(operationRoot, opts = {}) {
|
|
118
|
+
if (opts.exclude === null) return dom
|
|
119
|
+
const semanticSelector = [capabilitySelector('data'), opts.exclude].filter(Boolean).join(', ')
|
|
120
|
+
const searchContext = operationRoot.nodeType === 9 ? operationRoot : (operationRoot.ownerDocument || operationRoot)
|
|
121
|
+
const rootElement = operationRoot.nodeType === 9 ? operationRoot.documentElement : operationRoot
|
|
122
|
+
if (!opts._write && !rootElement?.matches?.(semanticSelector) && !rootElement?.querySelector?.(semanticSelector) &&
|
|
123
|
+
!searchContext?.querySelector?.(semanticSelector)) return dom
|
|
124
|
+
const ownerContext = operationRoot.nodeType === 9 || !operationRoot.isConnected
|
|
125
|
+
? operationRoot
|
|
126
|
+
: operationRoot.ownerDocument
|
|
127
|
+
const outputDocument = operationRoot.nodeType === 9 ? operationRoot : operationRoot.ownerDocument
|
|
128
|
+
let view = null
|
|
129
|
+
const contentView = () => view || (view = createContentView(ownerContext, { capability: 'data', exclude: opts.exclude || null }))
|
|
130
|
+
const projected = node => {
|
|
131
|
+
const current = contentView()
|
|
132
|
+
return node === operationRoot ? current.cloneOf(operationRoot) : (current.cloneOf(node) || node)
|
|
133
|
+
}
|
|
134
|
+
const live = node => view?.original(node) || node
|
|
135
|
+
const mapParallel = (liveNode, cloneNode) => {
|
|
136
|
+
contentView().liveToClone.set(liveNode, cloneNode)
|
|
137
|
+
contentView().cloneToLive.set(cloneNode, liveNode)
|
|
138
|
+
const liveKids = liveNode.childNodes || []
|
|
139
|
+
const cloneKids = cloneNode.childNodes || []
|
|
140
|
+
for (let i = 0; i < Math.min(liveKids.length, cloneKids.length); i++) mapParallel(liveKids[i], cloneKids[i])
|
|
141
|
+
}
|
|
142
|
+
const replaceProjectedContent = (target, copy, name, value) => {
|
|
143
|
+
const included = Array.from(target.childNodes).filter(node => view.cloneOf(node))
|
|
144
|
+
const first = included[0]
|
|
145
|
+
let anchor = first
|
|
146
|
+
while (anchor && included.includes(anchor)) anchor = anchor.nextSibling
|
|
147
|
+
for (const node of included) node.remove()
|
|
148
|
+
if (name === 'innerHTML') {
|
|
149
|
+
const template = outputDocument.createElement('template')
|
|
150
|
+
template.innerHTML = value
|
|
151
|
+
for (const child of Array.from(template.content.childNodes)) target.insertBefore(child, anchor || null)
|
|
152
|
+
} else {
|
|
153
|
+
target.insertBefore(outputDocument.createTextNode(value), anchor || null)
|
|
154
|
+
}
|
|
155
|
+
const filteredView = createContentView(target, { capability: 'data', exclude: opts.exclude || null })
|
|
156
|
+
copy.replaceChildren(...Array.from(filteredView.root?.childNodes || []))
|
|
157
|
+
const mapFiltered = cloneNode => {
|
|
158
|
+
const liveNode = filteredView.original(cloneNode)
|
|
159
|
+
if (liveNode) {
|
|
160
|
+
view.liveToClone.set(liveNode, cloneNode)
|
|
161
|
+
view.cloneToLive.set(cloneNode, liveNode)
|
|
162
|
+
}
|
|
163
|
+
for (const child of Array.from(cloneNode.childNodes || [])) mapFiltered(child)
|
|
164
|
+
}
|
|
165
|
+
for (const child of Array.from(copy.childNodes)) mapFiltered(child)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const adapter = {
|
|
169
|
+
...dom,
|
|
170
|
+
find(ctx, selector, findOpts = {}) {
|
|
171
|
+
const projectedContext = projected(ctx)
|
|
172
|
+
if (!projectedContext?.querySelectorAll) return []
|
|
173
|
+
let matches = contentView().query(selector, projectedContext)
|
|
174
|
+
if (!findOpts.includeRulesTag) matches = matches.filter(node => !isRulesTag(node))
|
|
175
|
+
const skipParts = []
|
|
176
|
+
if (findOpts.skip) skipParts.push(findOpts.skip)
|
|
177
|
+
const tplAttr = findOpts.templateAttr === null ? null : (findOpts.templateAttr || 'cms-template')
|
|
178
|
+
if (tplAttr) skipParts.push(`[${tplAttr}]`)
|
|
179
|
+
if (skipParts.length) {
|
|
180
|
+
const combined = skipParts.join(', ')
|
|
181
|
+
matches = matches.filter(node => !node.closest?.(combined))
|
|
182
|
+
}
|
|
183
|
+
return matches
|
|
184
|
+
},
|
|
185
|
+
parent(node) {
|
|
186
|
+
const result = projected(node)?.parentElement
|
|
187
|
+
return result ? live(result) : null
|
|
188
|
+
},
|
|
189
|
+
children(node) {
|
|
190
|
+
return Array.from(projected(node)?.children || [], live)
|
|
191
|
+
},
|
|
192
|
+
text(node, value) {
|
|
193
|
+
if (value === undefined) {
|
|
194
|
+
const target = live(node)
|
|
195
|
+
if (!target?.matches?.(semanticSelector) && !target?.querySelector?.(semanticSelector)) return dom.text(target)
|
|
196
|
+
return (projected(node)?.textContent || '').trim()
|
|
197
|
+
}
|
|
198
|
+
const target = live(node)
|
|
199
|
+
if (!target?.matches?.(semanticSelector) && !target?.querySelector?.(semanticSelector) && !view) {
|
|
200
|
+
dom.text(target, value)
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
const copy = contentView().cloneOf(target)
|
|
204
|
+
if (copy) replaceProjectedContent(target, copy, 'textContent', value)
|
|
205
|
+
else dom.text(target, value)
|
|
206
|
+
},
|
|
207
|
+
attr(node, name, value) {
|
|
208
|
+
const target = live(node)
|
|
209
|
+
if (value === undefined) return dom.attr(target, name)
|
|
210
|
+
dom.attr(target, name, value)
|
|
211
|
+
const copy = view?.cloneOf(target)
|
|
212
|
+
if (copy) {
|
|
213
|
+
dom.attr(copy, name, value)
|
|
214
|
+
if (createContentView(target, { capability: 'data', exclude: opts.exclude || null }).root === null) {
|
|
215
|
+
copy.remove()
|
|
216
|
+
view.liveToClone.delete(target)
|
|
217
|
+
view.cloneToLive.delete(copy)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
removeAttr(node, name) {
|
|
222
|
+
const target = live(node)
|
|
223
|
+
dom.removeAttr(target, name)
|
|
224
|
+
const copy = view?.cloneOf(target)
|
|
225
|
+
if (copy) dom.removeAttr(copy, name)
|
|
226
|
+
},
|
|
227
|
+
prop(node, name, value) {
|
|
228
|
+
const target = live(node)
|
|
229
|
+
if (value === undefined) {
|
|
230
|
+
if (name === 'innerHTML' || name === 'outerHTML' || name === 'textContent' || name === 'innerText') {
|
|
231
|
+
return dom.prop(projected(target), name)
|
|
232
|
+
}
|
|
233
|
+
return dom.prop(target, name)
|
|
234
|
+
}
|
|
235
|
+
const semanticContent = name === 'innerHTML' || name === 'textContent' || name === 'innerText'
|
|
236
|
+
const copy = semanticContent ? contentView().cloneOf(target) : view?.cloneOf(target)
|
|
237
|
+
if (copy && semanticContent) {
|
|
238
|
+
replaceProjectedContent(target, copy, name, value)
|
|
239
|
+
} else {
|
|
240
|
+
dom.prop(target, name, value)
|
|
241
|
+
if (copy) dom.prop(copy, name, value)
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
clone(node) {
|
|
245
|
+
const copy = projected(node)
|
|
246
|
+
return copy === node ? dom.clone(node) : outputDocument.importNode(copy, true)
|
|
247
|
+
},
|
|
248
|
+
insertAt(parent, node, index) {
|
|
249
|
+
const targetParent = live(parent)
|
|
250
|
+
const contentChildren = adapter.children(targetParent)
|
|
251
|
+
const ref = contentChildren[index] || (() => {
|
|
252
|
+
for (let i = targetParent.children.length - 1; i >= 0; i--) {
|
|
253
|
+
const child = targetParent.children[i]
|
|
254
|
+
if (contentView().cloneOf(child)) return child.nextElementSibling
|
|
255
|
+
}
|
|
256
|
+
return targetParent.firstElementChild
|
|
257
|
+
})()
|
|
258
|
+
const targetNode = live(node)
|
|
259
|
+
targetParent.insertBefore(targetNode, ref || null)
|
|
260
|
+
const parentCopy = contentView().cloneOf(targetParent)
|
|
261
|
+
if (parentCopy) {
|
|
262
|
+
let nodeCopy = contentView().cloneOf(targetNode)
|
|
263
|
+
if (!nodeCopy) {
|
|
264
|
+
nodeCopy = outputDocument.importNode(targetNode, true)
|
|
265
|
+
mapParallel(targetNode, nodeCopy)
|
|
266
|
+
}
|
|
267
|
+
const copyContentChildren = Array.from(parentCopy.children)
|
|
268
|
+
parentCopy.insertBefore(nodeCopy, copyContentChildren[index] || null)
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
remove(node) {
|
|
272
|
+
const target = live(node)
|
|
273
|
+
const copy = contentView().cloneOf(target)
|
|
274
|
+
dom.remove(target)
|
|
275
|
+
if (copy) dom.remove(copy)
|
|
276
|
+
},
|
|
277
|
+
replaceWith(node, html) {
|
|
278
|
+
const target = live(node)
|
|
279
|
+
const copy = contentView().cloneOf(target)
|
|
280
|
+
const replacement = dom.replaceWith(target, html)
|
|
281
|
+
if (copy) {
|
|
282
|
+
const filteredView = createContentView(replacement, { capability: 'data', exclude: opts.exclude || null })
|
|
283
|
+
if (!filteredView.root) {
|
|
284
|
+
copy.remove()
|
|
285
|
+
} else {
|
|
286
|
+
copy.replaceWith(filteredView.root)
|
|
287
|
+
const mapFiltered = cloneNode => {
|
|
288
|
+
const liveNode = filteredView.original(cloneNode)
|
|
289
|
+
if (liveNode) {
|
|
290
|
+
view.liveToClone.set(liveNode, cloneNode)
|
|
291
|
+
view.cloneToLive.set(cloneNode, liveNode)
|
|
292
|
+
}
|
|
293
|
+
for (const child of Array.from(cloneNode.childNodes || [])) mapFiltered(child)
|
|
294
|
+
}
|
|
295
|
+
mapFiltered(filteredView.root)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return replacement
|
|
299
|
+
},
|
|
300
|
+
}
|
|
301
|
+
return adapter
|
|
302
|
+
}
|
|
303
|
+
|
|
113
304
|
export default dom
|
package/src/dom-api.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import * as engineMod from './engine/index.js'
|
|
2
|
-
import domAdapter from './adapters/dom.js'
|
|
2
|
+
import domAdapter, { createDomAdapter } from './adapters/dom.js'
|
|
3
3
|
|
|
4
4
|
// The DOM-bound engine: every engine call pre-wired with the DOM adapter. Lives
|
|
5
5
|
// here (instead of inline in hyper-html-api.js) so both the full CDN bundle and
|
|
6
6
|
// the lean `data.js` entry share one definition.
|
|
7
7
|
export const engine = {
|
|
8
|
-
extract: (root, rules, opts) => engineMod.extract(
|
|
9
|
-
apply: (root, rules, data, opts) => engineMod.apply(
|
|
8
|
+
extract: (root, rules, opts = {}) => engineMod.extract(createDomAdapter(root, opts), root, rules, opts),
|
|
9
|
+
apply: (root, rules, data, opts = {}) => engineMod.apply(createDomAdapter(root, { ...opts, _write: true }), root, rules, data, opts),
|
|
10
10
|
findRulesIn: (root, token) => engineMod.findRulesIn(domAdapter, root, token),
|
|
11
11
|
findRules: (root, source) => engineMod.resolveRules(domAdapter, root, source),
|
|
12
|
-
bind: (root, source, opts) =>
|
|
12
|
+
bind: (root, source, opts = {}) => {
|
|
13
|
+
const found = engineMod.resolveRules(domAdapter, root, source)
|
|
14
|
+
if (!found) {
|
|
15
|
+
const what = typeof source === 'string' ? `data-rules-name~="${source}"` : 'the provided rules object'
|
|
16
|
+
throw new Error(`hyper-html-api: could not resolve rules for ${what}`)
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
...found,
|
|
20
|
+
get: () => engineMod.extract(createDomAdapter(root, opts), root, found.rules, opts),
|
|
21
|
+
set: data => engineMod.apply(createDomAdapter(root, { ...opts, _write: true }), root, found.rules, data, opts),
|
|
22
|
+
}
|
|
23
|
+
},
|
|
13
24
|
parseStrict: engineMod.parseStrict,
|
|
14
25
|
parseRelaxed: engineMod.parseRelaxed,
|
|
15
26
|
// Adapter-free, like the parsers above: a consumer that has to split a rule
|
|
@@ -48,7 +59,7 @@ function autodetect(root) {
|
|
|
48
59
|
export function extractData(a, b) {
|
|
49
60
|
const root = isNode(a) ? a : document
|
|
50
61
|
const source = isNode(a) ? b : a
|
|
51
|
-
if (source === undefined) return engineMod.extract(
|
|
62
|
+
if (source === undefined) return engineMod.extract(createDomAdapter(root), root, autodetect(root))
|
|
52
63
|
return engine.bind(root, source).get()
|
|
53
64
|
}
|
|
54
65
|
|
|
@@ -59,7 +70,7 @@ export function applyData(root, data, source) {
|
|
|
59
70
|
if (!isNode(root)) {
|
|
60
71
|
throw new Error('hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.')
|
|
61
72
|
}
|
|
62
|
-
if (source === undefined) engineMod.apply(
|
|
73
|
+
if (source === undefined) engineMod.apply(createDomAdapter(root), root, autodetect(root), data)
|
|
63
74
|
else engine.bind(root, source).set(data)
|
|
64
75
|
return root
|
|
65
76
|
}
|
package/src/engine/apply.js
CHANGED
|
@@ -14,6 +14,9 @@ import { ruleAttrIndex } from './rule-syntax.js'
|
|
|
14
14
|
const BOOLEAN_PROPS = new Set(['checked', 'selected', 'disabled', 'readOnly', 'paused'])
|
|
15
15
|
|
|
16
16
|
export function apply(adapter, root, rules, data, opts = {}) {
|
|
17
|
+
if (Object.prototype.hasOwnProperty.call(opts, 'exclude') && adapter.semanticExclude === false) {
|
|
18
|
+
throw new Error('This adapter does not support semantic exclude queries; omit exclude or use the DOM adapter.')
|
|
19
|
+
}
|
|
17
20
|
const mismatches = []
|
|
18
21
|
validateShape(rules, data, [], mismatches)
|
|
19
22
|
if (mismatches.length) throw new ShapeMismatch(mismatches)
|
|
@@ -76,16 +79,28 @@ function applyScalar(adapter, ctx, rule, value, trace, opts) {
|
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
if (rule === '.') {
|
|
79
|
-
adapter
|
|
82
|
+
writeText(adapter, ctx, value)
|
|
80
83
|
return ctx
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
const matches = adapter.find(ctx, rule, opts)
|
|
84
87
|
if (matches.length === 0) return ctx
|
|
85
|
-
adapter
|
|
88
|
+
writeText(adapter, matches[0], value)
|
|
86
89
|
return ctx
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
// Writing identical text still replaces the text node, so an apply of unchanged
|
|
93
|
+
// data emitted a childList record for every text rule on the page. The CMS
|
|
94
|
+
// re-applies the whole page on each keystroke, so those records reached the undo
|
|
95
|
+
// observer and live sync on every one. Scalar lists already compared before
|
|
96
|
+
// writing (see writeItems); this is the same comparison for every other text
|
|
97
|
+
// rule. adapter.text reads trimmed, so surrounding whitespace alone no longer
|
|
98
|
+
// counts as a change, which is exactly what writeItems has always done.
|
|
99
|
+
function writeText(adapter, node, value) {
|
|
100
|
+
const target = value == null ? '' : String(value)
|
|
101
|
+
if (adapter.text(node) !== target) adapter.text(node, target)
|
|
102
|
+
}
|
|
103
|
+
|
|
89
104
|
// Returns the (possibly new) node. For outerHTML, the original is detached
|
|
90
105
|
// and a freshly parsed element takes its place; that new node is returned.
|
|
91
106
|
// For every other write, returns the original node unchanged.
|
|
@@ -97,11 +112,20 @@ function writePropOrAttr(adapter, node, name, value) {
|
|
|
97
112
|
const html = value == null ? '' : String(value)
|
|
98
113
|
return adapter.replaceWith(node, html)
|
|
99
114
|
}
|
|
115
|
+
// Compare before writing, exactly as writeText does. A property write of an
|
|
116
|
+
// identical value is not a no-op: assigning innerHTML destroys and rebuilds
|
|
117
|
+
// every child, and setting an attribute to the value it already has still
|
|
118
|
+
// emits a mutation record. The CMS re-applies the whole page on each
|
|
119
|
+
// keystroke, so without this every rich-text region on the page was torn
|
|
120
|
+
// down per keystroke (losing the caret, restarting an embedded video or
|
|
121
|
+
// iframe) and every attribute rule emitted a record to undo and live sync.
|
|
100
122
|
if (DOM_PROPERTIES_WRITE_SET.has(name)) {
|
|
101
|
-
|
|
123
|
+
const next = coercePropValue(name, value)
|
|
124
|
+
if (adapter.prop(node, name) !== next) adapter.prop(node, name, next)
|
|
102
125
|
return node
|
|
103
126
|
}
|
|
104
|
-
|
|
127
|
+
const next = value == null ? '' : String(value)
|
|
128
|
+
if (adapter.attr(node, name) !== next) adapter.attr(node, name, next)
|
|
105
129
|
return node
|
|
106
130
|
}
|
|
107
131
|
|